최근에 스터디를 하면서 공부를 하고 있습니다.
그런데 금방 까먹는 듯한 기분이 들어 정리하는 시간을 가지려고 합니다.
이렇게 하면 더 오래 남지 않을까 하는 개인적인 기대가 있습니다.
이번 글은 인프런 김영한 님의 스프링 강의 - 스프링의 기본 기능 내용 정리입니다.
로깅(Logging)
제가 프로젝트를 수행할 때는 어떠한 버그가 발생했을 때 이유를 알아보기 위해서
시스템 콘솔에 데이터를 출력하는 System.out.println()을 사용했습니다.
하지만 실무에서 위의 방법을 사용할 경우에는 로그관리를 할 수 없기 때문에 별도의 로깅 라이브러리를 사용합니다.
스프링 부트는 기본적으로 slf4j라는 라이브러리를 사용하는데,
이는 Logback, Log4j, Log4j2 등 수많은 라이브러리를 통합해서 제공하는 라이브러리입니다.
로그의 선언에는
private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class);
@Slf4j
위와 같은 방법을 사용할 수 있습니다. Logger와 LoggerFactory은 slf4j의 클래스입니다.
그리고 @Slf4j 어노테이션은 Lombok 라이브러리의 어노테이션으로 위의 두줄과 같이 직접적인 선언 없이
로그를 호출할 수 있게 해 줍니다. 이외에도 Lombok은 DTO 클래스에서 setter, getter의 작성을 쉽게 해주기도 합니다.
Lombok에 대한 자세한 내용은 다음에 다뤄보도록 하겠습니다.
호출은 아래와 같이 할 수 있습니다.
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);
로그의 출력은 개발 단계와 운영 단계에 맞춰 각각 출력하는 범위를 정할 수 있습니다.
레벨 순은 trace >> debug >> info >> warn >> error 순으로 디폴트 값은 info입니다.
그래서 출력을 info로 설정하면 하위 레벨인 debug와 trace는 출력되지 않습니다.
log.debug("String concat log=" + name);
그리고 로그의 출력을 위와 같이 + 연산자를 사용해서 출력할 수도 있습니다.
하지만 위와 같은 경우는 리소스를 낭비하여 사용하지 않아야 합니다.
출력이 info로 설정되어 있을 경우 debug는 대상이 아니라 그냥 넘어가야 하지만
그 작업이 이뤄지기 이전에 + 연산자의 로직이 실행돼 불필요한 자원을 소모하기 때문입니다.
로그 사용의 장점
- 스레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있습니다.
- 로그를 상황에 맞게 레벨을 조절하여 출력할 수 있습니다.
- 파일이나 네트워크 등, 로그를 별도의 위치에 남길 수 있습니다.
- 파일로 남길 때에는 특정 기준에 맞춰 로그를 분할할 수 있습니다.
매핑(Mapping)
스프링에서는 @Controller 어노테이션을 사용해 컨트롤러를 찾을 수 있습니다.
그리고 @RequestMapping 어노테이션을 사용해 해당하는 URL 호출이 오면 메서드가 실행되도록 매핑할 수 있습니다.
여기서는 @RequestMapping의 여러 매핑 방법에 대해 정리해보도록 하겠습니다.
@RequestMapping 방법
- HTTP 메서드 매핑
- PathVariable 매핑
- 특정 파라미터 조건 매핑
- 특정 헤더 조건 매핑
- 미디어 타입 조건 매핑
HTTP 메서드 매핑
HTTP 메서드 매핑은 @RequestMapping의 method 속성으로 매핑을 하는 방법입니다.
기본적으로 GET, POST, PUT, PATCH 등 모든 메서드에 대해 허용하게 됩니다.
method 속성을 사용하면 이를 특정 메서드의 요청에만 응답하도록 설정할 수 있습니다.
@RequestMapping(value = "/mapping", method = RequestMethod.GET)
위 URL에 POST 요청을 보내고 POST 요청에 해당하는 매핑이 없을 경우
스프링 MVC는 HTTP 405(Method Not Allowed) 코드를 반환합니다.
덧붙여 스프링 부트는 해당 메서드 매핑의 축약형 어노테이션을 제공합니다.
@GetMapping(value="/mapping")
@PostMapping(value="/mapping")
@PutMapping(value="/mapping")
PathVariable 매핑
HTTP 리소스 경로에 식별자를 넣는 방법입니다.
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {}
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable String userId) {}
위와 같이 사용할 수 있으며, 경로 변수와 파라미터의 이름이 같다면 @PathVariable의 이름을 생략할 수 있습니다.
특정 파라미터 조건 매핑
/**
* 파라미터로 추가 매핑
* params="mode",
* params="!mode"
* params="mode=debug"
* params="mode!=debug" (! = )
* params = {"mode=debug","data=good"}
*/
@GetMapping(value = "/mapping-param", params = "mode=debug")
특정 파라미터가 있거나 없는 요청에 대해서 매핑하는 방법입니다.
하지만 잘 사용되지는 않는다고 합니다.
특정 헤더 조건 매핑
/**
* 특정 헤더로 추가 매핑
* headers="mode",
* headers="!mode"
* headers="mode=debug"
* headers="mode!=debug" (! = )
*/
@GetMapping(value = "/mapping-header", headers = "mode=debug")
파라미터 매핑과 비슷하지만 HTTP 헤더를 이용합니다.
미디어 타입 조건 매핑
미디어 타입 조건 매핑에는 HTTP 요청의 Content-Type과 Accept 해당하는 매핑이 있습니다.
Content-Type은 클라이언트가 서버에게 전송하는 데이터의 원래 미디어 유형을 말합니다.
Accept는 클라이언트가 이해할 수 있는 미디어 유형의 HTTP 요청 헤더입니다.
특정 Content-Type 요청에는 consumes 속성을 사용하고, Accept 요청에는 produces 속성을 사용합니다.
제가 이 속성들을 사용할 때에는 주로 jQuery로 Ajax 통신을 할 때 사용했습니다.
특정한 값으로 전달받거나 전달하기 위해서 그렇습니다.
Content-Type
/**
* Content-Type 헤더 기반 추가 매핑 Media Type
* consumes="application/json"
* consumes="!application/json"
* consumes="application/*"
* consumes="*\/*"
* MediaType.APPLICATION_JSON_VALUE
*/
@PostMapping(value = "/mapping-consume", consumes = "application/json")
/**
*
* consumes 예시
*/
consumes = "text/plain"
consumes = {"text/plain", "application/*"}
consumes = MediaType.TEXT_PLAIN_VALUE
맞지 않으면 HTTP 415(Unsupported Media Type) 상태 코드를 반환합니다.
Accept
/**
* Accept 헤더 기반 Media Type
* produces = "text/html"
* produces = "!text/html"
* produces = "text/*"
* produces = "*\/*"
*/
@PostMapping(value = "/mapping-produce", produces = "text/html")
/**
*
* produces 예시
*/
produces = "text/plain"
produces = {"text/plain", "application/*"}
produces = MediaType.TEXT_PLAIN_VALUE
produces = "text/plain;charset=UTF-8"
맞지 않으면 HTTP 406(Not Acceptable) 상태코드를 반환합니다.