일반
- Spring Framework는 Jackson 라이브러리를 통해 값을 매핑한다.
- Spring Framework는 HTTP Body와 URL 쿼리스트링에 들어있는 값을 받는다.
- HTTP Method, Content-Type, 파라미터 어노테이션(@RequestParam, @ModelAttribute, @RequestBody)에 따라 받는 값이 다르다.
- HTTP Body와 URL 쿼리스트링 값을 동시에 받는 상황에서 key가 중복되는 경우
- 파라미터 데이터 타입이 String이 아니라면 하나의 값만 받는데, HTTP Body 값을 우선으로 받는다.
- 파라미터 데이터 타입이 String이라면 컴마(,)로 구분하여 모든 값을 받는다.
- 파라미터 데이터 타입이 배열이나 Collection이라면 모든 값을 받는다.
- GET
application/x-www-form-urlencoded | multipart/form-data | application/json | |
@RequestParam | Query String 값만 받음 HTTP Body 값 무시 |
Query String, HTTP Body 값 중복으로 받음 | Query String 값만 받음 HTTP Body 값 무시 |
@ModelAttribute | Query String 값만 받음 HTTP Body 값 무시 |
Query String, HTTP Body 값 중복으로 받음 | Query String 값만 받음 HTTP Body 값 무시 |
@RequestBody | Query String 값 무시 HTTP Body 값만 받음 |
Query String, HTTP Body 값 전부 무시 | Query String 값 무시 HTTP Body 값만 받음 |
- GET을 제외한 Method
application/x-www-form-urlencoded | multipart/form-data | application/json | |
@RequestParam | Query String, HTTP Body 값 중복으로 받음 | Query String, HTTP Body 값 중복으로 받음 | Query String 값만 받음 HTTP Body 값 무시 |
@ModelAttribute | Query String, HTTP Body 둘 중 하나의 값만 받음 (Query String 값 우선) | Query String, HTTP Body 값 중복으로 받음 | Query String 값만 받음 HTTP Body 값 무시 |
@RequestBody | Query String 값, HTTP Body 값 전부 받음 | Query String, HTTP Body 값 전부 무시 | Query String 값 무시 HTTP Body 값만 받음 |
Annotation
- 파라미터 앞에 사용하는 어노테이션으로, 데이터 타입에 따라 구분한다.
@RequestParam
- 하나의 key에 해당하는 값을 받을 때 사용한다.
- Spring에서 정한 "간단한 타입"에 대해서 사용 가능하다.
- 구글에 검색해보면 String, int, long 등 String과 primitive 타입만 적용되는 것처럼 알려져 있으나 정확한 목록은 다음과 같다. (BeanUtils.isSimpleValueType 메소드에서 확인 가능)
- 간단한 타입 목록
- Primitive 타입 (boolean, byte, char, short, int, long, float, double)
- Primitive Wrapper 타입 (Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void)
- Enum
- CharSequence
- Number
- Date
- Temporal
- URI
- URL
- Locale
- Class
- 어노테이션 생략 가능
- 생략 시 자동으로 @RequestParam(required = false)가 붙은 것과 마찬가지로 동작한다. 실제로 없는 어노테이션이 자동으로 생성되는 건 아니고 RequestParamMethodArgumentResolver.RequestParamNamedValueInfo 클래스에서 다음과 같이 동작한다.
// 어노테이션이 없는 경우 호출하는 생성자 public RequestParamNamedValueInfo() { super("", false, ValueConstants.DEFAULT_NONE); } // 어노테이션이 있는 경우 호출하는 생성자 public RequestParamNamedValueInfo(RequestParam annotation) { super(annotation.name(), annotation.required(), annotation.defaultValue()); }
- 생략 시 자동으로 @RequestParam(required = false)가 붙은 것과 마찬가지로 동작한다. 실제로 없는 어노테이션이 자동으로 생성되는 건 아니고 RequestParamMethodArgumentResolver.RequestParamNamedValueInfo 클래스에서 다음과 같이 동작한다.
- 어노테이션을 생략하지 않는 경우 required 값을 필요에 따라 false로 바꾸거나 defaultValue를 설정해서 사용할 수 있다.
- 여러 key 값들을 Map으로 받고 map.get("key")로 값을 가져올 수도 있지만 좋은 코드는 아니기 때문에 거의 사용되지 않는다.
- 이렇게 사용하는 경우 파라미터(Map)에 선언한 제네릭은 무시되고 key와 value 전부 String으로 저장된다.
- DTO 대신 Map을 사용하면 안에 어떤 key가 들어있는지 알기 힘들다.
@ModelAttribute
- 일반적으로 여러 key 값을 객체에 받을 때(Ex. DTO) 사용한다.
- key와 객체의 필드명은 일치해야 한다.
- Setter를 통해 값을 객체에 바인딩하기 때문에 Setter를 생성해야 한다.
- Spring에서 정한 "간단한 타입" 이외의 데이터 타입에 대해서 사용 가능하다.
- 어노테이션 생략 가능
- 생략 시 자동으로 @ModelAttribute가 붙은 것과 마찬가지로 동작한다.
- ModelAttributeMethodProcessor.supportsParameter 메소드에서 확인할 수 있으며 조건은 다음과 같다.
public boolean supportsParameter(MethodParameter parameter) { return (parameter.hasParameterAnnotation(ModelAttribute.class) || (this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType()))); // 어노테이션이 있는 경우 || (어노테이션이 필수가 아니고 "간단한 타입"이 아닌 경우) }
@RequestBody
- HTTP Body를 그대로 가져오며 일반적으로 JSON 데이터를 받을 때 사용한다.
- 여러 key 값을 객체(DTO)에 받을 수 있다.
- key와 객체의 필드명은 일치해야 한다.
- Jackson에서 리플렉션을 통해 값을 바인딩하는데, 필드를 찾기 위해 Getter나 Setter 둘 중 하나는 반드시 생성해야 한다.
- status라는 필드가 있다면, getStatus()나 setStatus() 메소드 중 하나를 찾아 앞의 get과 set을 제외하고 첫 문자를 소문자로 바꿔서 필드를 찾아 값을 저장한다.
- 객체에 값을 받는 경우 HTTP Content-Type이 application/json이 아니라면 Exception이 발생한다.
- String으로 HTTP Body 문자열을 그대로 받을 수 있다.
- String으로 값을 받는 경우 HTTP Content-Type이 제한되지 않는다.
Content-Type
- REST API 요청의 Content-Type은 대부분 다음 셋 중 하나로 들어온다.
- application/x-www-form-urlencoded
- multipart/form-data
- application/json
application/x-www-form-urlencoded
- 일반적으로 @RequestParam 또는 @ModelAttribute와 함께 사용해 Controller에서 값을 받는다.
- 메소드가 GET인 경우 HTTP Body에 값을 담을 수 없기 때문에 클라이언트에서 URL 쿼리스트링에 값을 담아 요청해야 한다.
- 메소드가 GET이 아닌 경우 HTTP Body에 값을 담아서 보낼 수 있다.
- @RequestBody를 사용하면 HTTP Body 값을 받을 수 있다.
multipart/form-data
- 일반적으로 @RequestParam 또는 @ModelAttribute와 함께 사용해 Controller에서 값을 받는다.
- 모든 메소드에서 HTTP Body에 값을 담아 보낼 수 있다.
- 파일을 전송할 때 사용한다.
- Spring 설정을 통해 일정 크기가 넘어가는 파일은 메모리가 아닌 파일시스템에 임시로 저장해서 사용할 수 있다.
- @RequestBody를 사용하면 아무 값도 받을 수 없다.
application/json
- 일반적으로 @RequestBody와 함께 사용해 Controller에서 값을 받는다.
- 모든 메소드에서 HTTP Body 값을 받을 수 있다.
- REST API에서 가장 많이 사용하는 타입이다.
'Network > 2. HTTP' 카테고리의 다른 글
RESTful API 설계 (0) | 2022.02.22 |
---|