Spring/Spring MVC

스프링 MVC 요청 파라미터 , 요청 메시지

taey 2024. 9. 30. 21:53

클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 3가지 방법을 사용한다.

  • GET - 쿼리 파라미터
    • /URL**?username=hello&age=20**
    • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
    • 예) 검색, 필터, 페이징 등에서 많이 사용하는 방식
  • POST - HTML Form
    • content-type : application/x-www-form-urlencoded
    • 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
    • 예) 회원 가입, 상품 주문, HTML Form 사용
  • HTTP message body에 데이터를 직접 담아서 요청
    • HTTP API에서 주로 사용, JSON, XML, TEXT
    • 데이터 형식은 주로 JSON 사용
    • POST, PUT, PATCH

요청 파라미터 - 쿼리 파라미터, HTML Form

HttpServletRequestrequest.getParameter()를 사용하면 다음 두 가지 요청 파라미터를 조회할 수 있다.

 

HTTP 요청 파라미터 - @RequestParam

@RequestParam : 파라미터 이름으로 바인딩

@ResponseBody : View 조회를 무시하고, HTTP message body에 직접 해당 내용 입력

 

@RequestParam의 name(value) 속성이 파라미터 이름으로 사용

  • @RequestParam("username") String memberName
  • → request.getParameter("username")
  • HTTP 파라미터 이름이 변수 이름과 같으면 @RequestParam(name="xx") 생략 가능
  • String, int, Integer 등의 단순 타입이면 @RequestParam도 생략 가능
    • 스프링 부트 3.2부터 자바 컴파일러에 -parameters 옵션을 넣어주어야 애노테이션에 적는 이름을 생략할 수 있다.

 

파라미터 필수 여부 - requestParamRequired

  • @RequestParam.required
    • 파라미터 필수 여부
    • 기본 값이 파라미터 필수(true)이다.
  • /request-param-required 요청
    • username이 없으므로 400 예외가 발생한다.
  • 파라미터 이름만 사용
    • /request-param-required?username=
    • 파라미터 이름만 있고, 값이 없는 경우 → 빈문자로 통과
  • 기본형(primitive)에 null 입력
    • /request-param 요청
    • @RequestParam(required = false) int age
    • null을 int에 입력하는 것은 불가능(500 예외 발생)
    • null을 받을 수 있는 Integer로 변경하거나, defaultValue 사용
    • defaultValue는 빈 문자의 경우에도 설정한 기본 값이 적용된다.

 

파라미터를 Map으로 조회하기 - requestParamMap

파라미터를 Map, MultiValueMap으로 조회할 수 있다.

  • @RequestParam Map
  • @RequestParam MultiValueMap

 


 

HTTP 요청 파라미터 - @ModelAttribute

 

@ModelAttribute

  • 파라미터 클래스 객체를 생성해준다.
  • 요청 파라미터 이름으로 객체의 프로퍼티를 찾아서, 해당 프로퍼티의 setter를 호출해서 파라미터의 값을 입력(바인딩)한다.

ModelAttribute는 생략할 수 있다.

그런데 @RequestParam도 생략할 수 있으니 혼란이 발생할 수 있다.

 

스프링은 해당 생략시 다음과 같은 규칙을 적용한다.

  • String, int, Integer 같은 단순 타입이면 @RequestParam
  • 나머지 = @ModelAttribute (argument resolver로 지정해둔 타입 제외)

 

HTTP 요청 메시지 - 단순 텍스트

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

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

 

스프링 MVC는 다음 파라미터를 지원한다.

  • InputStream(Reader): HTTP 요청 메시지 바디의 내용을 직접 조회
  • OutputStream(Writer): HTTP 응답 메시지의 바디에 직접 결과 출력
  • HttpEntity: HTTP header, body 정보를 편리하게 조회
    • 메시지 바디 정보를 직접 조회
    • 요청 파라미터를 조회하는 기능과 관계 없음 
  • HttpEntitiy는 응답에도 사용 가능
    • 메시지 바디 정보 직접 반환
    • 헤더 정보 포함 가능
    • view 조회 X

HttpEntity를 상속받은 다음 객체들도 같은 기능을 제공한다.

  • RequestEntitiy
    • HttpMethod, url 정보가 추가, 요청에서 사용
  • ResponseEntity
    • HTTP 상태 코드 설정 가능, 응답에서 사용
    • return new ResponseEntity<<String>("Hello World", responseHeaders, HttpStatus.CREATED)

 

  • @RequestBody
    • HTTP 메시지 바디 정보를 편리하게 조회할 수 있다.
    • 헤더 정보가 필요하다면 HttpEntity를 사용하거나, @RequestHeader를 사용
  • @ResponseBody
    • 응답 결과를 HTTP 메시지 바디에 직접 담아서 전달할 수 있다.
    • 이 경우에도 view를 사용하지 않는다.

 

요청 파라미터 vs HTTP 메시지 바디

  • 요청 파라미터를 조회하는 기능 : @RequestParam, @ModelAttribute
  • HTTP 메시지 바디를 직접 조회하는 기능 : @RequestBody

 


 

HTTP 요청 메시지 - JSON

 

서블릿에서 사용했던 방식과 유사

package hello.springmvc.basic.request;

import com.fasterxml.jackson.databind.ObjectMapper;
import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * {"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");
     }
}
  • HttpServletRequest를 사용해서 직접 HTTP 메시지 바디에서 데이터를 읽어와서, 문자로 변환한다.
  • 문자로 된 JSON 데이터를 Jackson 라이브러리인 objectMapper를 사용해서 자바 객체로 변환한다.

 

@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";
}
  • 문자로 된 JSON 데이터인 messageBody를 objectMapper를 통해서 자바 객체로 변환한다.

 

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

 

  • @RequestBody에 직접 만든 객체를 지정할 수 있다.

 

HttpEntity, @RequestBody를 사용하면 HTTP 메시지 컨버터가 HTTP 메시지 바디의 내용을 우리가 원하는 문자나 객체 등으로 변환해준다.

HTTP 메시지 컨버터는 문자 뿐만 아니라 JSON도 객체로 변환해준다.

 

@RequestBody는 생략 불가능

@RequestBody를 생략할 경우, @RequestParam, @ModelAttribute가 적용되어 버린다.

 

주의
HTTP 요청 시에 content-type이 application/json인지 확인해야 한다. 그래야 JSON을 처리할 수 있는 HTTP 메시지 컨버터가 실행된다.

 

  • @RequestBody 요청
    • JSON 요청 → HTTP 메시지 컨버터 →  객체
  • @ResponseBody 응답
    • 객체 → HTTP 메시지 컨버터 → JSON 응답

'Spring > Spring MVC' 카테고리의 다른 글

스프링 MVC HTTP 메시지 컨버터  (2) 2024.09.30
스프링 MVC 응답  (0) 2024.09.30
스프링 MVC 요청 - 기본, 헤더 조회  (2) 2024.09.30
스프링 MVC 요청 매핑  (1) 2024.09.30
스프링 Log  (1) 2024.09.30