Spring

[Spring] MVC 13편 - HTTP 요청 데이터 처리와 바인딩

dev-nadan 2025. 8. 14. 15:35

 

이번 편에서는 스프링 MVC가 HTTP 요청에서 데이터를 읽어오는 다양한 방법을 정리한다.

단순히 URL과 매핑하는 것에서 나아가, 헤더·쿼리 파라미터·폼 데이터·JSON을 어떻게 받아올 수 있는지, 그리고 이를 객체로 바인딩하는 방법까지 다룬다.


1. HTTP 요청과 헤더 조회

RequestHeaderController 예시

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping("/headers")
    public String headers(HttpServletRequest request,
                          HttpServletResponse response,
                          HttpMethod httpMethod,
                          Locale locale,
                          @RequestHeader MultiValueMap<String, String> headerMap,
                          @RequestHeader("host") String host,
                          @CookieValue(value = "myCookie", required = false) String cookie) {

        log.info("request={}", request);
        log.info("httpMethod={}", httpMethod);
        log.info("locale={}", locale);
        log.info("headerMap={}", headerMap);
        log.info("host={}", host);
        log.info("myCookie={}", cookie);
        return "ok";
    }
}

 

주요 파라미터 설명

  • HttpServletRequest / HttpServletResponse
  • 서블릿 API 직접 접근
  • HttpMethod
  • 요청 메서드(GET, POST, PUT…)
  • Locale
  • 요청 언어/지역 정보
  • @RequestHeader
    • MultiValueMap: 같은 키로 여러 값 가능 (ex. Cookie)
    • @RequestHeader("host"): 특정 헤더만 조회
  • HTTP 헤더 조회.
  • @CookieValue
  • 쿠키 값 조회. required=false면 없어도 예외 발생 안 함

실무 팁

  • 헤더 전체를 보고 싶으면 MultiValueMap<String, String>
  • 특정 헤더만 확인하면 @RequestHeader("키")
  • 다국어 처리를 고려한다면 Locale 활용

2. 요청 파라미터 (Query Parameter / HTML Form)

GET 쿼리 파라미터 예시

http://localhost:8080/request-param?username=hello&age=20

POST HTML Form 예시

<form action="/request-param-v1" method="post">
    username: <input type="text" name="username" />
    age: <input type="text" name="age" />
    <button type="submit">전송</button>
</form>

 

Content-Type: application/x-www-form-urlencoded


3. @RequestParam 사용

기본 사용

@ResponseBody
@RequestMapping("/request-param-v2")
public String requestParamV2(@RequestParam("username") String memberName,
                             @RequestParam("age") int memberAge) {
    log.info("username={}, age={}", memberName, memberAge);
    return "ok";
}
  • 파라미터 이름과 변수명이 다를 경우 (name="...") 지정
  • @ResponseBody: 뷰를 거치지 않고 HTTP Body에 직접 출력

변수명과 동일할 때 생략

@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(@RequestParam String username,
                             @RequestParam int age) { ... }

단순 타입이면 @RequestParam 생략

@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) { ... }

4. 필수 여부와 기본값

필수 여부 설정

@ResponseBody
@RequestMapping("/request-param-required")
public String requestParamRequired(@RequestParam(required = true) String username,
                                   @RequestParam(required = false) Integer age) {
    ...
}
  • required=true (기본값): 값이 없으면 400 예외
  • 빈 문자열 ""은 예외 아님
  • int → null 불가, Integer 사용

기본값 적용

@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(@RequestParam(defaultValue = "guest") String username,
                                   @RequestParam(defaultValue = "-1") int age) {
    ...
}
  • 값이 없거나 빈 문자열일 경우 기본값 사용

5. Map으로 파라미터 받기

@ResponseBody
@RequestMapping("/request-param-map")
public String requestParamMap(@RequestParam Map<String, Object> paramMap) {
    log.info("username={}, age={}", paramMap.get("username"), paramMap.get("age"));
    return "ok";
}
  • Map: 파라미터당 하나의 값
  • MultiValueMap: 파라미터당 여러 값 가능

6. @ModelAttribute - 객체 바인딩

예시 클래스

@Data
public class HelloData {
    private String username;
    private int age;
}

사용 방법

@ResponseBody
@RequestMapping("/model-attribute-v1")
public String modelAttributeV1(@ModelAttribute HelloData helloData) {
    log.info("username={}, age={}", helloData.getUsername(), helloData.getAge());
    return "ok";
}

동작 원리

  1. 객체 생성 (HelloData)
  2. 요청 파라미터 이름과 같은 프로퍼티 찾기
  3. Setter 호출하여 값 주입

생략 가능

@ResponseBody
@RequestMapping("/model-attribute-v2")
public String modelAttributeV2(HelloData helloData) { ... }

 

  • 단순 타입(String, int 등)은 @RequestParam으로 처리
  • 나머지는 @ModelAttribute로 처리

회고

이번 장을 정리하면서, 예전에는 요청 데이터를 받을 때 HttpServletRequest로 직접 꺼내 쓰는 게 전부라고 생각했지만, 스프링이 제공하는 어노테이션을 쓰면 코드가 훨씬 간결하고 가독성이 높아진다는 걸 다시 실감했다.

특히 @ModelAttribute로 객체 바인딩을 하면 setter 호출까지 자동으로 처리되기 때문에, 필드를 추가하거나 이름을 바꿔도 코드 변경이 최소화된다.

앞으로는 단순 파라미터는 @RequestParam, 복합 객체는 @ModelAttribute, JSON은 @RequestBody로 딱 구분해서 쓰는 습관을 유지해야겠다.