숑숑이의 개발일기

메시지가 단순 텍스트인 경우

파라미터와 다르게 HTTP 메시지 바디를 통해 데이터가 넘어오는 경우, @RequestParam, @ModelAttribute를 사용하지 못한다.(Form 형식으로 전달되는 경우에는 요청 파라미터로 인정된다.)

 

InputStream (서블릿)

HTTP 메시지 바디의 데이터를 InputStream을 활용해 직접 읽을 수 있다.

@PostMapping("/request-body-string-v1")
public void requestBodyString(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ServletInputStream inputStream = request.getInputStream();
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    log.info("messageBody={}", messageBody);
    response.getWriter().write("ok");
}

 

해당 코드를 조금 더 간략하게 바꾼다면 아래와 같이 바꿀수 있다. 스프링 MVC에서 InputStreamOutputStream(Writer)을 지원하기 때문이다.

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

 

HttpEntity

이전에 HTTP Entity를 사용하여 HTTP 헤더와 바디 정보를 편리하게 조회할 수 있다는것을 배웠다. 이를 해당 코드에도 적용할 수 있다.

@PostMapping("/request-body-string-v3")
public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) throws IOException {
    String messageBody = httpEntity.getBody();
    log.info("messageBody={}", messageBody);

    return new HttpEntity<>("ok");
}

HttpEntitiy는 응답에도 사용이 가능하며 헤더의 정보를 포함할 수 있다는 이점이있다.

HttpEntitiy를 상속받은 RequestEntitiy, ResponseEntitiy 객체들도 아래와 같은 기능을 제공한다.

  • RequestEntity : HttpMethod, url 정보 추가, 요청에서 사용
  • ResponseEntity : HTTP 상태 코드 설정 가능, 응답에서 사용

 

@RequestBody

그리고 이를 더 간단하게 사용하자면 스프링 MVC의 @RequestBody가 존재한다. 허나 @RequestBody 어노테이션 단일로는 헤더 정보를 조회할 수 없으므로 헤더의 정보가 필요하다면 HttpEntitiy 혹은 메서드 단위에 @ResponseBody 어노테이션을 사용하면 된다. 이 경우, view는 사용하지 않는다.

@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) {
    log.info("messageBody={}", messageBody);

    return "ok";
}

 

 

요청 메시지가 JSON인 경우

먼저 JSON 데이터를 자바 객체로 변환하기 위해 Jackson 라이브러리인 objectMapper를 생성한다.

private ObjectMapper objectMapper = new ObjectMapper();

 

그리고 포스트맨으로 테스트 시엔 꼭 json 형식으로 테스트한다.

  • {"username":"hello", "age":20}
  • content-type: application/json
@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");

}

해당 코드는 단순 텍스트를 읽어왔을때와 비슷하게, HttpServletRequest를 사용하여 직접 데이터를 읽어와서 문자로 변환한다. 이후 objectMapper를 사용하여 자바 객체로 변환한다.

 

위에서 학습하였던 @RequestBody를 json형식에서도 사용가능하다.

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

허나 파라미터에서 문자로 변환후, objectMapper를 사용하여 다시 json으로 변환하는 과정이 불편하다.

 

그래서 아래와 같이(HelloData) 직접 만든 객체를 지정할 수 있다.

@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return "ok";
}

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

이전에 학습하였던 @RequestParam@ModelAttribute의 경우 이름이 같다면 생략할 수 있었다. 그러나 @RequestBody의 경우 생략하면 위의 코드에서는 @ModelAttribute가 적용되므로 생략하지 말자. (메시지 바디가 아닌 요청 파라미터를 처리하게 된다.)

 

또한 위의 2번째 코드와 같이 HttpEntitiy<객체>와 같이 사용할 수도 있다. 

 

응답의 경우에도 @ResponseBody 어노테이션을 사용하여 해당 객체를 바로 HTTP 메시지 바디에 넣어줄 수 있다.

@ResponseBody
@PostMapping("/request-body-json-v5")
public HelloData requestBodyJsonV5(@RequestBody HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return helloData;
}

해당 코드와 같이 작성하면 응답값이 ok가 아닌 json형태로 반환된다. 당연히 이 경우에도 HttpEntity<HelloData>와 같이 사용해도 된다.

 

정리하자면 아래와 같다.

  • @RequestBody 요청 : JSON 요청 -> Http 메시지 컨버터 -> 객체
  • @ResponseBdoy 응답 : 객체 -> Http 메시지 컨버터 -> JSON 응답
위 글은 김영한 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술의 일부 내용을 정리한 것입니다.
profile

숑숑이의 개발일기

@숑숑-

풀스택 개발자 준비중입니다