1. Spring MVC
DispatcherServlet
프론트 컨트롤러 패턴은 중앙 집중형 컨트롤러를 제일 앞단에 두고 모든 요청을 받는다. 디스패처 서블릿이 프론트 컨트롤러 패턴으로 구현되었으며 요청에 맞는 컨트롤러를 찾아서 호출하고 응답을 받아 뷰를 만든다.
이름에서 알 수 있듯이 이것 역시 하나의 서블릿이며 스프링 부트는 자동으로 서블릿 컨테이너에 등록하면서 모든 경로("/")에 대해서 맵핑한다.
Spring MVC 처리 흐름
1) DispatcherServlet에서 컨트롤러로 HTTP 요청 위임
디스패처 서블릿이 HTTP 요청을 받는다.
요청 URL 기준으로 어떤 컨트롤러에게 작업을 위임할지 파라미터 정보, HTTP 메서드 등을 참고해서 결정한다. 이 과정을 핸들러 맵핑(HandlerMapping) 이라고 한다.
이러한 맵핑을 결정하는 방법 중 가장 많이 쓰이는 것이 어노테이션 기반의 컨트롤러에서 사용되는 RequestMappingHandlerMapping
이다. 스프링 빈 중에서 @RequestMapping
또는 @Controller
가 클래스 레벨에 붙어 있는 경우 맵핑 정보로 인식되어 이에 의해 해당 URL이 어떤 메서드를 호출하는지 결정되게 된다.
요청을 처리할 핸들러가 결정되었다면 핸들러가 실행할 수 있는 핸들러 어댑터를 조회한다. 실제 컨트롤러를 호출하는 것은 핸들러 어댑터(HandlerAdapter) 를 통해서 수행하게 된다.
디스패처 서블릿이 요청을 핸들러 어댑터에 전달하면 어댑터가 적절히 변환하여 컨트롤러가 받을 수 있는 메서드 파라미터로 변환해서 핸들러를 실행하게 된다.
2) DispatcherServlet의 뷰 호출과 모델 참조
뷰 리졸버는 핸들러 어댑터가 반환한 정보를 가지고 어떠한 뷰를 반환할지 결정한다.
획득한 논리 뷰 이름을 가지고 디스패처 서블릿에 등록된 뷰 리졸버를 통해 매칭되는 뷰를 찾는다. 스프링 부트는 여러 뷰 리졸버를 자동 등록하였으며 순서대로 이를 호출하여 뷰를 찾는다.
디스패처 서블릿은 반환된 뷰를 렌더링하여 클라이언트에게 실제 응답을 반환하게 된다.
3) 정리
- HTTP 요청: 디스패처 서블릿이 HTTP 요청을 받는다.
- 핸들러 조회: 핸들러 맵핑을 통해서 URL에 맵핑된 핸들러를 조회한다.
- 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어탭터를 조회한다.
- 핸들러 어탭터 실행: 디스패처 서블릿이 핸들러 어댑터를 실행한다.
- 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
- ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를
ModelAndView
로 변환해서 반환한다. - 뷰 리졸버 호출: 뷰 리졸버를 찾고 실행한다.
- 뷰 반환: 뷰리 졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고 렌더링 역할을 담당하는 뷰 객체를 반환한다.
- 뷰 렌더링: 뷰를 통해서 뷰를 렌더링 한다.
2. 실습
스프링 프레임워크의 @EnableWebMvc
를 사용하게 되면 스프링 MVC에 필요한 빈들이 자동으로 등록된다.
@Configuration
@EnableWebMvc
public class WebConfig {
}
또한 WebMvcConfigurer
인터페이스를 구현하여 MVC 구성 정보를 설정할 수 있다.
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
}
예를 들어 configureViewResolvers()
를 오버라이딩하면 JSP 뷰 파일들의 경로를 설정해주거나, 타임리프와 같은 템플릿 엔진을 사용하기 위한 뷰 리졸버를 등록할 수 있다. 또는, addFormatters()
를 사용하여 컨버터를 등록하고 우리가 원하는 타입으로의 변환을 수행할 수 있다.
컨트롤러에는 다음과 같이 URL 호출 시 실행할 메서드를 작성한다. URL 맵핑을 위한 @RequestMapping
을 추가하면 RequestMappingHandlerMapping
은 이를 맵핑 정보로 인식한다. 디스패처 서블릿이 RequestMappingHandlerApapter
를 실행하면서 핸들러 정보를 넘겨 받고 해당 핸들러를 실행하고 그 결과를 ModelAndView
로 반환하게 된다.
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public ModelAndView hello() {
return new ModelAndView("hello");
}
좀 더 간단하게 하면 Model
을 파라미터로 받고 반환 값을 뷰의 논리 이름으로 할 수 있다.
@GetMapping("/hello")
public String hello(Model model) {
return "hello";
}
정적 리소스 처리하기
스프링인 정적 컨텐츠를 제공하기 위한 리소스 핸들러를 제공한다. WebMvcConfigurer
의 addResourceHandlers()
를 이용하여 이를 쉽게 추가할 수 있다.
다음은 /resources/
로 시작하는 경로로 요청이 주어졌을 때 리소스 핸들러가 작동하고 /reseources
아래 디렉터리에서 리소스 파일을 찾게 된다.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources");
}
타임리프
타임리프는 자바 템플릿 엔진으로 템플릿을 파싱하여 화면을 렌더링해주는 역할을 한다. 성능상으로는 조금 느리지만 순수 HTML을 유지하여 높은 가독성과 막강한 표현식을 가진다.
순수 스프링에서 타임리프를 사용하기 위해서는 WebMvcCongiurer
의 configureViewResolvers()
를 통해 뷰 리졸버를 등록해줘야 한다.
타임리프는 다양한 표현식을 제공한다.
- 변수 표현식:
${...}
- 선택 변수 표현식:
*{...}
- 메시지 표현식:
#{...}
- 링크 URL 표현식:
@{...}
- 조각 표현식:
~{...}
학습 내용 출처
'공부방' 카테고리의 다른 글
[TIL] 스프링 시큐리티 Quick Start (0) | 2023.08.05 |
---|---|
[TIL 07/05] Spring MVC, REST API (0) | 2023.07.07 |
[TIL 07/03] 웹, 서블릿 (0) | 2023.07.05 |
[TIL 06/30] 스프링 AOP, 스프링 트랜잭션 (0) | 2023.07.04 |
[TIL 06/29] NamedParameterJdbcTemplate, Transaction (0) | 2023.06.30 |