[Spring]HTTP Body 요청 처리

김용현·2023년 9월 28일
0

Spring

목록 보기
6/13

본 글은 김영한님의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술강의를 토대로 작성하였습니다.

앞선 글에서 @RequestParam, @ModelAttribute에 대해 알아봤다.
여기서 주의할 점은 앞선 글에서는 클라이언트 요청을 받는 3가지 방법 중,
쿼리 파라미터HTTP Form 방식으로 데이터가 들어왔을 때의 처리 방법이었다.
이번 글에서는 HTTP message Body에 데이터가 담겨져 들어올 때의 처리 방법에 대해 알아보자.
(HTML Form 방식의 경우 HTTP message Body에 담기긴 하지만 요청 파라미터 방식으로 인정되어 @RequestParam, @ModelAttribute를 사용하는 것이 가능하다.)

HTTP 요청 - 텍스트

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

첫 단계는 역시 HttpServletRequest를 사용하는 방법이다. request의 getInputStream()함수를 호출하여 ServletInputStream 객체를 획득하고 이를 이용하여 HTTP Message Body 자체를 가져올 수 있다.

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

다음은 request 객체를 받지 않고 바로 InputStream 객체를 파라미터로 넣어 바로 받는 방식이다.
이처럼 따로 객체를 생성하는 코드를 파라미터에 객체를 변수로 받음으로써 생략할 수 있다.

다음 방식은 HTTPEntity를 이용하는 것이다.

/**
* HttpEntity: HTTP header, body 정보를 편리하게 조회
* - 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 *
* 응답에서도 HttpEntity 사용 가능
* * */
- 메시지 바디 정보 직접 반환(view 조회X)
- HttpMessageConverter 사용 -> StringHttpMessageConverter 적용
  @PostMapping("/request-body-string-v3")
  public HttpEntity<String> requestBodyStringV3(HttpEntity<String> httpEntity) {
      String messageBody = httpEntity.getBody();
      log.info("messageBody={}", messageBody);
      return new HttpEntity<>("ok");
  }

다음과 같이 HttpEntity 객체로 http body를 받아 getBody()함수를 호출하면 이를 문자열로 가져올 수 있다. 또한 리턴 값 또한 HttpEntity객체를 반환하면 이를 Http Message Body에 담아 response로 내보낸다.

❗️참고
다음과 같이 HttpEntity를 상속받는 RequestEntity, ResponseEntity를 사용할 수도 있다.

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

❗️참고
스프링MVC 내부에서 HTTP 메시지 바디를 읽어서 문자나 객체로 변환해서 전달해주는데, 이때 HTTP
메시지 컨버터( HttpMessageConverter )라는 기능을 사용한다.

마지막 최종은 @RequesetBody 어노테이션을 사용하는 것이다.

/**
     * @RequestBody
* - 메시지 바디 정보를 직접 조회(@RequestParam X, @ModelAttribute X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 *
* @ResponseBody
* - 메시지 바디 정보 직접 반환(view 조회X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 */
    @ResponseBody
    @PostMapping("/request-body-string-v4")
    public String requestBodyStringV4(@RequestBody String messageBody) {
        log.info("messageBody={}", messageBody);
        return "ok";
    }

정말 간단해졌다. 단지 파라미터로 @RequestBody를 선언하고 뒤에 받을 변수를 선언해주면 된다.
이와 관련하여 응답을 보낼 때도 @ResponseBody어노테이션이 붙으면 return 하는 String 자체를 응답 바디에 담아서 그대로 내보낸다.

HTTP 요청 - JSON

이렇게 HTTP Message Body의 데이터를 그대로 읽을 수 있는 방법을 알아봤다. 물론 body 데이터를 읽어와서 Json으로 파싱할 수도 있겠지만 Spring에서는 더욱 효과적으로 Json 형태의 데이터를 가져올 수 있다. 이 또한 단계별로 알아보자

처음은 늘 그렇듯 HttpServletRequest 방식이다.

/**
   * {"username":"hello", "age":20}
   * content-type: application/json
   */
  @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 data = objectMapper.readValue(messageBody, HelloData.class);
          log.info("username={}, age={}", data.getUsername(), data.getAge());
          
          response.getWriter().write("ok");
      }
}

ObjectMappter 객체를 획득하여 이를 이용해 HelloData 객체를 생성한다.

다음은 @RequestBody를 이용해 데이터를 가져오는 부분을 단순화한 것이다.

/**
* @RequestBody
* HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 *
* @ResponseBody
* - 모든 메서드에 @ResponseBody 적용
* - 메시지 바디 정보 직접 반환(view 조회X)
* - HttpMessageConverter 사용 -> StringHttpMessageConverter 적용 */
  @ResponseBody
  @PostMapping("/request-body-json-v2")
  public String requestBodyJsonV2(@RequestBody String messageBody) throws
  IOException {
      HelloData data = objectMapper.readValue(messageBody, HelloData.class);
      log.info("username={}, age={}", data.getUsername(), data.getAge());
      return "ok";
}

body를 가져오는 방식만 바뀌고 나머지는 동일하다. 앞서 알아본 단순히 텍스트를 가져오고 이를 다시 객체로 변환하는 방식이다. 그렇다면 한 번에 모델 객체로 변환하는 방법은 없을까?

다음은 @RequestBody 객체 변환 방식이다.

/**
* @RequestBody 생략 불가능(@ModelAttribute 가 적용되어 버림)
* HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter (content-
  type: application/json)
   *
*/
  @ResponseBody
  @PostMapping("/request-body-json-v3")
  public String requestBodyJsonV3(@RequestBody HelloData data) {
	  log.info("username={}, age={}", data.getUsername(), data.getAge());
        return "ok";
    }

마치 @ModelAttribute를 적용하는 것처럼 앞에 RequestBody를 붙이고 뒤에 변환할 객체를 적어주면 Spring에서 알아서 변환하여 객체를 생성해준다.

❗️주의할 점은 @ReqeustBody를 생략할 수 없다.
-> 이유는 생략할 시 @ModelAttribute가 적용되어 요청 파라미터로 처리해버리기 때문에 생성된 객체 안에 데이터가 들어가지 않는다.

또한 HttpEntity를 이용하여 객체를 생성하는 것도 가능하다.

@ResponseBody
    @PostMapping("/request-body-json-v4")
    public String requestBodyJsonV4(HttpEntity<HelloData> httpEntity) {
    HelloData data = httpEntity.getBody();
      log.info("username={}, age={}", data.getUsername(), data.getAge());
      return "ok";
}

getBody()의 리턴 값을 객체에 넣어주면 된다.(신기하다 그냥 넣으면 알아서 spring이 바꿔주네)

응답 데이터를 보낼 때도 간편하게 가능하다(@ResponseBody)

/**
* @RequestBody 생략 불가능(@ModelAttribute 가 적용되어 버림)
* HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter (content-
  type: application/json)
   *
* @ResponseBody 적용
* - 메시지 바디 정보 직접 반환(view 조회X)
* - HttpMessageConverter 사용 -> MappingJackson2HttpMessageConverter 적용
  (Accept: application/json)
   */
  @ResponseBody
  @PostMapping("/request-body-json-v5")
  public HelloData requestBodyJsonV5(@RequestBody HelloData data) {
      log.info("username={}, age={}", data.getUsername(), data.getAge());
      return data;
  }

이렇게 json 응답을 내보낼 때 간편하게 이용할 수 있다.

이처럼 api 서버를 만들 때 Spring의 다양한 기능을 사용하면 손 쉽게 만들 수 있다.

profile
평생 여행 다니는게 꿈 💭 👊 😁 🏋️‍♀️ 🦦 🔥

1개의 댓글

comment-user-thumbnail
2024년 5월 17일

좋은글 감사드려요

답글 달기

관련 채용 정보