클라이언트에서 서버로 요청 데이터를 전달할 때는 주로 다음 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
HttpServletRequest의 request.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 |