【spring mvc】配置默认Servlet处理器

发布于:2024-04-25 ⋅ 阅读:(28) ⋅ 点赞:(0)

最近在开发项目时遇到将springmvc无法处理的静态资源请求转发给tomcat默认的servlet进行处理的场景,然后根据DispatcherServlet请求的路径,找到了如何配置默认Servlet处理器。

一、配置方式

具体需要看您是否使用了springmvc提供的方式完成的注入配置:

  1. 使用了@EnableWebMvc注解
  2. 使用了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对象。

  1. 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();
        }
    
    }
    
    DefaultServletHandlerConfigurer中定义了enable方法,enable方法用于创建DefaultServletHttpRequestHandler对象,并设置DefaultServletHttpRequestHandler对象的默认Servlet名称和Servlet上下文;而buildHandlerMapping方法则用于创建一个SimpleUrlHandlerMapping对象用于处理其余HandlerMapping不能处理的所有请求,使用的处理器正是enable方法中创建的DefaultServletHttpRequestHandler对象。
  2. @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对象中处理请求使用了请求转发。