項(xiàng)目中兑凿,我們可以有兩種方式凯力,進(jìn)行請求的過濾,一種是Filter過濾器礼华,另一種就是Spring攔截器(HandlerInterceptor)咐鹤。
它們都是起前置處理器的作用,能夠在真正的業(yè)務(wù)邏輯執(zhí)行之前進(jìn)行某些前置處理圣絮,例如權(quán)限校驗(yàn)祈惶、登錄校驗(yàn)、日志記錄等等扮匠。
Filter過濾器
過濾器在我們剛接觸web開發(fā)捧请,學(xué)習(xí)Servlet的時(shí)候,就已經(jīng)接觸到了棒搜,應(yīng)該非常的熟悉疹蛉,有點(diǎn)需要注意,過濾器能夠增強(qiáng)進(jìn)出的邏輯帮非,如下:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//請求傳遞前處理
chain.doFilter(request, response);
//請求處理后處理
}
用起來比較簡單氧吐,不做詳細(xì)贅述讹蘑,下面介紹幾個(gè)比較重要的Filter。
CharacterEncodingFilter
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
因?yàn)閣eb容器處理http請求筑舅,默認(rèn)的編碼格式是IOS8859-1座慰。CharacterEncodingFilter的作用就是設(shè)置請求體編碼格式,用于請求體參數(shù)的字節(jié)轉(zhuǎn)字符翠拣,也就是對Post請求的參數(shù)進(jìn)行解碼版仔。
需要注意的是get請求或者URL上的參數(shù)是容器進(jìn)行解碼的,需要設(shè)置容器的URL解碼的字符集误墓。
Get請求與Post請求會有不同處理的原因在于蛮粮,字符串解析是耗性能的,如果不需要使用谜慌,那么就不解析然想,也就不用消耗這部分性能。請求體通常比較大,只有在程序中需要的時(shí)候才會進(jìn)行解碼,而URL需要在傳遞給業(yè)務(wù)類之前就解碼嗜诀。
DelegatingFilterProxy
這個(gè)過濾器是用來代理自定義過濾器的,為什么需要代理妨蛹?因?yàn)閺倪^濾器的配置可以看出,過濾器是不能通過Spring依賴注入的晴竞,有時(shí)候很不方便蛙卤,通過DelegatingFilterProxy進(jìn)行代理,實(shí)際上就是通過ApplicationContext中獲取filter對象
<filter>
<filter-name>xxx</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>simpleFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>xxx</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
HandlerInterceptor
作為SpringMVC提供的攔截器噩死,HandlerInterceptor有以下三個(gè)方法:
- preHandle() - 請求處理前被調(diào)用颤难,通過返回值,判定請求是否向下傳遞甜滨。
- postHandle() - 在請求處理后乐严,數(shù)據(jù)模型產(chǎn)生后被調(diào)用。
- afterCompletion() - 請求被返回或視圖被返回后調(diào)用衣摩。
在項(xiàng)目中使用昂验,可以有兩種方式,選擇實(shí)現(xiàn)HandlerInterceptor接口或者繼承HandlerInterceptorAdapter類艾扮,配置上有下面兩種方式:
java-based方式配置
只需要繼承WebMvcConfigurerAdapter既琴,并重寫addInterceptors()方法。
@Component
public class CustomerWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SimpleHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/path1")
}
}
xml方式配置
使用的是MVC的命名空間標(biāo)簽
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<ref bean="simpleHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
Filter和HandlerInterceptor區(qū)別
相同點(diǎn)
Filter和HandlerInterceptor都可以說是過濾器泡嘴,都可以在請求真正處理之前進(jìn)行預(yù)處理操作甫恩,增強(qiáng)了實(shí)際業(yè)務(wù)處理的功能。
差異點(diǎn)
相較與Filter酌予,HandlerInterceptor能夠更加細(xì)粒度的攔截請求磺箕,從上面配置也可以看到奖慌,HandlerInterceptor能夠配置多個(gè)攔截地址,并且能夠排除也就是不過濾特殊請求松靡。
關(guān)于請求鏈的傳遞简僧,HandlerInterceptor通過布爾返回值判定是否繼續(xù)傳遞,而Filter需要主動調(diào)用傳遞雕欺,也就是說ServletRequest和ServletResponse這兩個(gè)對象在Filter傳遞時(shí)可以被替換岛马。
從而可以認(rèn)為HandlerInterceptor處理細(xì)粒度的攔截過濾,F(xiàn)ilter處理粗粒度的屠列,例如請求體中有自定義協(xié)議啦逆,需要預(yù)先解析然后替換ServletRequest或者解壓縮等等操作。