본문 바로가기
Tech/Spring

ResponseEntity vs @ResponseStatus

반응형

1. ResponseEntity란?

  • Spring Framework에는 HTTP Request 혹은 Response을 나타내기 위해 제공하는 HttpEntity라는 클래스가 존재합니다
  • HttpEntity는 HttpHeaderHttpBody를 포함하는 클래스입니다
  • 위에서 소개된 HttpEntity를 상속하여 추가적으로 HttpStatus 속성을 더 가지는 클래스가 RequestEntity, ResponseEntity 클래스입니다
  • 제네릭으로 선언되어있으며 해당부분은 HttpBody의 타입을 나타냅니다

 

2. @ResponseStatus란?

  • 위에서 소개드린 ResponseEntity를 이용하면 HttpStatus, HttpHeader, HttpBody를 표현할 수 있습니다
  • 이 중에서 HttpStatus를 다른 방식으로 표현할 수 있는데 이것이 @ResponseStatus 어노테이션을 통해 마킹하는 방법입니다
  • Controller단에서 반환하는 Body를 감싸 @ResponseStatus에 정의된 HttpStatus를 추가할 수도 있지만 주로 예외처리에서 많이 쓰입니다 ( 이유는 사용법에서!! )

 

3. 사용법

  • ResponseEntity
    • static method를 활용하여 ResponseEntity 반환
      // static method
      
      @GetMapping(value = "/my-response/v1/get")
      public ResponseEntity<String> myV1Get() {
          return ResponseEntity.ok("hello world!");
      }​

      // response
      
      HTTP/1.1 200 
      Content-Type: text/plain;charset=UTF-8
      Content-Length: 12
      Date: Sun, 12 Sep 2021 05:26:22 GMT
      Keep-Alive: timeout=60
      Connection: keep-alive
      
      hello world!​

      • ResponseEntity에는 자주 쓰이는 HttpStatus로 쉽게 instance를 생성할 수 있는 static 메서드를 지원합니다
      • OK(200), CREATED(201), NO_CONTENT(204), NOT_FOUND(404) 등등
    • 생성자를 이용한 ResponseEntity 반환
      // constructor
      
      @GetMapping(value = "/my-response/v2/get")
      public ResponseEntity<String> myV2Get() {
          return new ResponseEntity("hello world!", HttpStatus.OK);
      }​

      // response
      
      HTTP/1.1 200 
      Content-Type: text/plain;charset=UTF-8
      Content-Length: 12
      Date: Sun, 12 Sep 2021 05:31:22 GMT
      Keep-Alive: timeout=60
      Connection: keep-alive
      
      hello world!​

      • 결국 static 메서드로 정의된 내용은 위의 예제처럼 생성자를 통해서 생성할 수 있습니다
      • ResponseEntity는 여러 생성자를 지원하며 HttpBody, HttpHeader, HttpStatus 세 가지의 케이스를 유연하게 오버로딩해놨습니다
    • HttpHeader 추가하기
      // add HttpHeader
      
      @GetMapping(value = "/my-response/v3/get")
      public ResponseEntity<String> myV3Get() {
          MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
          headers.add("test", "hello world!!!!");
          return new ResponseEntity("hello world!", headers, HttpStatus.OK);
      }​

      // response
      
      HTTP/1.1 200 
      test: hello world!!!!
      Content-Type: text/plain;charset=UTF-8
      Content-Length: 12
      Date: Sun, 12 Sep 2021 05:34:32 GMT
      Keep-Alive: timeout=60
      Connection: keep-alive
      
      hello world!​

      • ResponseEntity는 MultiValueMap type을 가지는 Header를 정의할 수 있습니다
      • 기본적으로 쓰이는 Header(Content-Type, Accept 등)은 각기 다른 어노테이션등으로 마킹하여 표기하는 것이 일반적이나 커스텀한 Header등을 정의할 때 사용합니다
  • @ResponseStatus
    • Controller layer 사용
      // @ResponseStatus
      
      
      @ResponseStatus(value = HttpStatus.OK)
      @GetMapping(value = "/my-response/v4/get")
      public String myV4Get() {
          return "hello world!";
      }
      
      @ResponseStatus(value = HttpStatus.CREATED)
      @GetMapping(value = "/my-response/v5/get")
      public String myV5Get() {
          return "hello world!";
      }​

      // HttpStatus.OK response
      
      HTTP/1.1 200 
      Content-Type: text/plain;charset=UTF-8
      Content-Length: 12
      Date: Sun, 12 Sep 2021 05:46:29 GMT
      Keep-Alive: timeout=60
      Connection: keep-alive
      
      hello world!
      
      
      
      
      // HttpStatus.CREATED response
      
      HTTP/1.1 201 
      Content-Type: text/plain;charset=UTF-8
      Content-Length: 12
      Date: Sun, 12 Sep 2021 05:46:32 GMT
      Keep-Alive: timeout=60
      Connection: keep-alive
      
      hello world!
      • 위 예제는 ModelAndView로 반환하는 @Controller가 아닌 텍스트 Body로 반환하는 @RestController 기준으로 작성되었습니다
      • @ResponseStatus에 정의된 HttpStatus로 반환되는 것을 확인할 수 있습니다
      • 다만 @ResponseStatus는 위에서 본 ResponseEntity 클래스처럼 유연하지 않습니다, 커스텀 Header 정의도 불가능하며 반환값에 추가적인 작업도 불가능합니다
      • @ResponseStatus의 기본 default는 HttpStatus.INTENAL_SERVER_ERROR(500) 입니다
    • Exception으로 활용
      // Custom Exception
      
      @ResponseStatus(value = HttpStatus.NOT_FOUND)
      @Slf4j
      public class MyResponseCustomException extends RuntimeException {
      
          public MyResponseCustomException(String message) {
              super(message);
              log.error(message);
          }
      }​



      • 기본적으로 Spring Web MVC는 로직상에서 Exception이 터지면 HttpStatus.INTERNAL_SERVER_ERROR를 반환합니다
      • 위처럼 Exception에 @ResponseStatus를 정의하면 해당 HttpStatus로 반환할 수 있습니다
    • @ControllerAdvice로 활용
      // @ControllerAdvice
      
      @RestControllerAdvice
      public class MyResponseGlobalExceptionHandler {
      
          @ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
          @ExceptionHandler(MyResponseCustomException.class)
          public String myResponseCustomExceptionHandler(MyResponseCustomException ex) {
              return ex.getMessage();
          }
      
      }
      • 위에서 보셧던 예저처럼 Exception에서 정의할 수도 있고, @ControllerAdvice 혹은 @ExceptionHandler에서 활용할 수 도 있습니다

 

728x90
반응형