logo

@RequestMapping Method Arguments

Controller에서 정의된 @RequestMapping 메소드
즉, 요청을 핸들링하는 메소드는 여러가지 매개변수를 받을 수 있습니다.

다음 내용은 @RequestMapping 메소드의 매개변수에
명시할 수있는 Annotation과 Spring에서 자동으로 매개변수에 주입가능한 타입에 대한 정리입니다.

Spring.io doc 를 참고해서 정리하였습니다.
불명확한 부분은 테스트하여 정리하였습니다.

<br/>

Request Parameter 이해하기

우선 Request Parameter를 정의는 다음과 같습니다.

  1. URL 에 붙은 Query String
  2. 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&paramB=123
    @GetMapping("/")
    public String endpoint(@RequestParam String paramA, @RequestParam String paramB){
        return "";
    }
    
    // 쿼리 파라미터, Map으로받기
    //GET http://localhost:8080/?paramA=abc&paramB=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;
    }
  1. Model에 이미 추가되어있는 있는지 확인하고, 있는 경우 dto에 주입합니다.
  2. @SessionAttributes를 통해서 session에 동일한 값이 있는지 확인하고 주입합니다.
  3. Path Variable의 값에 매핑되는 dto 프로퍼티가 있을 경우, 자동으로 주입됩니다.
  4. dto 프로퍼티가 Request Parameter와 매칭되는 생성자를 호출하여 인스턴스를 생성합니다.
  5. 기본생성자를 호출하여 인스턴스를 생성합니다. 생성 후 파라미터와 일치한 프로퍼티의 setter를 통해 값이 주입됩니다.

<br/>

다음 속성 값을 가집니다.

  • value : = name
  • name : Model에 주입시 Atrribute name
  • binding : 기본값 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

HttpSessionHttpServletRequest#getSession(true) 의 반환값으로, null이 주입 될 수 없습니다.
HttpSession은 쓰레드세이프 하지않음을 주의해야합니다.
RequestMappingHandlerAdapter#synchronizeOnSessiontrue로 함으로써 쓰레드세이프하게 할 수 있습니다.

<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() 호출 시 현재 요청된 도메인주소를 확인 할 수 있습니다.

CommentCount 0
이전 댓글 보기
알림받기
등록
TOP