본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] @Controller의 메소드 파라미터의 종류

by 김코더 김주역 2022. 9. 11.
반응형

이번 포스팅에서는 Spring의 AnnotationMethodHandlerAdapter가 호출하는 컨트롤러 메소드의 파라미터의 종류를 알아보자.

 

1. HttpServletRequest, HttpServletResponse

- 컨트롤러와 DispatcherServlet 사이에서 핸들러 어댑터가 전달하는 인터페이스다.

- HttpServletRequest는 클라이언트 요청, 쿠키, 세션 등이 해당하는 HTTP 요청 정보를 제공하는 인터페이스다.

- HttpServletResponse는 content-type, 응답 코드, 응답 메시지 등이 해당하는 HTTP 응답 정보를 제공하는 인터페이스다.

 

 

2. HttpSession

- HttpServletRequest를 통해 가져올 수도 있다.

- 서버에 따라서 멀티스레드 환경에서 안전성이 보장되지 않는다. 서버에 상관없이 HttpSession을 안전하게 사용하려면 핸들러 어댑터의 synchronizeOnSession 속성을 true로 설정해야 한다.

 

 

3. WebRequest과 NativeWebRequest

- 서블릿과 포틀릿 환경 양쪽에 모두 적용 가능한 핸들러 인터셉터를 만들기 위해 만들어진 타입이다.

- HttpServletRequest의 요청정보를 대부분 가지고 있다.

- Servlet API에 종속적이지 않다.

- NativeWebRequest에는 WebRequest 내부에 감춰진 HttpServletRequest와 같은 환경종속적인 오브젝트를 가져올 수 있는 메소드가 추가되어 있다.

 

 

4. @PathVariable

- @PathVariable은 경로의 특정 부분에 변수를 적용할 때 쓰는 어노테이션이다.

- @RequestMapping.value에서 경로를 적용할 변수를 중괄호로 묶으면 된다.

@RequestMapping("user/view/{userId}")
public String method(@PathVariable("userId") int userId, Model model){
    model.addAttribute("userId", userId);
    return "user/view";
}

 

- 경로 변수의 이름과 메소드 파라미터의 이름이 일치한다면 @PathVariable의 속성을 생략할 수도 있다.

@PathVariable int userId

 

- 타입 변환이 불가능한 값이 들어오면 기본적으로 400 - Bad Request 응답 코드가 전달된다. 이 예외를 처리하고 싶다면 org.springframework.beans.TypeMismatchException 예외를 처리해주면 된다.

 

 

5. @RequestParam

- 단일 HTTP 요청 파라미터를 가져오는 어노테이션이다.

- 가져올 요청 파라미터의 이름을 @RequestParam의 기본 파라미터(value) 값으로 지정해주면 된다.

@RequestMapping("...")
public String method(@RequestParam("id") int id, @RequestParam("pw") String pw, 
    @RequestParam("file") MultipartFile file, Model model) {...}

요청 파라미터의 이름과 메소드 파라미터의 이름이 일치한다면 @RequestParam.value 속성을 생략할 수 있다.

@RequestParam String pw

 

- @RequestParam에 파라미터 이름을 지정하지 않고 Map<String, String> 타입으로 선언해서 모든 요청 파라미터를 받아올 수도 있다. 파라미터의 이름은 Map의 키에, 파라미터의 값은 Map의 값에 담긴다.

@RequestParam Map<String, String> params

 

- @RequestParam을 사용했을 때 해당 파라미터가 없다면 HTTP 400 - Bad Request 에러를 받게 된다. 특정 파라미터를 선택적으로 받게 하고 싶다면 @RequestParam.required 속성을 false로 지정하고 디폴트 값을 지정하면 된다.

@RequestParam(value="id", required=false, defaultValue="-1")

 

- String, int와 같은 단순 타입은 @RequestParam을 아예 생략할 수도 있지만 나중에 코드를 이해하는 데 불편할 수 있기 때문에 권장하는 방법은 아니다.

 

 

6. @CookieValue

- HTTP 요청으로 전달된 쿠키 값을 받을 수 있도록 하는 어노테이션이다.

- 가져올 쿠키의 이름을 @CookieValue의 기본 파라미터(value) 값으로 지정해주면 된다.

public String method(@CookieValue("auth") String auth) {...}

메소드 파라미터의 이름과 쿠키의 이름이 일치한다면 @CookieValue.value 속성을 생략할 수 있다.

@CookieValue String auth

 

- @CookieValue를 사용했을 때 해당 쿠키가 없다면 예외가 발생한다. 특정 쿠키를 선택적으로 받게 하고 싶다면 @CookieValue.required 속성을 false로 지정하고 디폴트 값을 지정하면 된다.

@CookieValue(value="auth", required=false, defaultValue="NONE") String auth

 

 

7. @RequestHeader

- 요청 헤더정보를 가져올 수 있도록 하는 어노테이션이다.

- 가져올 HTTP 헤더의 이름을 @RequestHeader의 기본 파라미터 값으로 지정해주면 된다.

public void method(@RequestHeader("Host") String host, @RequestHeader("keep-Alive") long keepAlive) {...}

 

- @RequestHeader를 사용했을 때 해당 헤더가 없다면 예외가 발생한다. 특정 헤더를 선택적으로 받게 하고 싶다면 @RequestHeader.required 속성을 false로 지정하고 디폴트 값을 지정하면 된다.

 

 

8. Map, Model, ModelMap

- 모델정보를 담는 데 사용되는 오브젝트로, 핸들러 어댑터가 미리 만들어서 제공해준다.

- Model과 ModelMap은 addAttribute() 메소드를 통해 key와 value를 넣을 수 있고, addAllAttribute() 메소드를 통해 Collection에 담긴 모든 오브젝트를 모두 모델로 추가해줄 수 있다.  

※ 자동 이름 생성 기능을 이용하여 key 없이 오브젝트만 넣을 수도 있다.

 

 

9. @ModelAttribute

- 요청 정보를 오브젝트로 받아서 컨트롤러의 로직에서 사용하고 다시 뷰로 전달하고 싶을 때 사용되는 모델 오브젝트로, 별도의 설정 없이도 오브젝트가 자동으로 모델에 저장되어 뷰에 전달된다.

 

- 요청 파라미터를 메소드 파라미터에서 1:1로 받을 때 사용되는 @RequestParam과 달리, @ModelAttribute는 도메인 오브젝트나 DTO의 프로퍼티에 요청 파라미터를 바인딩해서 한 번에 받을 때 사용된다. @RequestParam을 사용한다면 전송받을 form 데이터가 많아질수록 파라미터가 많아지는데, @ModelAttribute를 통해 하나의 오브젝트로 받는다면 이 단점을 보완할 수 있다. 이 때, 반드시 요청 파라미터의 속성 이름과 데이터 객체의 멤버 변수 이름을 일치시켜줘야 바인딩이 정상적으로 이루어진다.  

@RequestMapping(value="/user", method=RequestMethod.POST)
public String method(@ModelAttribute User user) {...}

 

- @ModelAttribute의 기본 파라미터를 이용하면 뷰에서 사용할 데이터 객체의 이름을 지정할 수 있다. 아래 예시에서는 "player"을 키 값으로해서 user 객체가 모델에 저장될 것이다. 생략 시에는 데이터 객체의 이름이 키가 된다.

@RequestMapping("...")
public String method(@ModelAttribute("player") User user) {...}

 

- 다음과 같이 @ModelAttribute 어노테이션을 생략할 수도 있지만, 권장하는 방법은 아니다.

@RequestMapping("...")
public String method(User user) {...}

※ 참고로, @RequestParam과 @ModelAttribute를 모두 생략한 경우에는, 스프링에서는 String, int와 같은 단순 타입은 @RequestParam이 생략된 것이라고 간주하고 그 외의 복잡한 오브젝트는 @ModelAttribute가 생략된 것이라고 간주한다.

 

- @ModelAttribute는 요청 파라미터에 대한 다양한 방식의 검증(Validation) 기능도 수행해주기 때문에 요청 파라미터의 타입 변환 문제가 발생하더라도 바로 HTTP 400 응답 상태 코드를 전달하지 않는다. 별도의 검증 과정 없이 타입 변환을 시도하는 @RequestParam과 대비된다. 검증에 대해서는 10, 11번에서 이어서 설명하도록 하겠다.

 

 

10. Errors, BindingResult

- org.springframwork.validation 패키지에 포함된 오브젝트로, 요청 파라미터에 대한 검증의 결과를 담고 있다.

- Errors, BindingResult 타입의 파라미터는 반드시 @ModelAttribute 파라미터의 뒤에 있어야 한다. 왜냐하면 바로 앞에 있는 @ModelAttribute 파라미터에 대한 검증 오류만을 담기 때문이다.

@RequestMapping(value="/user", method=RequestMethod.POST)
public String method(@ModelAttribute User user, BindingResult bindingResult) {...}

- Errors, BindingResult를 사용하지 않고 @ModelAttribute만 사용하는 경우에는 @ModelAttribute 파라미터에서 타입 변환 문제가 발생했을 때 BindingException 예외가 발생한다.

- 오류의 존재 여부는 Errors, BindingResult가 제공하는 hasErrors() 메소드로 확인하면 된다.

※ Errors 참고 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/Errors.html

※ BindingResult 참고 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindingResult.html

 

 

11. @Valid

- 특정 요청 파라미터를 검증하도록 지시하는 지시자다. 검증을 원하는 파라미터에 @Valid를 붙여주면 된다.

사용 예시는 아래 포스팅을 참고하면 된다.

https://kimcoder.tistory.com/239

 

[Spring] Validator로 form 데이터 검증하기

사용자가 입력한 input 데이터들을 태그로 전송하는 경우를 생각해보자. 만약 사용자가 실수로 textfield에 아무것도 입력하지 않았거나 제한 글자수를 초과했을 경우에는 사용자에게 다시 입력하

kimcoder.tistory.com

 

 

12. SessionStatus

- 현재 세션을 다룰 수 있도록 하는 오브젝트다.

- 컨트롤러에서는 모델 오브젝트를 세션에 저장했다가 다음 페이지에서 다시 활용할 수 있게 해주는 기능을 제공하는데,

세션에 더 이상 저장할 필요가 없어진 모델 오브젝트를 제거하는 책임은 컨트롤러 코드에게 있다. 그래서 SessionStatus.setComplete() 메소드를 직접 호출해서 세션을 제거해줘야 한다.

- @SessionAttributes를 사용할 때는 나중에 SessionStatus를 이용해서 세션을 정리해주는 코드가 반드시 필요하다.

 

 

 

13. @RequestBody

- HTTP 요청으로 전달된 body 부분을 받을 수 있도록 하는 어노테이션이다.

- 주로 XML이나 JSON 기반의 메시지를 사용하는 요청을 받을 때 사용된다.

 

- AnnotationMethodHandlerAdapter에는 여러 개의 HttpMessageConverter 타입의 메시지 변환기가 등록되어 있는데, @RequestBody가 붙은 파라미터를 발견하면 HTTP 요청의 미디어 타입과 메소드 파라미터의 타입을 확인한 뒤에, 처리 가능한 메시지 변환기가 있다면 그 변환기가 body를 통째로 변환해서 지정된 메소드 파라미터로 전달해준다. 예를 들어, 아래 예시에서는 StringHttpMessageConverter가 동작해서 body가 통째로 String으로 변환돼서 전달된다.

public String method(@RequestBody String body) {...}

참고로, XML 기반의 body는 MarshallingHttpMessageConverter가 처리하고, JSON 기반의 body는 MappingJacksonHttpMessageConverter가 처리한다.

 

- @RequestBody는 보통 @ResponseBody와 함께 사용된다.

※ @ResponseBody는 자바 객체를 body로 변환하여 클라이언트로 전송해주는 어노테이션이다. @RestController 컨트롤러를 사용하여 모든 컨트롤러 메소드가 @ResponseBody 역할을 수행하게 할 수 있다.

 

※ 참고할 만한 자료 - @RequestBody vs @RequestParam

https://ocblog.tistory.com/49

 

Spring / @RequestBody vs @RequestParam 이해하기

컨트롤러에서 데이터를 인자에 할당하는 대표적인 방법으로는 @RequestBody 와 @RequestParam 이 있다. @Controller public class UserController { @PostMapping("/receive") public String age(@RequestParam St..

ocblog.tistory.com

 

 

14. @Value

- 시스템 프로퍼티, 애플리케이션 프로퍼티 또는 bean의 프로퍼티 값 등을 읽어올 때 사용되는 어노테이션이다.

 

- @Value 어노테이션은 주로 클래스의 필드에 사용되지만, 다음과 같이 메소드 파라미터에 사용될 수도 있다. 아래 예시에서는 application.properties에 저장된 sentiment.client.id 값을 불러온다.

@RequestMapping(...)
public String method(@Value("${sentiment.client.id}") String clientId) {...}

<application.properties>

...
sentiment.client.id=c9ehssyoh7

 

※ 참고할 만한 포스팅 - @Value가 null을 가져오는 문제

https://kimcoder.tistory.com/415

 

[Spring] @Value가 null을 가져오는 문제

@Value가 property값을 받아오지 못했다면 아래 4가지 사항을 검토해보기를 바란다. 1) 프로퍼티 이름의 스펠링이 틀렸을 경우 2) 오브젝트가 스프링에서 관리되도록 하지 않은 경우 클래스 위에 @Serv

kimcoder.tistory.com

 

 

15. Locale

- DispatcherServlet의 지역정보 리졸버가 결정한 java.util.Locale 오브젝트를 받을 수 있다.

 

 

16. InputStream, Reader

- HttpServletRequest.getInputStream()을 통해서 받을 수 있는 콘텐트 스트림 또는 Reader 타입 오브젝트를 제공받을 수 있다.

 

 

17. OutputStream, Writer

- HttpServletResponse.getOutputStream()을 통해서 받을 수 있는 출력용 콘텐트 스트림 또는 Writer 타입 오브젝트를 제공받을 수 있다.

 

 

 

● 참고 자료 : 토비의 스프링 3.1 Vol.2

 

반응형

댓글