spring?boot?2.x靜態(tài)資源會(huì)被攔截器攔截的原因分析及解決
spring boot 2.x靜態(tài)資源會(huì)被攔截器攔截的原因
在spring boot 1.5.x中,resources/static目錄下的靜態(tài)資源可以直接訪問,并且訪問路徑上不用帶static,比如靜態(tài)資源放置位置如下圖所示:
那么訪問靜態(tài)資源的路徑可以是:
http://localhost:8080/views/demoindex.html
http://localhost:8080/res/js/jquery.min.js
當(dāng)有配置自定義HandlerInterceptor攔截器時(shí),請(qǐng)求以上靜態(tài)資源路徑不會(huì)被攔截。
自定義HandlerInterceptor攔截器源碼如下
package com.itopener.demo.config; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; /** * @author fuwei.deng * @date 2018年4月13日 下午3:32:26 * @version 1.0.0 */ public class LoginRequiredInterceptor extends HandlerInterceptorAdapter { private final Logger logger = LoggerFactory.getLogger(LoginRequiredInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info(request.getRequestURI()); return super.preHandle(request, response, handler); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info(request.getRequestURI()); super.afterCompletion(request, response, handler, ex); } }
配置如下
package com.itopener.demo.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /** * @author fuwei.deng * @date 2018年4月13日 下午3:32:54 * @version 1.0.0 */ @Configuration public class WebMvcConfiguration extends WebMvcConfigurerAdapter { private final Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class); @Override public void addInterceptors(InterceptorRegistry registry) { logger.info("add interceptors"); registry.addInterceptor(new LoginRequiredInterceptor()); } }
訪問靜態(tài)資源時(shí)路徑上不用加static目錄
當(dāng)spring boot版本升級(jí)為2.x時(shí),訪問靜態(tài)資源就會(huì)被HandlerInterceptor攔截
這樣對(duì)于利用HandlerInterceptor來處理訪問權(quán)限或其他相關(guān)的功能就會(huì)受影響,跟蹤源碼查看原因,是因?yàn)閟pring boot 2.x依賴的spring 5.x版本,相對(duì)于spring boot 1.5.x依賴的spring 4.3.x版本而言,針對(duì)資源的攔截器初始化時(shí)有區(qū)別
具體源碼在WebMvcConfigurationSupport中,spring 4.3.x源碼如下:
/** * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped * resource handlers. To configure resource handling, override * {@link #addResourceHandlers}. */ @Bean public HandlerMapping resourceHandlerMapping() { ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, mvcContentNegotiationManager()); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); if (handlerMapping != null) { handlerMapping.setPathMatcher(mvcPathMatcher()); handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); // 此處固定添加了一個(gè)Interceptor handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider())); handlerMapping.setCorsConfigurations(getCorsConfigurations()); } else { handlerMapping = new EmptyHandlerMapping(); } return handlerMapping; }
而spring 5.x的源碼如下:
/** * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped * resource handlers. To configure resource handling, override * {@link #addResourceHandlers}. */ @Bean public HandlerMapping resourceHandlerMapping() { Assert.state(this.applicationContext != null, "No ApplicationContext set"); Assert.state(this.servletContext != null, "No ServletContext set"); ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper()); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); if (handlerMapping != null) { handlerMapping.setPathMatcher(mvcPathMatcher()); handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); // 此處是將所有的HandlerInterceptor都添加了(包含自定義的HandlerInterceptor) handlerMapping.setInterceptors(getInterceptors()); handlerMapping.setCorsConfigurations(getCorsConfigurations()); } else { handlerMapping = new EmptyHandlerMapping(); } return handlerMapping; } /** * Provide access to the shared handler interceptors used to configure * {@link HandlerMapping} instances with. This method cannot be overridden, * use {@link #addInterceptors(InterceptorRegistry)} instead. */ protected final Object[] getInterceptors() { if (this.interceptors == null) { InterceptorRegistry registry = new InterceptorRegistry(); // 此處傳入新new的registry對(duì)象,在配置類當(dāng)中設(shè)置自定義的HandlerInterceptor后即可獲取到 addInterceptors(registry); registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider())); this.interceptors = registry.getInterceptors(); } return this.interceptors.toArray(); }
從源碼當(dāng)中可以看出,使用spring 5.x時(shí),靜態(tài)資源也會(huì)執(zhí)行自定義的攔截器,因此在配置攔截器的時(shí)候需要指定排除靜態(tài)資源的訪問路徑,即配置改為如下即可:
package com.itopener.demo.config; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author fuwei.deng * @date 2018年4月13日 下午3:32:54 * @version 1.0.0 */ @Configuration public class WebMvcConfiguration implements WebMvcConfigurer { private final Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class); @Override public void addInterceptors(InterceptorRegistry registry) { logger.info("add interceptors"); registry.addInterceptor(new LoginRequiredInterceptor()).excludePathPatterns(Arrays.asList("/views/**", "/res/**")); } }
這樣就可以和spring boot 1.5.x一樣的方式使用了。
不過從源碼當(dāng)中可以看出,每個(gè)靜態(tài)資源的請(qǐng)求都會(huì)被自定義Interceptor攔截,只是通過訪問路徑判斷后不會(huì)執(zhí)行攔截器的內(nèi)容,所以spring 5.x相對(duì)于spring 4.3.x而言,這部分處理的性能會(huì)更低一些
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot集成Shiro實(shí)現(xiàn)動(dòng)態(tài)加載權(quán)限的完整步驟
這篇文章主要給大家介紹了關(guān)于Spring Boot集成Shiro實(shí)現(xiàn)動(dòng)態(tài)加載權(quán)限的完整步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Java 獲取當(dāng)前時(shí)間及實(shí)現(xiàn)時(shí)間倒計(jì)時(shí)功能【推薦】
這篇文章主要介紹了Java 獲取當(dāng)前時(shí)間及實(shí)現(xiàn)時(shí)間倒計(jì)時(shí)功能 ,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05Springboot中@ConfigurationProperties輕松管理應(yīng)用程序的配置信息詳解
通過@ConfigurationProperties注解,可以將外部配置文件中的屬性值注入到JavaBean中,簡化了配置屬性的讀取和管理,這使得SpringBoot應(yīng)用程序中配置文件的屬性值可以映射到POJO類中,實(shí)現(xiàn)類型安全的屬性訪問,此方法避免了手動(dòng)讀取配置文件屬性的需要2024-10-10Netty分布式ByteBuf使用subPage級(jí)別內(nèi)存分配剖析
這篇文章主要為大家介紹了Netty分布式ByteBuf使用subPage級(jí)別內(nèi)存分配剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03JSON for java快速入門總結(jié)學(xué)習(xí)
這篇文章主要介紹了JSON for java入門總結(jié)學(xué)習(xí),有需要的可以了解一下。2016-11-11解決Maven項(xiàng)目中 Invalid bound statement 無效的綁定問題
這篇文章主要介紹了解決Maven項(xiàng)目中 Invalid bound statement 無效的綁定問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Java常用類庫Apache Commons工具類說明及使用實(shí)例詳解
這篇文章主要介紹了Java常用類庫Apache Commons工具類說明及使用實(shí)例詳解,需要的朋友可以參考下2020-02-02