공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.
프로젝트 생성
스프링 부트 프로젝트를 생성할 때 Packaging은 War가 아니라 Jar를 선택해야 한다.
이는 JSP를 사용하지 않는 환경에서 권장되는 방식이며, 내장 서버(Tomcat 등)와 함께 실행하는 데 최적화되어 있다.
Jar vs War
- Jar: 내장 서버를 사용하며 webapp 경로를 사용하지 않는다. 최근 대부분의 프로젝트에서 이 방식을 사용한다.
- War: 내장 서버도 가능하지만, 주로 외부 서버(WebLogic, JBoss 등)에 배포하는 용도로 사용된다.
Welcome 페이지 만들기
이번 장에서 학습할 내용을 편리하게 참고하기 위해 Welcome 페이지를 생성한다.
스프링 부트에서는 /resources/static/ 위치에 index.html 파일을 두면 자동으로 Welcome 페이지로 처리된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>로그 출력
<ul>
<li><a href="/log-test">로그 테스트</a></li>
</ul>
</li>
<!-- -->
<li>요청 매핑
<ul>
<li><a href="/hello-basic">hello-basic</a></li>
<li><a href="/mapping-get-v1">HTTP 메서드 매핑</a></li>
<li><a href="/mapping-get-v2">HTTP 메서드 매핑 축약</a></li>
<li><a href="/mapping/userA">경로 변수</a></li>
<li><a href="/mapping/users/userA/orders/100">경로 변수 다중</a></li>
<li><a href="/mapping-param?mode=debug">특정 파라미터 조건 매핑</a></li>
<li><a href="/mapping-header">특정 헤더 조건 매핑(POST MAN 필요)</a></li>
<li><a href="/mapping-consume">미디어 타입 조건 매핑 Content-Type(POST
MAN 필요)</a></li>
<li><a href="/mapping-produce">미디어 타입 조건 매핑 Accept(POST MAN 필
요)</a></li>
</ul>
</li>
<li>요청 매핑 - API 예시
<ul>
<li>POST MAN 필요</li>
</ul>
</li>
<li>HTTP 요청 기본
<ul>
<li><a href="/headers">기본, 헤더 조회</a></li>
</ul>
</li>
<li>HTTP 요청 파라미터
<ul>
<li><a href="/request-param-v1?username=hello&age=20">요청 파라미터 v1</
a></li>
<li><a href="/request-param-v2?username=hello&age=20">요청 파라미터 v2</
a></li>
<li><a href="/request-param-v3?username=hello&age=20">요청 파라미터 v3</
a></li>
<li><a href="/request-param-v4?username=hello&age=20">요청 파라미터 v4</
a></li>
<li><a href="/request-param-required?username=hello&age=20">요청 파라미
터 필수</a></li>
기본 값</a></li>
<li><a href="/request-param-default?username=hello&age=20">요청 파라미터
<li><a href="/request-param-map?username=hello&age=20">요청 파라미터
MAP</a></li>
<li><a href="/model-attribute-v1?username=hello&age=20">요청 파라미터
@ModelAttribute v1</a></li>
<li><a href="/model-attribute-v2?username=hello&age=20">요청 파라미터
@ModelAttribute v2</a></li>
</ul>
</li>
<li>HTTP 요청 메시지
<ul>
<li>POST MAN</li>
</ul>
</li>
<li>HTTP 응답 - 정적 리소스, 뷰 템플릿
<ul>
<li><a href="/basic/hello-form.html">정적 리소스</a></li>
<li><a href="/response-view-v1">뷰 템플릿 v1</a></li>
<li><a href="/response-view-v2">뷰 템플릿 v2</a></li>
</ul>
</li>
<li>HTTP 응답 - HTTP API, 메시지 바디에 직접 입력
<ul>
<li><a href="/response-body-string-v1">HTTP API String v1</a></li>
<li><a href="/response-body-string-v2">HTTP API String v2</a></li>
<li><a href="/response-body-string-v3">HTTP API String v3</a></li>
<li><a href="/response-body-json-v1">HTTP API Json v1</a></li>
<li><a href="/response-body-json-v2">HTTP API Json v2</a></li>
</ul>
</li>
</ul>
</body>
</html>
로깅 간단히 알아보기
운영 시스템에서는 System.out.println()을 사용하여 콘솔에 직접 로그를 출력하는 대신, 별도의 로깅 라이브러리를 사용한다.
로깅은 프로그램의 실행 흐름을 파악하고, 문제 발생 시 디버깅을 용이하게 하며, 성능 최적화에 중요한 역할을 한다.
스프링 부트에서는 기본적으로 Logback을 사용하며, 로깅 라이브러리를 통합하는 SLF4J 인터페이스를 지원한다.
로깅 라이브러리
스프링 부트에서 제공하는 기본 로깅 라이브러리는 다음과 같다.
라이브러리 | 설명 |
SLF4J | 여러 로깅 라이브러리를 통합하는 인터페이스 |
Logback | 스프링 부트의 기본 로깅 라이브러리 |
Log4J, Log4J2 | 과거에 많이 사용된 로깅 프레임워크 |
SLF4J는 인터페이스 역할을 하며, 실제 구현체로 Logback을 기본적으로 사용한다.
실무에서는 대부분 Logback을 그대로 사용한다.
로그 선언 방법
1. 일반적인 로그 선언
private final Logger log = LoggerFactory.getLogger(getClass());
또는
private static final Logger log = LoggerFactory.getLogger(클래스명.class);
2. Lombok을 사용하여 간단하게 선언
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SampleClass {
public void testLog() {
log.info("로그 출력 테스트");
}
}
→ @Slf4j 애노테이션을 사용하면 Logger 객체를 직접 선언하지 않아도 된다.
로그 호출 방법
1. 일반적인 로그 출력
log.info("hello");
2. System.out.println()과 비교
System.out.println("hello"); // 콘솔 출력
log.info("hello"); // 로깅 프레임워크를 통한 출력
System.out.println()은 단순히 콘솔에 출력하는 반면, 로깅을 사용하면 다양한 설정과 출력을 조절할 수 있다.
로그 레벨 (Log Level)
로그는 여러 레벨을 지원하며, TRACE > DEBUG > INFO > WARN > ERROR 순으로 중요도가 높아진다.
레벨 | 설명 |
TRACE | 가장 상세한 디버깅 정보를 제공 (개발 시 사용) |
DEBUG | 디버깅 정보를 출력 (개발 시 주로 사용) |
INFO | 일반적인 시스템 실행 흐름 (운영 서버 기본) |
WARN | 경고 메시지 (문제가 될 가능성이 있는 경우) |
ERROR | 치명적인 오류 (예외 발생 등) |
로그 레벨 설정 예시
- 개발 서버 → DEBUG 이상 로그 출력
- 운영 서버 → INFO 이상 로그 출력
로그 사용 예제 (LogTestController)
package hello.springmvc.basic;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogTestController {
private final Logger log = LoggerFactory.getLogger(getClass());
@RequestMapping("/log-test")
public String logTest() {
String name = "Spring";
log.trace("trace log={}", name);
log.debug("debug log={}", name);
log.info(" info log={}", name);
log.warn(" warn log={}", name);
log.error("error log={}", name);
// 잘못된 로그 사용 예시 (문자열 연산 발생)
log.debug("String concat log=" + name);
return "ok";
}
}
@RestController vs @Controller
애노테이션 | 설명 |
@Controller | 반환 값이 String이면 뷰 이름으로 인식하여 뷰를 렌더링 |
@RestController | 반환 값을 HTTP 메시지 바디에 직접 입력 (@ResponseBody 포함) |
→ @RestController를 사용하면 실행 결과로 "ok" 메시지를 직접 받을 수 있다.
로그 레벨 설정 변경 (application.properties)
# 전체 로그 레벨 설정 (기본값: info)
logging.level.root=info
# 특정 패키지의 로그 레벨 설정
logging.level.hello.springmvc=debug
→ 특정 패키지(hello.springmvc)의 로그 레벨을 debug로 변경하면,
해당 패키지에서 DEBUG 이상의 로그가 출력된다.
올바른 로그 사용법
log.debug("data=" + data); // ❌ 잘못된 예시
- INFO 레벨로 설정되어 있어도 문자열 연산("data=" + data)이 실행된다.
- 불필요한 성능 저하 발생 가능
log.debug("data={}", data); // ✅ 올바른 예시
- INFO 레벨에서는 아무 일도 발생하지 않음
- 불필요한 연산 없이 필요할 때만 로그 출력
로그 사용의 장점
1. 추가 정보 제공
- 쓰레드 정보, 클래스 이름, 로그 레벨 등 추가 정보를 포함할 수 있음
2. 로그 레벨 조절 가능
- 개발 환경과 운영 환경에 따라 필요한 로그만 출력 가능
3. 다양한 출력 위치 지원
- 콘솔뿐만 아니라 파일, 네트워크, 원격 서버 등에 로그 저장 가능
4. 성능 최적화
- System.out.println()보다 내부 버퍼링 및 멀티쓰레드 환경에서 성능이 우수함
더 공부하고 싶다면?
- SLF4J 공식 문서: http://www.slf4j.org
- Logback 공식 문서: http://logback.qos.ch
- Spring Boot Logging 문서 :
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.logging
'Spring MVC' 카테고리의 다른 글
[MVC] 스프링 MVC - 기본 기능(3) (0) | 2025.03.02 |
---|---|
[MVC] 스프링 MVC - 기본 기능(2) (1) | 2025.02.24 |
[MVC] 스프링 MVC - 구조 이해(3) (1) | 2025.02.22 |
[MVC] 스프링 MVC - 구조 이해(2) (0) | 2025.02.20 |
[MVC] 스프링 MVC - 구조 이해(1) (0) | 2025.02.19 |