다음은 HTTP 요청 메시지를 통해 데이터를 전달하는 세 번째 방법에 대해 알아본다.
③ HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용(JSON, XML...)
- POST, PUT...
요청 파라미터(GET, POST)를 사용한 이전 두 가지 방법과는 다르게, HTTP Message Body를 통해 데이터가 직접 넘어오는 경우에는 @RequestParam, @ModelAttribute를 사용할 수 없다.
Text 메시지 전송
먼저 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하는 실습을 한다. HTTP 메시지 바디의 데이터를 InputStream 을 사용해서 직접 읽을 수 있다.
@Slf4j
@Controller
public class RequestBodyStringController {
@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
// 바이트 코드(stream)를 문자로 받을 때는 어떤 인코딩 방식으로 변환할 것인지 설정해야 한다.
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
response.getWriter().write("good");
}
}
현재 Servlet 전체를 다 받을 필요가 없다. Spring에서는 다음 파라미터를 지원한다.
- InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
- OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력
@PostMapping("/request-body-string-v2")
public void requestBodyStringV2(InputStream inputStream, Writer responseWriter) throws IOException {
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
responseWriter.write("good");
}
HTTP Message Converter
스프링 MVC는 추가적으로 다음 파라미터를 지원한다.
# HttpEntity: HTTP Header, Body 정보를 편리하게 조회
- 메시지 바디 정보를 직접 조회
- HttpEntity는 응답에도 사용이 가능한데, 메시지 바디 정보를 직접 반환하거나 헤더 정보 포함이 가능하다.
- RequestEntity, ResponseEntity도 HttpEntity를 상속 받은 것으로,
@PostMapping("/request-body-string-v4")
public HttpEntity<String> requestBodyStringV2(HttpEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new HttpEntity<>("ok");
}
//
@PostMapping("/request-body-string-v5")
public HttpEntity<String> requestBodyStringV3(RequestEntity<String> httpEntity) throws IOException {
String messageBody = httpEntity.getBody();
log.info("messageBody={}", messageBody);
return new ResponseEntity<String>("ok", HttpStatus.CREATED);
}
# @RequestBody
@RequestBody 를 사용하면 HTTP 메시지 바디 정보를 편리하게 조회할 수 있다. 참고로 헤더 정보가 필요하다면 HttpEntity 를 사용하거나 @RequestHeader 를 사용하면 된다.
이렇게 메시지 바디를 직접 조회하는 기능은 요청 파라미터를 조회하는 @RequestParam , @ModelAttribute 와는 전혀 관계가 없다.
동작 방식
JSON 요청 → HTTP Message Converter → 객체
# @ResponseBody
@ResponseBody 를 사용하면 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다. 물론 이 경우에도 view를 사용하지 않는다.
동작 방식
객체 → HTTP Message Converter → JSON 응답
@ResponseBody
@PostMapping("/request-body-string-v6")
public String requestBodyStringV6(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
return "ok";
}
JSON
다음은 JSON 형태의 데이터를 HTTP Body에 담아 데이터를 전달하는 코드이다. HttpServlet 전체를 다 받아와서 request, response를 추출할 수 있다.
@Slf4j
@Controller
public class RequestBodyJsonController {
private ObjectMapper objectMapper = new ObjectMapper();
@PostMapping("/request-body-json-v1")
public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
log.info("messageBody={}", messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
response.getWriter().write("ok");
}
}
이전에 학습했던 @RequestBody 를 사용해서 HTTP 메시지에서 데이터를 꺼내고 messageBody에 저장한다.
문자로 된 JSON 데이터인 messageBody 를 objectMapper 를 통해서 자바 객체로 변환한다.
// V2
@ResponseBody
@PostMapping("/request-body-json-v2")
public String requestBodyJsonV2(@RequestBody String messageBody) throws IOException {
log.info("messageBody={}", messageBody);
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
문자로 변환하고 다시 json으로 변환하는 과정이 불편하다. @ModelAttribute처럼 한번에 객체로 변환할 수는 없을까?
바로 @RequestBody 객체 파라미터를 사용하면 된다. @RequestBody 에 직접 만든 객체를 지정할 수 있다.
HttpEntity , @RequestBody 를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해준다.
HTTP 메시지 컨버터는 문자 뿐만 아니라 JSON도 객체로 변환해주는데, 우리가 방금 V2에서 했던 작업을 대신 처리해준다.
// V3
@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData helloData) throws IOException {
log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
return "ok";
}
스프링은 @ModelAttribute , @RequestParam 과 같은 해당 애노테이션을 생략시 다음과 같은 규칙을 적용한다.
- String , int , Integer 같은 단순 타입 → @RequestParam
- 나머지 → @ModelAttribute (argument resolver 로 지정해둔 타입 외)
따라서 이 경우 HelloData에 @RequestBody 를 생략하면 @ModelAttribute 가 적용되어버린다.
따라서 생략하면 HTTP 메시지 바디가 아니라 요청 파라미터를 처리하게 되는데, 요청 파라미터를 따로 전달하지 않았으니 아무 일도 발생하지 않게 된다.
물론 HttpEntity를 사용해도 된다.
@ResponseBody
@PostMapping("/request-body-json-v4")
public String requestBodyJsonV4(HttpEntity<HelloData> data) {
HelloData helloData = data.getBody();
log.info("username={}, age={}",helloData.getUsername(), helloData.getAge());
return "ok";
}
JSON 타입의 객체를 반환할 수도 있다.
@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData data) throws IOException {
return data;
}
'🌱 Spring > MVC ①' 카테고리의 다른 글
[Spring] HTTP 응답 _ HTTP API, 메시지 바디에 직접 입력 (0) | 2023.07.24 |
---|---|
[Spring] HTTP 응답 _ 정적 리소스, 뷰 템플릿 (0) | 2023.07.24 |
[Spring] HTTP 요청 - @ModelAttribute (0) | 2023.07.24 |
[Spring] HTTP 요청 - 헤더 & 파라미터 조회(@RequestParam) (0) | 2023.07.22 |
[Spring] RequestMapping _ API 매핑 (0) | 2023.07.22 |