前言:从概念上来讲,filter是servlet规范定义的,而interceptor是spring定义的。

 

作用在什么位置?

 

一次会话,请求在进入servlet容器执行service()方法之前就会经过filter过滤(上图步骤1),在离开servlet容器相应客户端的时候也会经过过滤器(上图步骤7)。而interceptor,分两种情况,一种是对会话的拦截,需要定义类实现spring的org.springframework.web.servlet.HandlerInterceptor接口并注册到mvc的拦截队列中,其中preHandle()方法在调用Handler之前进行拦截(上图步骤3),postHandle()方法在视图渲染之前调用(上图步骤5.5),afterCompletion()方法在返回相应之前执行(上图步骤6.5);另一种是对方法的拦截,需要使用@Aspect注解,在每次调用指定方法的前、后进行拦截。

下面通过代码详述他们之间的区别:

先写一个controller方法,进行测试。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/intercepter")
public class InterceptorController {

    @GetMapping("/pre")
    public String preHandleTest(){
        System.out.println("boom!!!!导弹击中我方指挥部!!");
        return "wow";
    }
}

 

filter产生的效果

该filter拦截器对上述controller方法进行过滤


import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@Component//注入ioc容器
@WebFilter(filterName = "urlFilter",urlPatterns = "/intercepter/pre")//配置拦截路径
public class UrlFilter implements Filter {

    //filter初始化的时候调用,即web容器启动时调用
    //web容器启动时根据web.xml文件,依次加载ServletContext----》listener---》filter----》servlet
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("【安全过滤雷达已经开启】");

    }
    
    //filter执行功能,根据参数来看,可以对request,response和chain(是否放行)进行操作
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("【不明飞行物穿过大气层】");//请求进入servlet之前调用
        chain.doFilter(request,response);//请求放行,允许进入servlet,可手动禁止放行
        System.out.println("【不明飞行物已经解除警报】");//请求从servlet出来返回客户端之前调用
        System.exit(0);
    }
    
    //filter在服务器正常关闭(比如System.exit(0))等情况下会调用。
    @Override
    public void destroy() {
        System.out.println("【安全过滤雷达已经关闭】");

    }
}

启动时:

2018-07-19 12:18:51.122  INFO 10428 --- [ost-startStop-1] 
【安全过滤雷达已经开启】
2018-07-19 12:18:51.572  INFO 10428 --- [           main] 

执行结果:

【不明飞行物穿过大气层】
boom!!!!导弹击中我方指挥部!!
【不明飞行物已经解除警报】

服务器正常关闭:

2018-07-19 12:21:49.042  INFO 6812 --- [      Thread-12]
【安全过滤雷达已经关闭】

 

interceptor产生的效果

 

interceptor对请求进行拦截

现在加上interceptor,首先定义interceptor:

package com.peilian.practice.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class PreIntercepterDemo implements HandlerInterceptor {
    
    //在HandlerMapping获取handler之后,调用handler之前调用该方法,可以对request,response和handler进行操作
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("--------导弹拦截失败!!--------");
        return true;
    }
    
    //在调用handler之后,视图渲染之前调用,可以对中request,response,handler,modelAndView进行操作
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("--------司令部被摧毁-----!!!");
    }
    
    //在视图渲染之后,返回客户端之前调用,可以对request,response,handler以及handler产生的异常信息ex进行操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("---------重新开启司令部-------");
    }
}

然后对interceptor进行注册:


import com.peilian.practice.interceptor.PreIntercepterDemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


@SpringBootConfiguration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private PreIntercepterDemo preIntercepterDemo;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器并配置拦截的路径
        registry.addInterceptor(preIntercepterDemo).addPathPatterns("/intercepter/pre");
    }
}

运行结果:

【不明飞行物穿过大气层】
--------导弹拦截失败!!--------
boom!!!!导弹击中我方指挥部!!
--------司令部被摧毁-----!!!
---------重新开启司令部-------
【不明飞行物已经解除警报】

interceptor对方法进行拦截

被拦截的方法:

import org.springframework.stereotype.Component;

@Component
public class AspectDemo {

    public void attack(){
        System.out.println("》》》攻击《《《");
    }
}

拦截器定义:

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class EnhanceMonitor {
    
    //定义切点
    @Pointcut("execution(* com.peilian.*..attack(..))")
    public void pointCutMethod(){}
    
    //前置
    @Before("pointCutMethod()")
    public void magicEnhance1(){
        System.out.println("----冰霜特效----");
    }
    
    //前置
    @Before("pointCutMethod()")
    public void magicEnhance2(){
        System.out.println("----火焰特效----");
    }
    
    //后置
    @After("pointCutMethod()")
    public void afterAttack(){
        System.out.println("---攻击后僵直---");
    }
    
    /*环绕
    @Around("pointCutMethod()")
    public void buffAttack(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("----骑士光环---");
        pjp.proceed();
        System.out.println("-----骑士光环消失----");
    }*/
}

运行结果:

----冰霜特效----
----火焰特效----
》》》攻击《《《
---攻击后僵直---

环绕通知开启后,运行结果:

----骑士光环---
----冰霜特效----
----火焰特效----
》》》攻击《《《
-----骑士光环消失----
---攻击后僵直---

可见,@Around总是在@Before和@After之前运行。另外,还有其他如@AfterReturning和@AfterThrowing,读者请自行百度。

 

简单总结

过滤器和拦截器在对请求进行拦截时,一个是发生的时机不一样,filter是在servlet容器外,interceptor在servlet容器内,且可以对请求的3个关键步骤进行拦截处理。另外filter在过滤是只能对request和response进行操作,而interceptor可以对request、response、handler、modelAndView、exception进行操作。

如有异议,可至邮   zwh_mc@sina.com,欢迎指正。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐