[스프링] 스프링 MVC - 기본기능 (마지막) HTTP 요청 메시지: text와 JSON

2025. 9. 3. 19:28·스프링

지난 글에서 요청 파라미터(query string, form-data)를 @RequestParam, @ModelAttribute로 바인딩하는 법을 보았다.


이번에는 HTTP 요청 메시지(body) 자체를 읽어오는 방법을 살펴본다. 실무에서는 특히 JSON 본문을 주고받는 REST API가 많기 때문에 @RequestBody 사용을 익혀두는 게 중요하다.


아래 예제는 text 본문과 JSON 본문을 각각 “초기 버전 → 점점 스프링 방식 → 최종 버전”의 흐름으로 설명한다.

 

1. text 본문 읽기: RequestBodyStringController

v1. 서블릿 API로 직접 읽기 (가장 기초)

@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");
}
  • 흐름: request.getInputStream() 으로 바이트 스트림을 꺼내고 → StreamUtils.copyToString 으로 문자열로 변환 → response.getWriter() 로 직접 응답 작성.
  • 특징: 동작 원리를 이해하는 데 유용하지만, 코드가 길고 매번 스트림을 다뤄야 한다

v2. 스프링이 스트림을 주입받아 사용

@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");
}
  • 흐름: 서블릿 의존성을 줄이고, 스프링이 요청 입력 스트림과 응답 Writer를 직접 주입해준다.
  • 특징: v1보다 결합도가 낮고 테스트가 쉽다.

v3. HttpEntity로 본문과 헤더를 포괄적으로 다루기

@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<String> 에서 본문(body) 를 바로 꺼낸다. 필요하면 헤더도 다룰 수 있다.
  • 특징: 응답도 HttpEntity 로 반환해 상태/헤더/본문을 제어할 수 있다.

v4. 최종 버전: @RequestBody로 본문 바로 받기

@ResponseBody
@PostMapping("/request-body-string-v4")
public String requestBodyStringV4(@RequestBody String messageBody) {
    log.info("messageBody={}", messageBody);
    return "ok";
}
  • 흐름: @RequestBody 가 HTTP 메시지 본문을 문자열로 바로 바인딩한다. 응답은 @ResponseBody 로 본문에 직접 쓴다.
  • 특징: 가장 간결하고 실무에서 권장되는 형태다.
    → text 본문 처리의 최종 형태는 v4 방식으로 정리하면 된다.

 

2. JSON 본문 읽기: RequestBodyJsonController

v1. 서블릿 + ObjectMapper로 수동 파싱

@PostMapping("/request-body-json-v1")
public void requestBodyJsonV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String messageBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
    log.info("messageBody={}", messageBody); // {"username":"kim","age":20}

    HelloData data = objectMapper.readValue(messageBody, HelloData.class);
    log.info("username={}, age={}", data.getUsername(), data.getAge());

    response.getWriter().write("ok");
}
  • 흐름: 문자열로 읽은 뒤, ObjectMapper 로 직접 JSON → 객체(HelloData) 변환.
  • 특징: 동작 이해에는 좋지만, 컨트롤러마다 수동 파싱 코드를 반복해야 한다.

v2. @RequestBody String + ObjectMapper (반자동)

@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";
}
  • 흐름: 본문을 문자열로 받고, 변환만 ObjectMapper 로 수행.
  • 특징: v1보다 간단하지만 여전히 변환 코드를 써야 한다.

v3. 최종 버전: @RequestBody DTO (메시지 컨버터 자동 변환)

@ResponseBody
@PostMapping("/request-body-json-v3")
public String requestBodyJsonV3(@RequestBody HelloData data) {
    log.info("username={}, age={}", data.getUsername(), data.getAge());
    return "ok";
}
  • 흐름: @RequestBody HelloData 로 선언하면, 스프링의 메시지 컨버터(HttpMessageConverter) 가 JSON → HelloData 를 자동으로 변환한다.
  • 특징: 컨트롤러는 비즈니스 로직에만 집중할 수 있다.
    → JSON 본문 처리의 최종 형태는 v3 방식으로 정리하면 된다.

참고: JSON 요청을 보내는 클라이언트는 Content-Type: application/json 헤더를 반드시 포함해야 한다.

 

3. 그래서 어떻게 사용하나?

결국 실전에서 아래 두 가지 형태만 기억하면 된다.
text 본문은 @RequestBody String 으로 받고, JSON 본문은 @RequestBody DTO 로 받으면 된다.

 

text 본문 최종

@Slf4j
@RestController
public class TextApiController {

    @PostMapping("/text")
    public String handleText(@RequestBody String messageBody) {
        log.info("messageBody={}", messageBody);
        return "ok";
    }
}

 

JSON 본문 최종

@Slf4j
@RestController
public class HelloApiController {

    @PostMapping("/hello")
    public HelloData handleJson(@RequestBody HelloData data) {
        log.info("username={}, age={}", data.getUsername(), data.getAge());
        return data; // JSON으로 자동 변환되어 응답
    }
}

 

4. 언제 @RequestBody, 언제 @ModelAttribute?

  • @ModelAttribute
    • 데이터 출처: 요청 파라미터 (query string, form-data)
    • 예시: /search?username=kim&age=20
    • 적합한 경우: 검색 조건, 로그인·회원가입 등 간단한 폼 입력 처리
  • @RequestBody
    • 데이터 출처: HTTP 요청 본문 (JSON/XML/text)
    • 예시: { "username": "kim", "age": 20 }
    • 적합한 경우: REST API 요청, 클라이언트–서버 간 JSON 통신, 외부 시스템 연동

 

마무리하며

요약하면, 폼 전송이나 쿼리 파라미터는 @ModelAttribute, JSON 본문은 @RequestBody 를 사용하면 된다.

앞에서 본 버전 1, 2처럼 직접 스트림을 꺼내거나 ObjectMapper로 JSON을 일일이 변환하는 방식은 이미 스프링이 내부에서 구현해 두었다.


덕분에 개발자는 최종 버전 코드처럼 애노테이션 하나만 붙여주면 요청 데이터를 객체로 바인딩하고, 응답까지 JSON으로 자동 변환할 수 있다.

즉, 실전에선 다음 세 가지 페턴을 중점적으로 기억하면 된다.

  • text 본문 → @RequestBody String
  • JSON 본문 → @RequestBody DTO
  • 폼 데이터(query string, form-data) → @ModelAttribute

스프링이 반복적이고 저수준의 작업을 모두 처리해주기 때문에, 우리는 비즈니스 로직에만 집중하기에 스프링은 정말 좋은 프레임워크이다.

 

감사합니다.

'스프링' 카테고리의 다른 글

[스프링] Validation에 대하여  (0) 2025.09.27
[스프링] 메시지, 국제화  (0) 2025.09.19
[스프링] 스프링 MVC - 기본기능 (2) 요청 파라미터  (0) 2025.09.03
[스프링] 스프링 MVC - 기본기능 (1) 로깅  (0) 2025.09.03
[스프링] 컬렉션 조회 최적화  (4) 2025.07.31
'스프링' 카테고리의 다른 글
  • [스프링] Validation에 대하여
  • [스프링] 메시지, 국제화
  • [스프링] 스프링 MVC - 기본기능 (2) 요청 파라미터
  • [스프링] 스프링 MVC - 기본기능 (1) 로깅
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자바
    dfs
    QueryDSL
    스프링
    스프링 데이터 JPA
    타임리프
    Java
    spring
    쿼리
    코딩 테스트
    스프링 컨테이너
    최적화
    BFS
    SOLID
    다형성
    쿼리dsl
    fetch join
    재귀
    thymeleaf
    LocalDateTime
    백준
    mvc
    예외처리
    컬렉션
    예외 처리
    객체지향
    코딩테스트
    불변객체
    SpringDataJpa
    JPA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[스프링] 스프링 MVC - 기본기능 (마지막) HTTP 요청 메시지: text와 JSON
상단으로

티스토리툴바