인프런/스프링 MVC 1편

14)HTTP 응답 문자(v1~v3) JSON(v1~v2) ,@RestController

backend dev 2023. 1. 26.

V1 - HttpServletResponse 객체이용

@GetMapping("/response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
    response.getWriter().write("ok");
}

spring에게 HttpServletResponse를 전달받고, Writer를 받아 바디에 값을 넣어주는것이다

V2 - ResponseEntity<> , HttpEntity<>

@GetMapping("/response-body-string-v2")
public ResponseEntity<String> responseBodyV2() {
    return new ResponseEntity<>("ok", HttpStatus.OK);
}

HttpEntity<>를 사용해서  바디,헤더값을 넣어 응답할 수 있고

ResponseEntity<>를 이용하면 바디,헤더,상태코드을 넣어 응답 할 수 있다. ( ResponseEntity는 상태코드가 필수입력값)

ResponseEntity<> , HttpEntity<>는 받은 객체를 http메시지컨버터를 통해 JSON으로 변환시키고

http응답메시지바디에 값을 넣어주는데

(값을 넣어주는 방법은 HttpServletResponse 객체의 Writer를 이용하는것같다. 그리고 서블릿 컨테이너가  HttpServletResponse의 내용을 이용해서  http응답메시지를 생성해준다.)

 

(@ResponseBody가 없는 @Controller의 컨트롤러에서도 HttpEntity<> , ResponseEntity<>는 메세지컨버터가 동작해서 해당 객체를 JSON으로 변환해서 응답내준다.   당연하게도 HttpEntity<> , ResponseEntity<>는 http응답메시지 바디에 직접 값을 넣어야하니까 http메시지컨버터가 동작한다. (@ResponseBody가 없어도) ) -> 15장에서 설명나옴

 

1)★★http,웹서버,웹 어플리케이션 서버,웹 시스템 구성,서블릿(servlet),동시요청 - 멀티스레드,HTML

HTTP란? 클라이언트에서 서버로, 서버에서 클라이언트로 데이터를 전송할때 http라는 프로토콜기반으로 동작한다. 그래서 대부분의 데이터는 http기반으로 주고 받는다. 웹 서버(Web Server) 정적 리

keeeeeepgoing.tistory.com

 

V3 - @ResponseBody 사용

@ResponseBody
@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
    return "ok";
}

메소드에 @ResponseBody를 붙이면 반환되는 값을 http응답메시지바디에 넣어준다.(http메시지컨버터를 통해서)

 

여기까지가 문자로 응답하는 방법


여기서부터 JSON으로 응답하는 방법

V1 - ResponseEntity<> , HttpEntity<>

ResponseEntity를 이용한다면   (상태코드는 필수값)

@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return new ResponseEntity<>(helloData, HttpStatus.OK);
}

HttpEntity를 이용한다면

@GetMapping("/response-body-json-v1")
public HttpEntity<HelloData> responseBodyJsonV1() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return new HttpEntity<>(helloData);
}

V2 - @ResponseBody

@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return helloData;
}

@ResponseBody를 메소드에 붙이면 객체를 반환할때 객체 -> JSON으로 변환이 이뤄져서 응답이 된다.

 

만약  ResponseEntity<>를 사용할때처럼 상태코드를 내가 원하는 대로 지정하고 싶다면 

@ResponseStatus 어노테이션을 사용하면 된다.

@ResponseStatus

@ResponseStatus(HttpStatus.ACCEPTED)
@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return helloData;
}

해당 어노테이션이 붙은 메소드는 http상태코드가 설정한대로 나타난다.

 

 

@Controller + @ResponseBody

클래스레벨에 @ResponseBody를 붙이면 모든 메소드에 @ResponseBody가 적용된다.

@Slf4j
@Controller
@ResponseBody
public class ResponseBodyController {
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return new ResponseEntity<>(helloData, HttpStatus.OK);
}

ResponseEntity<>를 사용하는 메소드에 @ReponseBody가 붙어도 동작은 같다. ReponseEntity는 어차피 응답메시지의 설정을 위한것이니까

@GetMapping("/response-body-string-v3")
public String responseBodyV3() {
    return "ok";
}

클래스레벨에  @ResponseBody를 붙였기에 ok라는 문자열이 바디에 잘 담겨 와서 작동한다.

@Controller + @ResponseBody  = @RestController

그래서 탄생한 컨트롤러가 @RestController이다.

@Slf4j
@RestController
public class ResponseBodyController {

    @GetMapping("/response-body-string-v1")
    public void responseBodyV1(HttpServletResponse response) throws IOException {
        response.getWriter().write("ok"); //response객체를 이용해 바디값을 사용넣는방식
    }

    @GetMapping("/response-body-string-v2")
    public ResponseEntity<String> responseBodyV2() {
        return new ResponseEntity<>("ok", HttpStatus.OK); // ResponseEntity를 이용해 응답메시지를 설정하는 방식
    }


    @GetMapping("/response-body-string-v3")
    public String responseBodyV3() {
        return "ok"; //@ResponseBody덕에 문자열 그대로 바디에 담겨서 응답이 나간다.
    }


    @GetMapping("/response-body-json-v1")
    public ResponseEntity<HelloData> responseBodyJsonV1() {
        HelloData helloData = new HelloData();
        helloData.setUsername("kim");
        helloData.setAge(20);
        return new ResponseEntity<>(helloData, HttpStatus.OK); // ResponseEntity를 이용해 응답메시지를 설정하는 방식
        //객체를 JSON으로 변환하기 위해 메시지컨버터가 동작한다.
    }

    @ResponseStatus(HttpStatus.ACCEPTED)
    @GetMapping("/response-body-json-v2")
    public HelloData responseBodyJsonV2() {
        HelloData helloData = new HelloData();
        helloData.setUsername("kim");
        helloData.setAge(20);
        return helloData; //@ResponseBody덕분에 객체가 JSON으로 변환되어 응답이 나간다.
    }

}

모든메소드가 잘 동작함을 확인할 수 있었다.

@Restcontroller는 @Controller + @ResponseBody이고 ,  클래스레벨에 @ResponseBody가 붙어있으면 모든 메소드에 @ResponseBody가 적용된다.

 

 

결론

@RestController를 컨트롤러에 붙이고

@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(20);
    return helloData;
}

API만들때 위와같은 응답방식을 많이 사용한다. 

(@RestController의 @ResponseBody덕분에 객체를 그냥 리턴해도 HTTP메시지컨버터로 인해

JSON으로 반환되어 응답이 나가는 형태)   (정확하게는 MappingJackson2HttpMessageConverter라는 메시지컨버터)

 

댓글