@RequestMapping Method Argument
@RequestMapping Method Arguments
Controller
에서 정의된 @RequestMapping
메소드
즉, 요청을 핸들링하는 메소드는 여러가지 매개변수를 받을 수 있습니다.
다음 내용은 @RequestMapping
메소드의 매개변수에
명시할 수있는 Annotation
과 Spring에서 자동으로 매개변수에 주입가능한 타입에 대한 정리입니다.
Spring.io doc 를 참고해서 정리하였습니다.
불명확한 부분은 테스트하여 정리하였습니다.
<br/>
Request Parameter
이해하기
우선 Request Parameter를 정의는 다음과 같습니다.
- URL 에 붙은 Query String
- Submitt시에 Form Data
<br/>
Type Conversion
기본적으로 String-based
로 하는 input
에 대한 Annotation
은 타입변환을 자동적으로 지원 합니다.
ex.
@RequestParam
,@RequestHeader
,@PathVariable
,@MatrixVariable
,@CookieValue
String이 아닌 다른 타입으로 자동으로 전환되어 받을 수 있음을 의미합니다.
예를들면 http://test.com?value=1
의 요청에 @RequestParam int value
로 타입변환하여 받을 수 있습니다.
<br/>
No Annotation, No Inject
어노테이션을 명시하지 않거나, Spring이 자동으로 주입할수 없는 타입의 매개변수인 경우,
매개변수가 SimpleProperty이면, @RequestParam
으로 자동 명시됩니다.
매개변수가 SimplePerperty아니면, @ModelAttribute
로 자동 명시됩니다.
예를들어, DTO 객체로 받거나, 기본타입으로 매개변수를 받는경우에는
Annotation
없어도 스프링이 자동으로 Annotation
을 명시하여 사용하는 것입니다. (실제로 명시는 안하지만)
SimpleProperty
?simple value type: a primitive or primitive wrapper, an enum, a String or other CharSequence, a Number, a Date, a Temporal, a URI, a URL, a Locale, or a Class.
BeanUtils#isSimpleProperty
호출로 알 수 있습니다.
간단히하면, 기본타입과 기본타입의 wrapper 클래스는true
입니다.
DTO객체는false
입니다.
<br/>
@RequestParam
Request Parameter(query string, form data)
에 매핑하도록 하는 Annotation
입니다.
- DTO객체로 매핑이 안되고, 각 파라미터를 각자의 매개변수로 받아야합니다.
- 또는
Map<String, String>
,MultiValueMap<String, String>
으로 한번에 받을 수 있습니다.
다음 속성 값을 가집니다.
value
: =name
name
: 매핑될 파라미터명을 정의합니다, 없으면 매개변수명으로 파라미터를 찾아 바인딩합니다.required
: 기본값은true
이며,true
일 때 파라미터가 없으면400(Bad Request)
을 클라이언트에게 반환합니다.defaultValue
: 기본값을 지정합니다. 지정하게되면required
가 자동으로false
로 바뀝니다.
//default value 설정
@GetMapping("/")
public String endpoint(@RequestParam(value = "param", defaultValue = "abc") String param){
System.out.println(param);
return "";
}
// 쿼리 파라미터
//GET http://localhost:8080/?paramA=abc¶mB=123
@GetMapping("/")
public String endpoint(@RequestParam String paramA, @RequestParam String paramB){
return "";
}
// 쿼리 파라미터, Map으로받기
//GET http://localhost:8080/?paramA=abc¶mB=123
@GetMapping("/")
public String endpoint(@RequestParam Map<String, String> params){
return "";
}
// form 형식
// POST http://localhost:8080/ form paramA=abc, paramB=123
@PostMapping("/")
public String endpoint(@RequestParam String paramA, @RequestParam String paramB){
return "";
}
<br/>
@ModelAttribute
매개변수에 Request Parameter, Path Variable, Model, SessiaonAttributes를 매핑합니다
명시된 메소드 매개변수, 명시된 메소드의 반환값을 Model
에 자동으로 추가합니다.
@ModelAttribute
를 선언하면Model
에 자동으로 추가됩니다.Controller
의 메소드에도 명시할 수 있으며, 모든 요청에 해당 메소드의 반환값이Model
에 추가됩니다.Request Parameter
를 DTO객체에 매핑 할 수 있습니다.setter
또는, 멤버변수를 포함하는 생성자를 필요로합니다.- 없으면, 주입되지 않아 객체 멤버변수가
null
입니다.
@Valid
어노테이션을 추가하면, 유효성 검사를 실행합니다.BindingResult
를 매개변수로 바로 다음 매개변수로 받으면, 예외가 발생하지 않습니다.BindingResult
를 매개변수로 받지 않거나 다음 위치의 매개변수가 아니면,400(Bad Request)
을 반환합니다.
<br/>
@ModelAttribute
가 명시된 dto
객체는 다음과 같이 값이 주입됩니다.
@GetMapping("/{paramA}")
public String processSubmit(@ModelAttribute Dto dto) { }
private static class Dto{
String paramA;
}
Model
에 이미 추가되어있는 있는지 확인하고, 있는 경우dto
에 주입합니다.@SessionAttributes
를 통해서session
에 동일한 값이 있는지 확인하고 주입합니다.Path Variable
의 값에 매핑되는dto
프로퍼티가 있을 경우, 자동으로 주입됩니다.dto
프로퍼티가Request Parameter
와 매칭되는 생성자를 호출하여 인스턴스를 생성합니다.- 기본생성자를 호출하여 인스턴스를 생성합니다. 생성 후 파라미터와 일치한 프로퍼티의
setter
를 통해 값이 주입됩니다.
<br/>
다음 속성 값을 가집니다.
value
: = namename
: Model에 주입시 Atrribute namebinding
: 기본값true
입니다.false
일경우Request Parametet
데이터 바인딩을 하지 않습니다. 즉,setter
를 통한 주입을하지 않습니다. 생성자로는 주입 가능합니다(!)
public class MainController{
// MainController의 모든 요청에, 메소드 반환값이 `Model`에 주입된다.
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
}
@GetMapping("/")
public String processSubmit(@ModelAttribute Dto dto) {
}
<br/>
@RequestHeader
Request Header를 어노테이션을 통해 메소드 매개변수로 받을 수 있습니다.
- 각 매개변수에 각
@RequestHeader
에 매핑됩니다. - 또한,
Map<String, String>
,MultiValueMap<String, String>
,HttpHeaders
형태로 복수로 받을 수 있습니다.
다음 속성값을 가집니다.
value
: =name
name
: 매핑될Header
명을 정의합니다. 대소문자를 구분하지 않습니다. 없으면 매개변수명으로 매핑됩니다.(컨벤션 변경은 안됩니다content-type
->contentType
불가)required
: 기본값으로true
이기 때문에, 파라미터가 없으면400(Bad Request)
을 클라이언트에게 반환합니다.defaultValue
: 기본값을 지정합니다. 지정하게되면required
가 자동으로false
로 바뀝니다.
@GetMapping("/demo")
public void handle(@RequestHeader("Accept-Encoding") String encoding) {
//...
}
<br/>
@CookieValue
Cookie 값에 매핑됩니다.
다음 속성값을 가집니다.
value
: =name
name
: 매핑될Cookie
키값을 정의합니다. 없으면 매개변수명으로 매핑됩니다.required
: 기본값으로true
이기 때문에, 파라미터가 없으면400(Bad Request)
을 클라이언트에게 반환합니다.defaultValue
: 기본값을 지정합니다. 지정하게되면required
가 자동으로false
로 바뀝니다.
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}
<br/>
@RequestBody
매개변수가 요청의 body
에 바인딩되어 변환됩니다.
body
값은HttpMessageConverter
에 의해서 변환되는데, 매개변수 타입에 의해 변환됩니다.- DTO객체로 받을 수 있습니다.
- DTO에 기본생성자가 있어야 합니다. 접근지정자는 상관없습니다.
- 기본생성자가 없으면 500(Internal Server Error)을 반환합니다.
setter
를 필요로 하지 않습니다.
@Valid
어노테이션을 추가하면 유효성 검사가 이 적용됩니다.BindingResult
를 매개변수로 바로 다음 매개변수로 받으면, 예외가 발생하지 않습니다.BindingResult
를 매개변수로 받지 않으면,MethodArgumentNotValidException
예외가 발생하며,400
을 반환합니다.
다음 속성 값을 가집니다.
required
: required true이기 때문에, 없을 경우 클라이언트에게 400을 던진다.
// content-type을 어떤것으로 보내든 body를 String으로 받을 수 있다.
@PostMapping("/")
public String endpointB(@RequestBody String param){
System.out.println(param);
return "";
}
// content-type을 application/json 으로 보내 DTO 객체로 받는다.
@PostMapping("/")
public String endpointB(@RequestBody Dto param){
System.out.println(param);
return "";
}
@ToString
private static class Dto{
String param;
}
// content-type: text/plain으로 보냈지만, 매개변수가 DTO객체이기 때문에 400예외가 발생한다.
@PostMapping("/")
public String endpointB(@RequestBody Dto param){
System.out.println(param);
return "";
}
@ToString
private static class Dto{
String param;
}
//Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/plain;charset=UTF-8' not supported]
<br/>
HttpEntity<T>
body
, header
값을 가지고 있습니다.
- 제네릭 타입으로 정해진 타입으로
body
가 변환됩니다. @Valid
를 사용하여 유효성 검사를 할 수 없습니다.
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
<br/>
Custom Resolver
정의하기
Spring이 지원외에도, 자동으로 객체를 주입하도록 커스텀하게 정의할 수 있습니다.
// CustomHandlerMethodArgumentResolver
public class CustomHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(CustomDto.class); // CustomDto가 매개변수로 있는경우
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new CustomDto("A", "B"); // 해당 객체를 주입
}
}
// WebConfig, Resolver 설정
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new CustomHandlerMethodArgumentResolver());
}
}
@GetMapping("/")
public String endpointB(CustomDto customDto){
System.out.println(customDto); // == CustomDto("A", "B")
return "";
}
<br/>
etc
그밖에 Spring 으로부터 주입받을 수 있는 매개변수 타입입니다.
<br/>
HttpSession
HttpSession
은 HttpServletRequest#getSession(true)
의 반환값으로, null
이 주입 될 수 없습니다.
HttpSession
은 쓰레드세이프 하지않음을 주의해야합니다.
RequestMappingHandlerAdapter#synchronizeOnSession
를 true
로 함으로써 쓰레드세이프하게 할 수 있습니다.
<br/>
HttpMethod
요청의 HttpMethod
를 가져옵니다.
<br/>
Principal
현재 인증된(authenticated) 사용자 java.security.Principal
을 가져옵니다.
<br/>
@MatrixVariable
matrix parameter
를 받는 Annotation
입니다.
사용한 것을 보지 못해, 간단한 예제를 첨부합니다.
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
<br/>
@RequestAttribute
Request Attribute
를 명시하여 가져옵니다.
name
속성을 지정하지 않으면, 파라미터명의 Request Attribute
를 가져옵니다.
requirted
기본값이 true
입니다.
<br/>
@SessionAttributes
, SessionStatus
model attribute
에 추가된 값을 session attribute
에도 추가하는 값입니다.
Controller
클래스 단에,
@SessionAttributes
에 지정된 attribute key
값은
model attribute
추가와 동시에 session attribute
에도 추가됩니다.
sessionStatus#setComplete()
를 호출하여, attribute
를 초기화 할 수 있습니다.
@Controller
@SessionAttributes("dto") // session attribute에 자동으로 추가될 `key`값 지정.
public class SampleController {
@GetMapping("/")
public String hello(@ModelAttribute Dto dto) {
// @SessionAttributes("dto") 코드에 의해, 동시에 Session Attribute에도 추가됩니다.
}
}
@Controller
@SessionAttributes("dto")
public class SampleController {
@GetMapping("/")
public String hello(SessionStatus sessionStatus) {
// session attribute를 초기화 합니다.
sessionStatus.setComplete();
}
}
<br/>
@SessionAttribute
Session Attribute
를 명시하여 가져옵니다.
name
속성을 지정하지 않으면, 파라미터명의 Session Attribute
를 가져옵니다.
requirted
기본값이 true
입니다.
<br/>
Model
, ModelMap
, Map
Model
을 가져옵니다.
<br/>
Locale
현재 요청의 Locale
정보를 가져옵니다.
<br/>
ServletRequest
, ServletResponse
request
, response
를 가져옵니다.
HttpServletRequest
, MultipartRequest
, MultipartHttpServletRequest
도 가능합니다.
<br/>
UriComponentsBuilder
UriComponentsBuilder
가 주입됩니다.
주입된 uriComponentsBuilder.buid()
호출 시 현재 요청된 도메인주소를 확인 할 수 있습니다.