RequestMapping
RequestMapping
RequestMapping에 대해 자세히 알아보자.
이전에 설명했던 것처럼 사용자는 웹페이지를 통해 어떤 요청을 해올 것이다.
그렇다면 우리는 그에 대해 어떻게 반응했는가하면, DispatcherServlet에서 핸들러가 있는지 조회하고 있다면
해당 핸들러를 다룰 핸들러어댑터를 찾아 진행했다.
우리는 흔히 RequestMappingHandlerMapping과 RequestMappingHandlerAdapter를 활용하여 @RequestMapping을 찾고 이를 처리한다고 했었다.
우리는 실제로 @RequestMapping을 사용하기 위해 @Controller 안에 @RequestMapping 애노테이션을 요청 URL과 함께 정의하고 해당 URL에 대해 어떤 동작을 실행할지에 대한 메소드를 정의하여 이를 처리한다.
그렇다면, @RequestMapping 애노테이션을 통해 핸들러로 등록한다는 걸텐데, @RequestMapping으로 어떻게 핸들러로 등록할까?
먼저, 이에 대해 자세히 알아보자.
그리고 그 이후에 간단한 예시를 통해 실제로 동작하는 과정을 살펴보자.
@RequestMapping 핸들러 등록 세부 과정
(1) RequestMappingHandlerMapping - 빈 생성
- 스프링에서 필요한 Bean을 생성하는 와중에 RequestMappingHandlerMapping Bean도 생성이 될 것이다.
- RequestMappingHandlerMapping의 추상체인 RequestMappingInfoHandlerMapping의 추상체인 AbstractHandlerMethodMapping에서의 메소드이다.
- 빈 초기화 메서드인 afterPropertiesSet을 통해 HandlerMethod를 초기화한다.
- 여기서, HandlerMethod로 초기화할만한 후보대상을 ProcessCandidateBean을 통해 찾고 등록한다.
(2) ProcessCandidateBean - Bean 후보자 찾기
- 여기서 Bean 중 클래스레벨에 @Controller로 등록되어있거나 @RequestMapping으로 등록되어있는 부분을 찾아 detectHandlerMethods를 한다.
(3) detectHandlerMethods - RequestMappingInfo 생성
- 여기서, Reflection API를 활용해 getMappingForMethod를 통해 @RequestMapping 애노테이션이 있는 메소드들에 대해 RequestMappingInfo를 생성한다.
(4) detectHandlerMethods - 핸들러 등록
- 만들어진 RequestMappingInfo를 기반으로 핸들러를 등록하는 메소드를 실행한다.
- 실제 register를 통해 등록을 진행한다.
- addMappingName을 통해 Request URL과 Handler를 매칭하여 저장하게된다.
- 실제로 nameLookup이라는 동시성을 보장하는 해시맵에 이를 저장한다.
우리는 다음과 같은 과정을 통해 핸들러를 등록하게 된다.
이제는 핸들러 조회에 대해 알아보자.
@RequestMapping 동작 과정
어떤식으로 진행되는지 간단하게 살펴보기 위해 다음 코드를 살펴보자.
@Slf4j
@Controller
public class request_mapping {
@RequestMapping("/request_mapping")
public String visit(Model model) {
model.addAttribute("name", "GilSSANG");
return "home";
}
}
위의 코드를 예로 들면 @RequestMapping을 통해 /request_mapping라는 URL과 메소드를 매칭하여 핸들러로 등록시키고 home이라는 뷰의 논리적 이름을 반환해준다.
좀 더 자세히 알아보자면, 우리가 http://localhost:8080/request_mapping이라는 URL에 접근하면 해당 접근에 대한 Request가 발생하고 DispatcherServlet에서 해당 요청에 대해 처리할 핸들러를 찾을 것이다.
해당 핸들러는 위의 처리과정과 위의 코드를 통해 핸들러로 등록되었을 것이고 RequestMappingHandlerMapping에서 다음과 같은 핸들러를 찾아준다.
있는지 확인이 되었기에 ReqeustMappingHandlerMapping에 맞는 어댑터인 RequestMappingHandlerAdapter를 꺼내오게 된다.
그리고 실제 동작을 하게 된다.
이를 통해 실제로 결과를 확인하면 다음과 같이 잘 되는 것을 확인할 수 있다.
@RequestMapping 파라미터
우리는 URL에 대한 요청으로 GET, POST 등 다양한 요청을 받을 수 있는데 이에 따라 @RequestMapping의 method로 지정할 수 있다.
- @RequestMapping(value="/request_mapping", method=RequestMethod.GET)
- @RequestMapping(value="/request_mapping", method=RequestMethod.POST)
우리는 우리가 수신하고자 하는 데이터의 타입을 지정하거나, 우리가 송신하고자 하는 데이터의 타입을 지정할 수 있다.
- @RequestMapping(value="/request_mapping", consumes="application/json")
- 우리가 수신하고자 하는 데이터의 타입을 지정한다.
- Content-Type과 consumes에 지정한 media-type이 동일해야한다.
- @RequestMapping(value="/request_mapping", produces="application/json")
- 우리가 송신하고자 하는 데이터의 타입을 지정한다.
- Accept Header와 produces에 지정한 media-type이 동일해야한다.
우리는 URL에 대한 요청으로 필수적인 파라미터 정보를 지정할 수 있다.
- @RequestMapping(value="/request_mapping", params = "mode=test")
우리는 URL에 대한 요청으로 필수적인 헤더 정보를 지정할 수 있다.
- @RequestMapping(value="/request_mapping", headers = "mode=test")
다른 애노테이션(@GetMapping, @PostMapping...)
하지만, 스프링에서는 이에 대한 애노테이션도 따로 제공한다.
- @GetMapping
- @PostMapping
- @DeleteMapping
- @PutMapping
- @PatchMapping
우리는 이 둘 중 택일하여 사용해도 되나, 후자가 조금 더 간편하므로 후자를 사용하도록 하자.