[Spring] MVC 기본 기능(1) log, API

JJoSuk·2023년 6월 5일
0
post-thumbnail

본 프로젝트 자료는 김영한님의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술을 참고 제작됐음을 알립니다.

로깅 이란?

실무에 들어가면 System.out.println() 같은 시스템 콘솔을 사용하기 보다는 logging 이라는 라이브러리를 사용한다.

logging 관련 프레임워크는 log4j, logback, log4j2 등 통합해서 Slf4j 라이브러리가 있다.

그럼 어떻게 사용하는지 알아볼려고 한다.

public class LogTestController {

    // 롬복을 사용하면 이걸 사용할 필요없이 자동으로 다 출력해준다
    private final Logger log = LoggerFactory.getLogger(getClass());

    @RequestMapping("/log-test")
    public String logTest() {
        String name = "Spring";

        // 무슨 일이든 실행만 시키면 무조건 나오는거라 시스템아웃은 쓰지마라
        System.out.println("name = " + name);
        // 이렇게 쓰면 안된다
        // 쓸모없는 리소스를 사용하게 된다
        log.trace(" trace my log = {}" + name);
        // 아래 방식을 추천
        // 이렇게 사용하면 출력할 필요 없을 때 출력을 안한다.
        // 그리고 현재 로그는 설정을 해서 튜닝해서 로그를 남길 수 있다
        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); // 에러

        return "ok";
    }
}

로그를 사용하기 위해서는 위와 같은 로그를 먼저 선언을 해줘야 한다. log 종류에는 trace, debug, info, warn, error 가 있으며 각각의 의미는

info는 기본적으로 우선 순위로 출력된다.

lombok 의 @Slf4j 어노테이션을 선언만 해주면 별도의 선언 필요없이 사용할 수 있다.


System.out.println()을 사용하지 않고 logging을 사용하는 이유

그렇다면 왜 굳이 println문으로 찍으면 편할 것을 굳이 logging을 이용할까?

logging을 사용했을 때의 장점

  1. 스레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
  2. 로그 레벨에 따라 개발서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.
  3. 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등, 로그를 별도의 위치에 남길 수 있다.
  4. 특히 파일로 남길 때에는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
  5. println을 썼을 때보다 내부 버퍼링, 멀티 스레드 등의 환경에서 훨씬 좋다

요청 매핑(mapping) 이란?

  • url 요청이 왔을 때 어떤 컨트롤러가 호출되어야 할지 매핑 해놓은 것을 말한다.
  • 메서드의 위에 @RequestMapping 어노테이션을 명시함으로써 적용할 수 있다.
@RequestMapping("/mapping")
public String mappingPath() {
	log.info("request mapping");
	return "ok";
}

HTTP 메서드

@RequestMapping(value = "/mapping-get-v1", method = RequestMethod.GET)
public String mappingGetV1() {
    log.info("mappingGetV1");
    return "ok";
}
  • @RequestMapping 에 method 속성으로 HTTP 메서드를 지정하지 않으면 HTTP 메서드와 무관하게 호출된다.
  • 모두 허용 GET, HEAD, POST, PUT, PATCH, DELETE
  • @RequestMapping에 method 속성을 통해 HTTP 메서드를 지정하면, 해당 HTTP 메서드로만 호출이 가능하다.
  • 만일 지정하지 않은 HTTP 메서드를 통해 요청이 들어오면 상태코드 405(Method Not Allowed)를 반환한다.

HTTP 메서드 매핑 축약

/**
 * 편리한 축약 애노테이션 (코드보기) * @GetMapping
 * @PostMapping
 * @PutMapping
 * @DeleteMapping
 * @PatchMapping
 */
@GetMapping(value = "/mapping-get-v2")
public String mappingGetV2() {
    log.info("mapping-get-v2");
    return "ok";
}
  • HTTP 메서드를 축약한 애노테이션을 사용하는 것이 더 직관적이다. 코드를 보면 내부에서 @RequestMapping 과 method 를 지정해서 사용하는 것을 확인할 수 있다.

PathVariable(경로 변수) 사용

@PathVariable을 이용하여 url 경로에서 매칭되는 부분(변수)를 조회할 수 있다.

// localhost:8080/mapping/userA 로 요청한 경우, data의 값에 userA가 들어가게 된다.
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable("userId") String data) {
	log.info("mappingPath userId={}", data);
	return "ok";
}

@PathVariable의 이름과 변수명이 같다면 밑과 같이 생략할 수 있다.

// @PathVariable의 이름과 파라미터 이름이 같으면 밑과 같이 생략할 수 있다.
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable String userId) {
	log.info("mappingPath userId={}", userId);
	return "ok";
}

@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";
}

특정 파라미터 조건 매핑

1. 파라미터를 통한 추가 매핑 : params = "key=value"

  • value에 해당하는 url의 뒤에 query string 형식을 통해 특정 파라미터가 있거나 없는 조건을 통해 추가 매핑할 수 있다.
    • = 외에도, !, !=, 중복 조건 등을 추가할 수 있다.
  • 밑의 코드 경우에는 localhost:8080/mapping-param?mode=debug 요청이 들어오면 실행된다.
/**
 * 특정 헤더로 추가 매핑
 * headers="mode",
 * headers="!mode"
 * headers="mode=debug"
 * headers="mode!=debug" (! = )
 */
 @GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
	 log.info("mappingHeader");
	return "ok";
}
  • 특정 파라미터가 있거나 없는 조건을 추가할 수 있다. 잘 사용하지는 않는다.

2. 특정 헤더 조건 매핑

  • HTTP 요청 메세지의 header 내용을 통해 추가 매핑할 수 있는 방법이다.
  • localhost:8080/mapping-header 요청이 들어왔을 때, HTTP의 header에 key의 값에 value가 있다면 밑의 메서드가 실행된다.
/**
 * 특정 헤더로 추가 매핑
 * headers="mode",
 * headers="!mode"
 * headers="mode=debug"
 * headers="mode!=debug" (! = )
 */
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
	 log.info("mappingHeader");
	return "ok";
}
  • 파라미터 매핑과 비슷하지만, HTTP 헤더를 사용한다.

3. 미디어 타입 조건 매핑 - HTTP 요청 Content-Type : consumes = "미디어 타입"

  • HTTP 요청의 Content-Type 헤더를 기반으로 미디어 타입으로 매핑한다.
  • 만약 맞지 않으면 HTTP 415 상태코드(Unsupported Media Type)을 반환한다.
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
	 log.info("mappingHeader");
	return "ok";
}

4. 미디어 타입 조건 매핑 - HTTP 요청 Accept : produce = "미디어 타입"

  • HTTP 요청의 Accept 헤더를 기반으로 미디어 타입으로 매핑한다.
  • 만약 맞지 않으면 HTTP 406 상태코드(Not Acceptable)을 반환한다.
@GetMapping(value = "/mapping-header", headers = "mode=debug")
public String mappingHeader() {
	 log.info("mappingHeader");
	return "ok";
}

요청 매핑 API 와 예시

REST API의 핵심인 리소스의 표현과 행위의 표현을 충족하기 위해서 Mapping의 축약 방법을 활용하면 좀 더 깔끔하게 설계가 가능하다

정리

  • URL 매핑을 위하여 @RequestMapping을 사용한다.
  • 메서드 혹은 클래스 단위로 Mapping을 주어 중복 URL을 공통으로 처리할 수 있다.
  • 각 매핑은 조건부로 제약조건을 주어 추가 매핑을 할 수 있다.
  • HTTP메서드에 따라 축약된 Mapping을 사용하면 훨씬 가독성이 좋은 코드를 작성할 수 있다.
  • 축약 Mapping을 활용하여 REST API를 설계할 수 있다.
profile
안녕하세요

0개의 댓글