1. 程式人生 > 實用技巧 >解決Spring MVC攔截器導致靜態資源訪問失敗(基於java註解配置)

解決Spring MVC攔截器導致靜態資源訪問失敗(基於java註解配置)

前言

對於這個問題,我們準備了以下三種解決方案:
1、靜態資源統一交由Servlet容器直接處理;
2、靜態資源統一交由Spring MVC框架間接處理,再轉交給Servlet容器處理;
3、靜態資源統一交由Spring MVC框架直接處理;

從這3種解決方案中,處理靜態資源的方式可以分為Servlet容器處理和Spring MVC框架處理。在這裡要說明的是,只要靜態資源的請求經過Spring MVC框架的大門,如果不做額外的配置,就必然會跟攔截器扯上關係。

Xml配置方式:請點選這裡

解決方案1:

靜態資源統一交由Servlet容器直接處理
參考程式碼:
使用該介面WebApplicationInitializer可以實現web.xml配置檔案的功能。

public class WebXml implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        //註冊Spring MVC配置類來建立Spring MVC容器
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        //SpringMvcConfig.class它是Spring Mvc的配置類,需要自行編寫
        ctx.register(SpringMvcConfig.class);
        ctx.setServletContext(servletContext);

        //新增default servlet對映路徑,將靜態資源的請求直接由Servlet容器處理
        ServletRegistration defaultServlt = servletContext.getServletRegistration("default");
        defaultServlt.addMapping("*.js", "*.css", "*.jpg","*.ico");

        //配置Spring MVC入口點,註冊DispatcherServlet
        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);

    }
}

結論:
加上該配置,即可解決靜態資源請求失敗的問題,此刻與Spring MVC完全沒有關係,所以配置Spring MVC攔截器時,不用考慮對靜態資源的處理。

解決方案2:

靜態資源統一交由Spring MVC框架間接處理,再轉交給Servlet容器處理

原始碼參考:


DefaultServletHttpRequestHandler處理器所在的對映器裡並沒有去獲取我們在配置類中配置的攔截器,所以我們配置的攔截器對這個處理器並不生效,那麼攔截器就可以不用特意對靜態資源的路徑進行排除操作。
程式碼參考:

@EnableWebMvc
@ComponentScan(basePackages = "com.xxx.controller")
public class SpringMvcConfig implements WebMvcConfigurer {

    //配置預設靜態資源處理器
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("default");
    }
    //配置Spring MVC攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        MyInterceptor myInterceptor = new MyInterceptor();
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }
}
   

總結:如果採用這種方式處理靜態資源,即使攔截器不排除靜態資源的請求,也不會攔截;但是請注意,如果採用Xml配置的方式,就必須要排除靜態資源的請求,這是2者不同配置的區別,具體可以檢視Xml配置的那篇文章,有詳細說明。

解決方案3:

靜態資源統一交由Spring MVC框架直接處理
請檢視截圖中原始碼的差異性:
原始碼:Spring MVC5.0.0版本

從Spring MVC5.0.0版本中可以看出,ResourceHttpRequestHandler處理器的對映器並沒有去獲取配置類中的攔截器,所以,就算攔截器不排除靜態資源的請求,也不會被攔截了。

結論:使用Spring MVC5.0.0版本或低版本開發的專案,配置攔截器的時候,即使不排除靜態資源的路徑,也不會對靜態資源進行攔截,因為攔截器根本就沒生效。

原始碼:Spring MVC5.0.1版本

從Spring MVC5.0.1版本配置資訊中可以看出ResourceHttpRequestHandler處理器的對映器獲取了所有的攔截器,包括配置類中的,如果配置攔截器不排除靜態資源的話,將會攔截靜態資源的請求。

結論:使用Spring MVC5.0.1版本或高版本開發的專案,如果攔截器不排除靜態資源的請求,將會對靜態資源進行攔截,因為靜態資源處理器對映器已獲取了配置類中的攔截器。

程式碼參考:
鑑於Spring MVC不同版本,建議採用統一在攔截器的配置中採用排除靜態資源路徑的方式,既適合高版本,也不影響低版本。

@EnableWebMvc
@ComponentScan(basePackages = "com.xxx.controller")
public class SpringMvcConfig implements WebMvcConfigurer {


    //配置靜態資源對映
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/jpg/**").addResourceLocations("/jpg/");
    }

    //配置Spring MVC攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        MyInterceptor myInterceptor = new MyInterceptor();
        registry.addInterceptor(myInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/js/**", "/css/**", "/jpg/**");
    }
}

總結:
1、如果採用第一種解決方案,攔截器不用做任何處理靜態資源的操作。因為Spring MVC的DispatcherServlet沒有匹配靜態資源的請求。
2、如果採用第二種解決方案,攔截器也不用做任何處理靜態資源的操作。因為配置類中的攔截器並沒有生效。
2、如果採用第三種解決方案,鑑於Spring MVC不同版本,建議統一在攔截器的配置中採用排除靜態資源的請求,既適合高版本,也不影響低版本。從而避免靜態資源訪問失敗。

以上內容為自己的理解所獲,如有誤,歡迎留言指正,謝謝!