最近在开发项目时遇到将springmvc无法处理的静态资源请求转发给tomcat默认的servlet进行处理的场景,然后根据DispatcherServlet请求的路径,找到了如何配置默认Servlet处理器。
一、配置方式
具体需要看您是否使用了springmvc提供的方式完成的注入配置:
- 使用了@EnableWebMvc注解
- 使用了SpringBoot中的自动装配(org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.EnableWebMvcConfiguration)
这两种方式都是间接的使用了DelegatingWebMvcConfiguration完成了springmvc的配置
针对这种情况可以写一个WebMvcConfigurer接口的实现来完成配置:
@Component
public class WebMvcConfigurerImpl extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("default");
}
}
如果您是直接继承WebMvcConfigurationSupport类完成的springmvc配置,可以重写父类的方法来完成配置:
@Configuration
public class WebMvcConfigurationImpl extends WebMvcConfigurationSupport {
@Override
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("default");
}
}
其中default是tomcat默认的Servlet的名称。
二、原理
要了解此配置的实现机制需要看WebMvcConfigurationSupport中的定义:
/**
* Return a handler mapping ordered at Integer.MAX_VALUE with a mapped
* default servlet handler. To configure "default" Servlet handling,
* override {@link #configureDefaultServletHandling}.
*/
@Bean
public HandlerMapping defaultServletHandlerMapping() {
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
configureDefaultServletHandling(configurer);
HandlerMapping handlerMapping = configurer.buildHandlerMapping();
return (handlerMapping != null ? handlerMapping : new EmptyHandlerMapping());
}
/**
* Override this method to configure "default" Servlet handling.
* @see DefaultServletHandlerConfigurer
*/
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
类中定义了defaultServletHandlerMapping方法,方法中创建了DefaultServletHandlerConfigurer对象,使用此对象的buildHandlerMapping方法用于构建一个HandlerMapping对象。
DefaultServletHandlerConfigurer中定义了enable方法,enable方法用于创建DefaultServletHttpRequestHandler对象,并设置DefaultServletHttpRequestHandler对象的默认Servlet名称和Servlet上下文;而buildHandlerMapping方法则用于创建一个SimpleUrlHandlerMapping对象用于处理其余HandlerMapping不能处理的所有请求,使用的处理器正是enable方法中创建的DefaultServletHttpRequestHandler对象。public class DefaultServletHandlerConfigurer { private final ServletContext servletContext; private DefaultServletHttpRequestHandler handler; /** * Create a {@link DefaultServletHandlerConfigurer} instance. * @param servletContext the ServletContext to use. */ public DefaultServletHandlerConfigurer(ServletContext servletContext) { Assert.notNull(servletContext, "ServletContext is required"); this.servletContext = servletContext; } /** * Enable forwarding to the "default" Servlet. * <p>When this method is used the {@link DefaultServletHttpRequestHandler} * will try to autodetect the "default" Servlet name. Alternatively, you can * specify the name of the default Servlet via {@link #enable(String)}. * @see DefaultServletHttpRequestHandler */ public void enable() { enable(null); } /** * Enable forwarding to the "default" Servlet identified by the given name. * <p>This is useful when the default Servlet cannot be autodetected, * for example when it has been manually configured. * @see DefaultServletHttpRequestHandler */ public void enable(String defaultServletName) { this.handler = new DefaultServletHttpRequestHandler(); this.handler.setDefaultServletName(defaultServletName); this.handler.setServletContext(this.servletContext); } /** * Return a handler mapping instance ordered at {@link Integer#MAX_VALUE} containing the * {@link DefaultServletHttpRequestHandler} instance mapped to {@code "/**"}; * or {@code null} if default servlet handling was not been enabled. * @since 4.3.12 */ protected SimpleUrlHandlerMapping buildHandlerMapping() { if (this.handler == null) { return null; } SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); handlerMapping.setUrlMap(Collections.singletonMap("/**", this.handler)); handlerMapping.setOrder(Integer.MAX_VALUE); return handlerMapping; } /** * @deprecated as of 4.3.12, in favor of {@link #buildHandlerMapping()} */ @Deprecated protected AbstractHandlerMapping getHandlerMapping() { return buildHandlerMapping(); } }
@Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName); if (rd == null) { throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" + this.defaultServletName + "'"); } rd.forward(request, response); }
DefaultServletHttpRequestHandler对象中处理请求使用了请求转发。