JAVA过滤器以及拦截器的基本介绍以及使用

JAVA过滤器以及拦截器的使用介绍

一 过滤器

1.1 过滤器简单介绍

JAVA过滤器能够对目标资源的请求和响应进行截取,对目标资源的请求和响应进行预处理,然后交给下一个过滤器或servlet处理。

通过过滤器进行预处理操作的主要逻辑都是在doFilter()方法中进行实现,这也是需要重点关注的方法,至于init()destroy()分别是初始化以及销毁方法。

1.2 自定义过滤器

那么,应该如何自定义过滤器呢?

  1. 实现 Filter 接口;
  2. 通过@WebFilter注解完成过滤路径设置

其实就是这么简单,如下:

/**
 * 通过实现 Filter 接口来设置一个过滤器
 * 通过 @Component 注解使之成为spring的一个Bean
 * 通过 @WebFilter(urlPatterns = {"/*"}) 设置会进入该过滤器的请求路径
 */
@Component
@WebFilter(urlPatterns = {"/common/test", "/common/test01"}) //设置会被过滤处理的路请求径
@Order(0)   //如果存在多个过滤器 设置过滤器的优先级,值越小,优先级越高,doFilter() 越早执行
public class FirstFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("我是第一个过滤器 init~");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("我是第一个过滤器 doFilter~");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        filterChain.doFilter(request, response);

    }

    @Override
    public void destroy() {
        System.out.println("我是第一个过滤器 destroy~");
    }

}

这里我还设置了第二个过滤器,代码和第一个过滤器几乎一样,除了优先级以及简单的日志输出,所以具体代码我就不重复贴出来了。

1.3 过滤器测试

这个待会儿和下面大的拦截器一起进行测试,便于观察(我就是懒图个省事)。

二 拦截器

2.1 拦截器简单介绍

JAVA里的拦截器是动态拦截Action调用的对象。它提供了一种机制,使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。

拦截器大部分是基于动态代理实现的,拦截是AOP的一种实现策略。

2.2 自定义拦截器

那么,如何自定义一个拦截器呢?

  1. 实现HandlerInterceptor接口;
  2. 实现WebMvcConfigurer配置接口,进行自定义过滤i的注册;

具体代码实现如下(基于SpringBoot2.x):
首先自然是实现HandlerInterceptor接口,然后实现相应的方法,具体作用以及介绍注释有说明:

/**
 * 通过实现 HandlerInterceptor 接口实现一个拦截器
 * 要想使得拦截器在SpringBoot生效:
 * 第一需要在实现类上添加注解 @Component
 * 第二需要在配置类注册拦截器
 */
@Component
public class FirstInterceptor implements HandlerInterceptor {

    /**
     * 该方法在处理拦截之前执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o)
            throws Exception {
        System.out.println("我是第一个拦截器 preHandle");
        //TODO 根据实际业务需求 符合要求的才返回true 不符合的返回false
        //注意: 如果请求参数是json格式,那么不能通过 request.getParameter()的方式获取
        String first = request.getParameter("first");
        if (Objects.equals(first, "111")) {
            return true;
        }
        response.setContentType("application/json,charset=utf-8");
        response.getOutputStream().write("不符合要求,不放行".getBytes(StandardCharsets.UTF_8));
        return false;
    }

    /**
     * 该方法仅在方法没有抛出异常且没有被拦截且执行成功的时候,才会进入执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("我是第一个拦截器 postHandle");
    }

    /**
     * 该方法无论方法是否抛出异常,只要没被拦截,最后都会进入执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                @Nullable Exception ex) throws Exception {
        System.out.println("我是第一个拦截器 afterCompletion");
    }

}

既然有了第一个拦截器,很显然,还会有第二个拦截器。为什么要定义多个拦截器呢?其实我的目的是为了展示多个拦截器之间的执行顺序

OK,接下来是第二个拦截器,具体代码和第一个拦截器几乎是一样的,区别就在于没有做任何拦截处理,直接放行。所以我就不重复贴出来了。

好了,拦截器定义好了还不够,还需要将其进行注册,接下来便是注册部分:

/**
 * 该配置类用于注册拦截器
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private FirstInterceptor firstInterceptor;
    @Autowired
    private SecondInterceptor secondInterceptor;

    /**
     * 拦截器注册 可注册多个 执行顺序和注册顺序一样
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //拦截器的执行顺序取决与注册顺序
        registry.addInterceptor(firstInterceptor)
                //设置会被该拦截器拦截的请求路径  /** 表示所有
                .addPathPatterns("/**");
        registry.addInterceptor(secondInterceptor)
                .addPathPatterns("/**")
                //设置该拦截器不会拦截的请求路径
                .excludePathPatterns("/common/test01");
    }

}
2.3 拦截器+过滤器测试

具体控制器层测代码如下:

@RestController
public class TestController {

    @GetMapping("/common/test")
    public void test() {
        System.out.println("我是test");
    }

    @GetMapping("/common/test01")
    public void test01() {
        System.out.println("我是test01");
    }

}

OK,让我们请求 /common/test 接口,看看会有什么效果

在这里插入图片描述
执行顺简单总结一下:

  • 可以看到,因为设置了第一个过滤器的优先级高于第二个过滤器,所以第一个过滤器优先执行。
  • 过滤器是优先于拦截器执行的。
  • 拦截器的执行顺序取决于注册顺序,也就是代码里的注册顺序。
  • 第一个拦截器并不是所有方法都是优先执行的,仅有preHandle()方法是优先执行的。

三 二者对比

  • 过滤器是基于函数回调的,而拦截器则是基于Java反射的。
  • 过滤器依赖于servlet容器,拦截器不依赖于servlet容器。
  • 过滤器几乎对所有的请求起作用,l拦截器只能对action请求起作用。
  • 拦截器可以访问Action的上下文,值栈里的对象,而过滤器不能。
  • 在Action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

一般拦截器用来做一些接口签名或者参数校验之类的,当然也可以做日志处理。功能比过滤器更加强大,也更加灵活。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值