HTTP API를 제공하는 경우에는 HTML이 아니라 데이터를 전달해야 한다.
HTTP 메시지 바디에 JSON 같은 형식으로 데이터를 실어 보낸다.
- HTML이나 뷰 템플릿 사용해도 HTTP 응답 메시지 바디에 HTML 데이터가 담겨서 전달됨.
- 정적 리소스나 뷰 템플릿 거치지 않고, 직접 HTTP 응답 메시지를 전달하는 경우를 말함
// ResponseBodyController Class
package hello.springmvc.basic.response;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
//@RestController
//@Controller 대신에 @RestController 애노테이션을 사용하면, 해당 컨트롤러에 모두
//@ResponseBody 가 적용되는 효과가 있다. 따라서 뷰 템플릿을 사용하는 것이 아니라, HTTP 메시지 바디에
// 직접 데이터를 입력한다. 이름 그대로 Rest API(HTTP API)를 만들 때 사용하는 컨트롤러이다.
// 참고로 @ResponseBody 는 클래스 레벨에 두면 전체에 메서드에 적용되는데, @RestController
//에노테이션 안에 @ResponseBody 가 적용되어 있다.
@RestController
public class ResponseBodyController {
// responseBodyV1
// 서블릿을 직접 다룰 때 처럼
// HttpServletResponse 객체를 통해서 HTTP 메시지 바디에 직접 ok 응답 메시지를 전달한다.
// response.getWriter().write("ok")
@GetMapping("response-body-string-v1")
public void responseBodyV1(HttpServletResponse response) throws IOException {
response.getWriter().write("ok");
}
// responseBodyV2
// ResponseEntity 엔티티는 HttpEntity 를 상속 받았는데, HttpEntity는 HTTP 메시지의 헤더, 바디
// 정보를 가지고 있다. ResponseEntity 는 여기에 더해서 HTTP 응답 코드를 설정할 수 있다.
// HttpStatus.CREATED 로 변경하면 201 응답이 나가는 것을 확인할 수 있다
@GetMapping("response-body-string-v2")
public ResponseEntity<String> responseBodyV2() throws IOException {
return new ResponseEntity<>("ok", HttpStatus.OK);
}
// responseBodyV3
// @ResponseBody 를 사용하면 view를 사용하지 않고, HTTP 메시지 컨버터를 통해서 HTTP 메시지를 직접
// 입력할 수 있다. ResponseEntity 도 동일한 방식으로 동작한다.
@ResponseBody
@GetMapping("response-body-string-v3")
public String responseBodyV3() {
return "ok";
}
// responseBodyJsonV1
// ResponseEntity 를 반환한다. HTTP 메시지 컨버터를 통해서 JSON 형식으로 변환되어서 반환된다.
@GetMapping("/response-body-json-v1")
public ResponseEntity<HelloData> responseBodyJsonV1() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return new ResponseEntity<>(helloData, HttpStatus.OK);
}
// responseBodyJsonV2
// ResponseEntity 는 HTTP 응답 코드를 설정할 수 있는데, @ResponseBody 를 사용하면 이런 것을
//설정하기 까다롭다.
// @ResponseStatus(HttpStatus.OK) 애노테이션을 사용하면 응답 코드도 설정할 수 있다.
// 물론 애노테이션이기 때문에 응답 코드를 동적으로 변경할 수는 없다. 프로그램 조건에 따라서 동적으로
// 변경하려면 ResponseEntity 를 사용하면 된다.
// ResponseBody가 있으면 (helloData, HttpStatus.OK) 지정을 못하니까 @ResponseStatus(HttpStatus.OK) annotation을 쓴다.
@ResponseStatus(HttpStatus.OK)
@ResponseBody
@GetMapping("/response-body-json-v2")
public HelloData responseBodyJsonV2() {
HelloData helloData = new HelloData();
helloData.setUsername("userA");
helloData.setAge(20);
return helloData;
}
}
최상단에 @ResponseBody를 붙이거나
@Controller이나 @ResponseBody를 주석처리하고 @RestController를 붙여서 대체할 수 있다.
@Slf4j
//@Controller
@ResponseBody
//@RestController
public class ResponseBodyController {
@Slf4j
//@Controller
//@ResponseBody
@RestController
public class ResponseBodyController {
HTTP 메시지 컨버터
뷰 템플릿으로 HTML을 생성해 응답하는 게 아니고, HTTP API처럼 JSON 데이터를 HTTP 메시지 바디에 직접 읽거나 쓰는 경우에 HTTP 메시지 컨버터를 사용하면 편리하다.
@ResponseBody를 사용
- HTTP의 BODY에 문자 내용을 직접 반환
- viewResolver 대신에 HttpMessageConverter이 동작
- 기본 문자처리: StringHttpMessageConverter
- 기본 객체처리: MappingJackson2HttpMessageConverter
- byte 처리 등등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있음
=> 응답의 경우 클라이언트의 HTTP Accept 해더와 서버의 컨트롤러 반환 타입 정보 둘을 조합해서
HttpMessageConverter 가 선택됨.
스프링 MVC는 다음의 경우에 HTTP 메시지 컨버터를 적용한다
- HTTP 요청: @RequestBody , HttpEntity(RequestEntity)
- HTTP 응답: @ResponseBody , HttpEntity(ResponseEntity)
HTTP 메시지 컨버터는 HTTP 요청, HTTP 응답 둘 다 사용된다.
- canRead() , canWrite() : 메시지 컨버터가 해당 클래스, 미디어타입을 지원하는지 체크
- read() , write() : 메시지 컨버터를 통해서 메시지를 읽고 쓰는 기능
스프링 부트 기본 메시지 컨버터
0 = ByteArrayHttpMessageConverter
1 = StringHttpMessageConverter
2 = MappingJackson2HttpMessageConverter
스프링 부트는 다양한 메시지 컨버터를 제공하는데, 대상 클래스 타입과 미디어 타입 둘을 체크해서
사용여부를 결정한다. 만약 만족하지 않으면 다음 메시지 컨버터로 우선순위가 넘어간다.
ByteArrayHttpMessageConverter : byte[] 데이터를 처리한다
- 클래스 타입: byte[] , 미디어타입: */*
- 요청 예) @RequestBody byte[] data
- 응답 예) @ResponseBody return byte[] 쓰기 미디어타입 application/octet-stream
StringHttpMessageConverter : String 문자로 데이터를 처리한다.
- 클래스 타입: String , 미디어타입: */*
- 요청 예) @RequestBody String data
- 응답 예) @ResponseBody return "ok" 쓰기 미디어타입 text/plain
MappingJackson2HttpMessageConverter : application/json
- 클래스 타입: 객체 또는 HashMap , 미디어타입 application/json 관련
- 요청 예) @RequestBody HelloData data
- 응답 예) @ResponseBody return helloData 쓰기 미디어타입 application/json 관련
StringHttpMessageConverter
content-type: application/json
@RequestMapping
void hello(@RequetsBody String data) {}
MappingJackson2HttpMessageConverter
content-type: application/json
@RequestMapping
void hello(@RequetsBody HelloData data) {}
?
content-type: text/html
@RequestMapping
void hello(@RequetsBody HelloData data) {}
HTTP 요청 데이터 읽기
HTTP 요청이 오고, 컨트롤러에서 @RequestBody , HttpEntity 파라미터를 사용한다.
메시지 컨버터가 메시지를 읽을 수 있는지 확인하기 위해 canRead() 를 호출한다.
대상 클래스 타입을 지원하는가.
- 예) @RequestBody 의 대상 클래스 ( byte[] , String , HelloData )
HTTP 요청의 Content-Type 미디어 타입을 지원하는가.
- 예) text/plain , application/json , */*
canRead() 조건을 만족하면 read() 를 호출해서 객체 생성하고, 반환한다.
HTTP 응답 데이터 생성
컨트롤러에서 @ResponseBody , HttpEntity 로 값이 반환된다.
메시지 컨버터가 메시지를 쓸 수 있는지 확인하기 위해 canWrite() 를 호출한다
대상 클래스 타입을 지원하는가
- 예) return의 대상 클래스 ( byte[] , String , HelloData )
HTTP 요청의 Accept 미디어 타입을 지원하는가.(더 정확히는 @RequestMapping 의 produces )
- 예) text/plain , application/json , */*
canWrite() 조건을 만족하면 write() 를 호출해서 HTTP 응답 메시지 바디에 데이터를 생성한다
<출처 김영한: 스프링 MVC 1편 - 벡앤드 웹 개발 핵심 기술>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의
웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -
www.inflearn.com
'Spring > SpringMVC' 카테고리의 다른 글
스프링MVC 프로젝트 - 도메인 개발 & 상품 서비스 HTML (0) | 2022.05.03 |
---|---|
요청 매핑 헨들러 어뎁터 구조 (0) | 2022.05.01 |
HTTP 요청 메시지 - JSON & HTTP 응답 - 정적 리소스, 뷰 템플릿 (0) | 2022.05.01 |
HTTP 요청 파라미터 - @ModelAttribute & 단순 텍스트 (0) | 2022.04.29 |
HTTP 요청 파라미터 - 쿼리 파라미터, HTML Form & RequestParam (0) | 2022.04.29 |