解決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不同版本,建議統一在攔截器的配置中採用排除靜態資源的請求,既適合高版本,也不影響低版本。從而避免靜態資源訪問失敗。
以上內容為自己的理解所獲,如有誤,歡迎留言指正,謝謝!