攔截器(Interceptor)與過(guò)濾器(Filter)
一、用戶的普通Http請(qǐng)求執(zhí)行順序

二、過(guò)濾器、攔截器添加后的執(zhí)行順序

三、攔截器(Interceptor)的基本定義
攔截器是面向切面(AOP)編程中應(yīng)用的一種統(tǒng)一處理方案,就是在你的Controller、Servie或者一個(gè)Method調(diào)用一個(gè)Method,或者在Method調(diào)用一個(gè)Method之后,統(tǒng)一的進(jìn)行處理的方案,基于Java的反射機(jī)制。
攔截器,在AOP(Aspect-Oriented Programming)中可以用于在某個(gè)方法或者字段被訪問(wèn)之前,進(jìn)行攔截,然后在之前或者之后加入某些統(tǒng)一的處理方法。攔截是AOP的一種具象的實(shí)現(xiàn)方式。
攔截器將很多service或者Controller中共有的行為提煉出來(lái),在某些方法執(zhí)行的前后執(zhí)行,提煉為通用的處理方式,讓被攔截的方法都能享受這一共有的功能,讓代碼更加簡(jiǎn)潔,同時(shí),當(dāng)共有的功能需要發(fā)生調(diào)整、變動(dòng)的時(shí)候,不必修改很多的類或者方法,只要修改這個(gè)攔截器就可以了,可復(fù)用性很強(qiáng)。
Spring MVC 中的Interceptor攔截請(qǐng)求是通過(guò)HandlerInterceptor來(lái)實(shí)現(xiàn)的。
四、攔截器(Interceptor)必須實(shí)現(xiàn)的三個(gè)方法
1)總覽

2)preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法
該方法將在請(qǐng)求處理之前進(jìn)行調(diào)用。SpringMVC 中的Interceptor 是鏈?zhǔn)降恼{(diào)用的,在一個(gè)應(yīng)用中或者說(shuō)是在一個(gè)請(qǐng)求中可以同時(shí)存在多個(gè)Interceptor 。每個(gè)Interceptor 的調(diào)用會(huì)依據(jù)它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor 中的preHandle 方法,所以可以在這個(gè)方法中進(jìn)行一些前置初始化操作或者是對(duì)當(dāng)前請(qǐng)求的一個(gè)預(yù)處理,也可以在這個(gè)方法中進(jìn)行一些判斷來(lái)決定請(qǐng)求是否要繼續(xù)進(jìn)行下去。該方法的返回值是布爾值Boolean類型的,當(dāng)它返回為false 時(shí),表示請(qǐng)求結(jié)束,后續(xù)的Interceptor 和Controller 都不會(huì)再執(zhí)行;當(dāng)返回值為true 時(shí)就會(huì)繼續(xù)調(diào)用下一個(gè)Interceptor 的preHandle 方法,如果已經(jīng)是最后一個(gè)Interceptor 的時(shí)候就會(huì)是調(diào)用當(dāng)前請(qǐng)求的Controller 方法。
3) postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法 【前提:在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時(shí)才能被調(diào)用】
在當(dāng)前請(qǐng)求進(jìn)行處理之后,也就是Controller 方法調(diào)用之后執(zhí)行,但是它會(huì)在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用,所以我們可以在這個(gè)方法中對(duì)Controller 處理之后的ModelAndView 對(duì)象進(jìn)行操作。postHandle 方法被調(diào)用的方向跟preHandle 是相反的,也就是說(shuō)先聲明的Interceptor 的postHandle 方法反而會(huì)后執(zhí)行,這和Struts2 里面的Interceptor 的執(zhí)行過(guò)程有點(diǎn)類型。Struts2 里面的Interceptor 的執(zhí)行過(guò)程也是鏈?zhǔn)降模皇窃赟truts2 里面需要手動(dòng)調(diào)用ActionInvocation 的invoke 方法來(lái)觸發(fā)對(duì)下一個(gè)Interceptor 或者是Action 的調(diào)用,然后每一個(gè)Interceptor 中在invoke 方法調(diào)用之前的內(nèi)容都是按照聲明順序執(zhí)行的,而invoke 方法之后的內(nèi)容就是反向的。
4)afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法 【前提:在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時(shí)才能被調(diào)用】
該方法將在整個(gè)請(qǐng)求結(jié)束之后,也就是在DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行。這個(gè)方法的主要作用是用于進(jìn)行資源清理工作的?! ?/span>
五、單個(gè)攔截器(Interceptor)的Demo實(shí)現(xiàn)
1)初始化攔截器
@Component
public class UserAccessInterceptor implements HandlerInterceptor {
private final Logger logger = LoggerFactory.getLogger(UserAccessInterceptor.class);
@Resource
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//1.獲取headers里的author-Cookie
//2.根據(jù)cookie使用userService查找當(dāng)前user
//3.存在且激活 當(dāng)前用戶信息設(shè)置到ThreadLocal return true;
//4.不存在 或 未激活 return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//銷毀ThreadLocal的用戶信息
}
2)攔截器配置類
@Configuration
public class WebInterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private UserAccessInterceptor userAccessInterceptor;
//不攔截的URL集合
private static List<String> exclusionUrlList=new ArrayList<>();
static {
exclusionUrlList.add("/favicon.ico");
exclusionUrlList.add("/**/*.css");
exclusionUrlList.add("/**/*.js");
exclusionUrlList.add("/ok");
exclusionUrlList.add("/");
exclusionUrlList.add("/console/**");
exclusionUrlList.add("/index");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.userAccessInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(exclusionUrlList);
super.addInterceptors(registry);
}
}
六、攔截器(Interceptor)的兩種配置方式
1)同上 -> Demo實(shí)現(xiàn)
2)Spring MVC使用mvc:interceptors標(biāo)簽
<mvc:interceptors>
<!-- 使用bean定義一個(gè)Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請(qǐng)求 -->
<bean class="com.baidu.interceptor.UserAccessInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/parent/**"/>
<bean class="com.baidu.interceptor.UserAccessInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
七、過(guò)濾器(Filter)的基本定義
Filter可以認(rèn)為是Servlet的一種“加強(qiáng)版”,它主要用于對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理,也可以對(duì)HttpServletResponse進(jìn)行后處理,是個(gè)典型的處理鏈。Filter也可以對(duì)用戶請(qǐng)求生成響應(yīng),這一點(diǎn)與Servlet相同,但實(shí)際上很少會(huì)使用Filter向用戶請(qǐng)求生成響應(yīng)。使用Filter完整的流程是:Filter對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理,接著將請(qǐng)求交給Servlet進(jìn)行處理并生成響應(yīng),最后Filter再對(duì)服務(wù)器響應(yīng)進(jìn)行后處理。
在Web中稱之為Filter,通過(guò)配置多個(gè)過(guò)濾器,Web系統(tǒng)可以對(duì)所有的Servlet請(qǐng)求進(jìn)行一層一層的過(guò)濾,以完成一些特殊的功能。例如常用的資源訪問(wèn)權(quán)限控制、特殊字符以及敏感詞過(guò)濾、響應(yīng)信息壓縮等功能。
Servlet中的過(guò)濾器Filter是實(shí)現(xiàn)了javax.servlet.Filter接口的服務(wù)器端程序,主要的用途是設(shè)置字符集、控制權(quán)限、控制轉(zhuǎn)向、做一些業(yè)務(wù)邏輯判斷等。其工作原理是,只要你在web.xml文件配置好要攔截的客戶端請(qǐng)求,它都會(huì)幫你攔截到請(qǐng)求,此時(shí)你就可以對(duì)請(qǐng)求或響應(yīng)(Request、Response)統(tǒng)一設(shè)置編碼,簡(jiǎn)化操作;同時(shí)還可進(jìn)行邏輯判斷,如用戶是否已經(jīng)登陸、有沒(méi)有權(quán)限訪問(wèn)該頁(yè)面等等工作。它是隨你的web應(yīng)用啟動(dòng)而啟動(dòng)的,只初始化一次,以后就可以攔截相關(guān)請(qǐng)求,只有當(dāng)你的web應(yīng)用停止或重新部署的時(shí)候才銷毀。
八、過(guò)濾器(Filter)必須實(shí)現(xiàn)的三個(gè)方法
1)總覽

2)default void init(FilterConfig filterConfig) throws ServletException {}
用于完成Filter的初始化。
3)void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
實(shí)現(xiàn)過(guò)濾功能,該方法就是對(duì)每個(gè)請(qǐng)求及響應(yīng)增加的額外處理。該方法可以實(shí)現(xiàn)對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理(ServletRequest request),也可實(shí)現(xiàn)對(duì)服務(wù)器響應(yīng)進(jìn)行后處理(ServletResponse response)—它們的分界線為是否調(diào)用了chain.doFilter(),執(zhí)行該方法之前,即對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理;執(zhí)行該方法之后,即對(duì)服務(wù)器響應(yīng)進(jìn)行后處理。
4) default void destroy() {}
用于Filter銷毀前,完成某些資源的回收。
九、單個(gè)過(guò)濾器(Filter)的Demo實(shí)現(xiàn)
1)TestFilter初始化
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
System.out.println("我是Filter,執(zhí)行filterChain.doFilter(request,response)之前。");
filterChain.doFilter(request,response);
System.out.println("我是Filter,執(zhí)行filterChain.doFilter(request,response)之后。");
}
@Override
public void destroy() {
}
2)Filter配置類
@Slf4j
@Configuration
public class TestFilterConfiguration {//不攔截路徑
private static List<String> exclusionUrlList=new ArrayList<>();
//攔截路徑
private static List<String> inclusionUrlList=new ArrayList<>();
static {
exclusionUrlList.add("/favicon.ico");
exclusionUrlList.add("/**/*.css");
exclusionUrlList.add("/**/*.js");
exclusionUrlList.add("/ok");
inclusionUrlList.add("/api/**");
}
@Bean
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new TestFilter());
registration.addInitParameter(FILTER_INIT_PARAM_EXCLUSION_URLS,String.join(",", exclusionUrlList));
registration.addInitParameter(AJAX_URL_PATTERNS,String.join(",", inclusionUrlList));
registration.addUrlPatterns("/*");
registration.setName("testFilter");
return registration;
}
}
十、過(guò)濾器(Filter)的三種配置方式
1)通過(guò)@WebFilter注解配置
1.初始化Filter
@WebFilter(urlPatterns = "/test001")
@Order(1) //order值越小,過(guò)濾器越靠前,此處配置無(wú)效
public class TestFilter implements Filter {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
System.out.println("##############TestFilter init##############");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//在DispatcherServlet之前執(zhí)行
System.out.println("##############doFilter before##############");
filterChain.doFilter(servletRequest, servletResponse);
// 在視圖頁(yè)面返回給客戶端之前執(zhí)行,但是執(zhí)行順序在Interceptor之后
System.out.println("##############doFilter after##############");
}
@Override
public void destroy() {
System.out.println("##############TestFilter destroy##############");
}
}
//2.在啟動(dòng)類添加 @ServletComponentScan
@SpringBootApplication
@ServletComponentScan
public class TestbootApplication {
public static void main(String[] args) {
SpringApplication.run(TestbootApplication.class, args);
}
}
2)通過(guò)@Bean來(lái)配置
//1.初始化Filter
@Component
public class TestFilter3 implements Filter{
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
System.out.println("##############Filter3 init##############");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//在DispatcherServlet之前執(zhí)行
System.out.println("##############doFilter3 before##############");
filterChain.doFilter(servletRequest, servletResponse);
// 在視圖頁(yè)面返回給客戶端之前執(zhí)行,但是執(zhí)行順序在Interceptor之后
System.out.println("##############doFilter3 after##############");
}
@Override
public void destroy() {
System.out.println("##############Filter3 destroy##############");
}
}
//2.注冊(cè)到config
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean testFilter3RegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter3());
registration.addUrlPatterns("/hello");
registration.setOrder(1); // 值越小越靠前,此處配置有效
return registration;
}
@Bean
public FilterRegistrationBean testFilter4RegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter4());
registration.addUrlPatterns("/hello");
registration.setOrder(2);
return registration;
}
}
3)Spring MVC在web.xml進(jìn)行配置
1.初始化Filter
2.web.xml文件中配置Filter
<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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
十一、攔截器和過(guò)濾器的區(qū)別

十二、攔截器和過(guò)濾器的作用/用途
過(guò)濾器用途:用于設(shè)置字符編碼、URL級(jí)別的權(quán)限控制,敏感詞匯的過(guò)濾
攔截器用途:攔截未登錄的用戶,攔截器和過(guò)濾器的功能相近
十三、總結(jié)
1.過(guò)濾器:所謂過(guò)濾器顧名思義是用來(lái)過(guò)濾的,在java web中,你傳入的request,response提前過(guò)濾掉一些信息,或者提前設(shè)置一些參數(shù),然后再傳入servlet或者struts的action進(jìn)行業(yè)務(wù)邏輯,比如過(guò)濾掉非法url(不是login.do的地址請(qǐng)求,如果用戶沒(méi)有登陸都過(guò)濾掉),或者在傳入servlet或者struts的action前統(tǒng)一設(shè)置字符集,或者去除掉一些非法字符(聊天室經(jīng)常用到的,一些罵人的話)。filter 流程是線性的, url傳來(lái)之后,檢查之后,可保持原來(lái)的流程繼續(xù)向下執(zhí)行,被下一個(gè)filter, servlet接收等.
2.java的攔截器 主要是用在插件上,擴(kuò)展件上比如 hibernate spring struts2等 有點(diǎn)類似面向切片的技術(shù),在用之前先要在配置文件即xml文件里聲明一段的那個(gè)東西。
source:https://www.cnblogs.com/l3306/p/14779295.html
喜歡,在看
