[스프링 웹 MVC 설정] 01. @EnableWebMvc와 WebMvcConfigurer
스프링에서 기본적인 전략은 DispatcherServlet.properties에서 제공해주지만,
개발자가 직접 스프링 MVC의 구성요소를 Bean으로 등록할 수 있다.
아래의 예시는 row-level에서 직접 Bean을 등록해주는 방식으로 실무에서 이렇게 사용하는 경우는 없다고 보면된다. 단지 원리를 익히자면 그런 것이다 라고 보고 넘어가면 되는 예시코드이다.
// #Controller코드
@Controller
public class HelloController {
@Autowired
HelloService helloService;
/*
* /hello/1?name=gayoung&age=25
* @param id
* @param name
* @return
* */
@GetMapping("/hello/{id}")
@ResponseBody
public String hello(@PathVariable int id, @ModelAttribute User usr)
{
// #1. 만약 uri에서 path에 변수가 하나만 날라올 때는 @PathVariable을 사용
// #2. parameter가 name=gayoung&age=25 이렇게 날라올 때 객체형식으로 받아오고 싶으면 @ModelAttribute로 한번에 받아오게끔 사용
// #3. 본문에 있는 파라미터 값을 가져오고 싶을 땐 @ResponseBody를 사용
return "Hello, " + helloService.getName();
}
}
// WebConfig.java 파일
@Configuration
@ComponentScan
public class WebConfig {
@Bean
public HandlerMapping handlerMapping(){
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
// #4. 아래 두줄처럼 setting해주는 값이 없다면 스프링의 기본 전략을 따라가게 된다.
handlerMapping.setInterceptors(); // #5. 핸들러를 처리하기 전에 모든 Servlet filter처럼 처리 전후 로직을 설정해줄 수 있음.
handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE); // #6. 핸들러가 여러개일 경우 핸들러 맵핑사이의 order를 설정
return handlerMapping;
}
@Bean
public HandlerAdapter handlerAdapter(){
RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
// #7. 아까 Controller에서 설정해주었던 것을 아래처럼 resolver를 직접 설정해줄 수 있다.
// 파라미터를 넣어서 setting을 해주어야 하지만 skip
//handlerAdapter.setArgumentResolvers(); 이런식으로 resolver를 설정해줄 수 있다.
return handlerAdapter;
}
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
그리고 이러한 설정을 좀 더 편하게 하기 위해서 사용하는 애노테이션 기반의 설정방식이 있다. @EnableWebMvc 인터페이스를 사용하기 위해 config 파일에 해당 애노테이션을 붙여준다.
이 EnableWebMvc 인터페이스는 아래의 코드처럼 DelegatingWebMvcConfiguration을 상속받고 있는데,
DelegatingWebMvcConfiguration란 WebMvcConfigurationSupport의 서브클래스로써, WebMvcConfigurer 타입의 빈들을 탐지하고, 이들에게 스프링 설정들을 커스터마이징 할 권한을 위임한다.
// #1. DelegatingWebMvcConfiguration 를 상속받는 EnableWebMvc 인터페이스
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
// #2. WebMvcConfigurationSupport를 확장한 DelegatingWebMvcConfiguration.class
//이 클래스는 WebMvcConfigurer타입의 빈들을 탐지하고, 이들에게 설정들을 커스터마이징할 권한을 위임한다.
/**
* A subclass of {@code WebMvcConfigurationSupport} that detects and delegates
* to all beans of type {@link WebMvcConfigurer} allowing them to customize the
* configuration provided by {@code WebMvcConfigurationSupport}. This is the
* class actually imported by {@link EnableWebMvc @EnableWebMvc}.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
단, EnableWebMvc인터페이스를 사용하기 위해선 WebApplication이 시작될 때, DispatcherServlet이 사용하는 context 안에 servletContext를 꼭 명시해주어야 한다. DelegatingWebMvcConfiguration 에서 ServletContext를 참조해서 빈 설정을 하기 때문.
// WebApplication.class
public class WebApplication implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setServletContext(servletContext);
// #2. servletContext를 지정을 꼭 해줘야 한다.
context.register(WebConfig.class);
context.refresh();
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
// #1. dispatcherservlet에서 사용하는 context 지정
ServletRegistration.Dynamic app = servletContext.addServlet("app", dispatcherServlet);
app.addMapping("/app/*");
}
}
다시 돌아가서 EnableWebMvc 인터페이스는 DelegatingWebMvcConfiguration를 상속받고 있으며,
DelegatingWebMvcConfiguration란 WebMvcConfigurationSupport의 서브클래스로써, WebMvcConfigurer 타입의 빈들을 탐지하고, 이들에게 스프링 설정들을 커스터마이징 할 권한을 위임한다고 했다.
이제 설정파일에서 @EnableWebMvc 애노테이션 설정과 함께 WebMvcConfigurer 를 상속받는 방식으로 설정을 간소화 해보자.
@Configuration
@ComponentScan
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/",".jsp");
}
}
너무 쉬워서 눈물이 난다. servlet context를 dispatcherServlet에 설정해주고, @EnableWebMvc와 WebMvcConfigurer를 사용해서 필요한 함수를 Override 해주면 끝이다.
스프링 부트에서는 아래와 같은 방식으로 MVC 를 설정해준다.
1. application.properties : 스프링부트의 스프링 MVC 기본 설정
2. @Configuration + implements WebMvcConfigurer : 스프링부트의 스프링 MVC 기본 설정 + 추가 설정
3. @Configuration + implements WebMvcCOnfigurer + @EnableWebMvc : 스프링부트의 스프링 MVC 기본 설정없이 직접 구현
근데 설정은 우선 여기까지만 알아보고, 다시 돌아와서 공부하자. 지금은 활용(구현) 부분 먼저 공부해야 할 것 같다.