복습

스프링 MVC 기본 기능 - 로깅, 요청 매핑 본문

Spring뿌시기/6주차 - 스프링 MVC 1편

스프링 MVC 기본 기능 - 로깅, 요청 매핑

ykm1256 2022. 11. 14. 12:50

로깅

  • 운영 시스템에서는 System.out.println() 같은 시스템 콘솔을 사용하지 않고, 로깅 라이브러리를 통해 로그를 출력한다.
  • 스프링 부트 라이브러리를 사용하면 스프링 부트 로깅 라이브러리(spring-boot-starter-logging)이 함께 포함된다.
  • 스프링 부트 로깅 라이브러리는 SLF4J, Logback을 기본으로 사용한다.

로그 선언

private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class)
  • @Slf4j : 롬복 사용 가능

로그 호출

log.info("hello")
System.out.println("hello")

LogTestController

//@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);
        
        //로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
        log.debug("String concat log=" + name);
        return "ok";
    }
}
  • @RestController
    • @RestController는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.
    • 따라서 실행 결과로 ok 메시지를 받을 수 있다.
  • @Controller
    • 반면 @Controller는 반환 값이 String이면 뷰 이름으로 인식하여 뷰를 찾아 뷰가 렌더링 된다.
  • 로그를 출력할 때 "메시지" + name의 형식으로 변수를 + 연산으로 출력할 수 있지만 이렇게 사용하게 되면 + 연산 로직이 먼저 실행되어 해당 로그가 출력되지 않는 경우에도 연산을 무조건 하여 자원이 낭비된다.
  • 따라서 로그에서 변수를 출력할 때는 {}을 사용하여 변수를 출력한다.
  • 로그 레벨
    • trace > debug > info > warn > error 순이며, 개발 서버에서는 보통 debug까지 출력하고 운영 서버에서는 info 정도 까지 출력한다.

로그 레벨 설정

#전체 로그 레벨 설정(기본 info)
logging.level.root=info

#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug

로그 사용 시 장점

  • 쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
  • 로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 상황에 맞게 조절한다.
  • 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등 별도의 위치에 로그를 남길 수 있다.
  • 특히, 파일로 남길 때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
  • 성능도 일반 System.out보다 좋다.(내부 버퍼링, 멀티 쓰레드 등등)
  • 따라서 실무에서는 꼭 로그를 사용해야 한다!

요청 매핑

MappingController

@RestController
public class MappingController {

private Logger log = LoggerFactory.getLogger(getClass());

/**
* 기본 요청
* 둘다 허용 /hello-basic, /hello-basic/
* HTTP 메서드 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
*/
    @RequestMapping("/hello-basic")
    public String helloBasic() {
        log.info("helloBasic");
        return "ok";
    }
}
  • @RequestMapping을 사용하여 /hello-basic url 호출이 오면 이 메서드가 실행되도록 매핑한다.
  • 대부분의 속성을 배열로 제공하여 다중 설정이 가능하다.({"/hello-basic", "/hello-go"})
  • /hello-basic과 /hello-basic/은 다른 URL이지만 스프링은 /hello-basic으로 매핑해도 같이 처리해준다.

HTTP 메서드 매핑

  • @RequestMapping의 method 속성으로 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
    log.info("mappingGetV1");
    return "ok";
}

-----------------------------------------------------------------

@GetMapping(value = "/mapping-get-v2")
public String mappingGetV2() {
 log.info("mapping-get-v2");
 return "ok";
}
  • 위와 같이 @RequestMapping의 method를 사용할 수도 있고, @GetMapping과 같이 애노테이션에서 바로 메서드를 지정할 수도 있다.
  • 애노테이션 종류 : @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping

PathVariable(경로 변수) 사용

/**
* PathVariable 사용
* 변수명이 같으면 생략 가능
* @PathVariable("userId") String userId -> @PathVariable userId
*/

@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
    log.info("mappingPath userId={}", data);
    return "ok";
}
  • PathVariable을 사용하여 url 경로에 입력된 경로 변수를 사용할 수 있다.
  • @RequestMapping은 URL 경로를 템플릿화 할 수 있는데({userId}), @PathVariable을 사용하여 매칭 되는 부분을 편리하게 조회할 수 있다.
  • @PathVariable의 이름과 파라미터 이름이 같으면 @PathVariable을 생략할 수 있다.

PathVariable 다중 사용

@GetMapping("/mapping/users/{userId}/orders/{orderId}")
public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
    log.info("mappingPath userId={}, orderId={}", userId, orderId);
    return "ok";
}
  • 위의 방식처럼 하나 이상의 경로 변수를 받아 여러 개를 사용할 수 있다.

특정 파라미터 조건 매핑

@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
    log.info("mappingParam");
    return "ok";
}
  • params 속성을 사용하여 특정 파라미터가 있거나 없는 조건을 추가하여 조건에 해당하는 url만 처리할 수도 있다.
  • 잘 사용하지는 않는다.

특정 헤더 조건 매핑

@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
    log.info("mappingHeader");
    return "ok";
}
  • 파라미터 매핑과 비슷하지만, HTTP 헤더를 사용하는 조건 매핑이다.

미디어 타입 조건 매핑 - HTTP 요청 Content-Type, consume

@PostMapping(value = "/mapping-consume", consumes = "application/json")
public String mappingConsumes() {
    log.info("mappingConsumes");
    return "ok";
}
  • HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑한다.
  • 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)을 반환한다.
  • consume은 클라이언트가 서버에 보내는 데이터를 제한한다.

미디어 타입 조건 매핑 - HTTP 요청 Accept, produce

@PostMapping(value = "/mapping-produce", produces = "text/html")
public String mappingProduces() {
    log.info("mappingProduces");
    return "ok";
}
  • HTTP 요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다.
  • 맞지 않다면 HTTP 406 상태코드(Not Acceptable)을 반환한다.
  • produces는 서버가 클라이언트에 보내는 데이터를 제한한다.

HTTP 요청 - 기본, 헤더 조회

  • 애노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.

RequestHeaderController

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                        HttpServletResponse response,
                        HttpMethod httpMethod,
                        Locale locale,
                        @RequestHeader MultiValueMap<String, String>
                        headerMap,
                        @RequestHeader("host") String host,
                        @CookieValue(value = "myCookie", required = false) String cookie) {
                        
        log.info("request={}", request);
        log.info("response={}", response);
        log.info("httpMethod={}", httpMethod);
        log.info("locale={}", locale);
        log.info("headerMap={}", headerMap);
        log.info("header host={}", host);
        log.info("myCookie={}", cookie);

        return "ok";
    }
}
  • HttpMethod : HTTP 메서드를 조회한다.
  • Locale : Locale 정보를 조회한다.
  • @RequestHeader MultiValueMap<String, String> headerMap : 모든 HTTP 헤더를 MultiValueMap 형식으로 조회한다.
  • @RequestHeader("host") String host
    • 특정 HTTP 헤더를 조회한다.
    • 속성
      • 필수 값 여부 : required
      • 기본 값 속성 : defaultValue
  • @CookieValue(value = "myCookie", required = false) String cookie
    • 특정 쿠키를 조회한다.
    • 속성
      • 필수 값 여부 : required
      • 기본값 : defaultValue

MultiValueMap이란?

MultiValueMap<String, String> map = new LinkedMultiValueMap();
map.add("keyA", "value1");
map.add("keyA", "value2");

//[value1,value2]
List<String> values = map.get("keyA");
  • Map과 유사하며, 하나의 키에 여러 값을 받을 수 있다.
  • HTTP header, HTTP 쿼리 파라미터와 같이 하나의 키에 여러 값을 받을 때 사용한다.
  • ex) keyA=value1&keyA=value2

@Slf4j

private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(RequestHeaderController.class);
  • 위의 코드를 자동으로 생성하여 로그를 선언해주기 때문에, 개발자는 편리하게 log라고 사용하면 된다.

 


출처

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com