SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

引言

关于两者的理论知识,网上有太多就补贴在本章了。该文章主要以代码的形式说明,方便新手理解。
这里也是新手学习时整理的文档,主要针对于新手的,如果有不正确的地方希望加一指正。

两者的区别

  1. Filter 是基于 函数回调的,而 Interceptor 则是基于 Java反射 和 动态代理。
  2. Filter 依赖于 Servlet 容器,而 Interceptor 它依赖于 web框架。
  3. Filter 对几乎 所有的请求 起作用,而 Interceptor 只对 Controller 对请求起作用。

执行顺序

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

对于自定义 Servlet 对请求分发流程:

  1. Filter 过滤请求处理;
  2. Servlet 处理请求;
  3. Filter 过滤响应处理。

对于自定义 Controller 的请求分发流程:

  1. Filter 过滤请求处理:
  2. Interceptor 拦截请求处理;
  3. 对应的 HandlerAdapter 处理请求;
  4. Interceptor 拦截响应处理;
  5. Interceptor 的最终处理;
  6. Filter 过滤响应处理。

代码示例

过滤器

一个 Servlet 请求可以经由多个 Filter 进行过滤,最终由 Servlet 处理并响应客户端。这里就建两个过滤器测试。

package com.blackcat.demo.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

import static org.springframework.util.ObjectUtils.isEmpty;

/**
 *  描述 :过滤器
 * @author : blackcat
 * @date : 2020/5/20 14:04
 *
 * Filter 对 用户请求 进行 预处理,接着将请求交给 Servlet 进行 处理 并 生成响应,
 *  最后 Filter 再对 服务器响应 进行 后处理。
 * Filter 是可以复用的代码片段,常用来转换 HTTP 请求、响应 和 头信息。
 * Filter 不像 Servlet,它不能产生 响应,而是只 修改 对某一资源的 请求 或者 响应。
 *
 * 过滤器就是筛选出你要的东西,比如requeset中你要的那部分
 * 一个 Servlet 请求可以经由多个 Filter 进行过滤,最终由 Servlet 处理并响应客户端。
 */
@Slf4j
@WebFilter(filterName = "firstIndexFilter",// filter名称
    displayName = "firstIndexFilter",
    urlPatterns = {"/index/*"},// 路径匹配
    initParams = @WebInitParam(
        name = "firstIndexFilterInitParam",
        value = "io.ostenant.springboot.sample.filter.FirstIndexFilter")
)
public class FirstIndexFilter implements Filter {

    /**
     *  描述 : 初始化时,会执行 init() 方法
     * @author : blackcat
     * @date  : 2020/5/20 14:16
    */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("注册新筛选器 {}", filterConfig.getFilterName());
    }

    /**
     *  描述 : 过滤请求
     * @author : blackcat
     * @date  : 2020/5/20 14:24
     * @param request 未到达 Servlet 的 HTTP 请求;
     * @param response 由 Servlet 处理并生成的 HTTP 响应;
     * @param chain 过滤器链 对象,可以按顺序注册多个 过滤器。
     * @return void
     * 每次请求路径匹配 urlPatterns 配置的路径时,就会进入 doFilter() 方法进行具体的 请求 和 响应过滤。
     * 一个 过滤器链 对象可以按顺序注册多个 过滤器。符合当前过滤器过滤条件,即请求 过滤成功 直接放行,则交由下一个 过滤器 进行处理。
     * 所有请求过滤完成以后,由 IndexHttpServlet 处理并生成 响应,然后在 过滤器链 以相反的方向对 响应 进行后置过滤处理。
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        log.info("FirstIndexFilter预过滤请求");
        // 当 HTTP 请求携带 filter1 参数时,请求会被放行;否则,直接 过滤中断,结束请求处理。
        String filter = request.getParameter("filter1");
        if (isEmpty(filter)) {
            response.getWriter().println("请设置请求参数 \"filter1\"");
            log.info("请设置请求参数 filter1"+filter);
            return;
        }
        chain.doFilter(request, response);
        log.info("FirstIndexFilter对响应进行后筛选");
    }

    @Override
    public void destroy() {
        log.info("注销过滤器 {}", getClass().getName());
    }
}
package com.blackcat.demo.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

import static org.springframework.util.ObjectUtils.isEmpty;

/**
 *  描述 :过滤器
 * @author : blackcat
 * @date : 2020/5/20 14:20
 *
 * 一个 Servlet 请求可以经由多个 Filter 进行过滤,最终由 Servlet 处理并响应客户端。
 */
@Slf4j
@WebFilter(filterName = "secondIndexFilter",// filter名称
        displayName = "secondIndexFilter",
        urlPatterns = {"/index/*"},// 路径匹配
        initParams = @WebInitParam(
                name = "secondIndexFilterInitParam",
                value = "io.ostenant.springboot.sample.filter.SecondIndexFilter")
)
public class SecondIndexFilter implements Filter {

    /**
     *  描述 : 初始化时,会执行 init() 方法
     * @author : blackcat
     * @date  : 2020/5/20 14:16
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("注册新筛选器 {}", filterConfig.getFilterName());
    }

    /**
     *  描述 : 过滤请求
     * @author : blackcat
     * @date  : 2020/5/20 14:24
     * @param request 未到达 Servlet 的 HTTP 请求;
     * @param response 由 Servlet 处理并生成的 HTTP 响应;
     * @param chain 过滤器链 对象,可以按顺序注册多个 过滤器。
     * @return void
     * 每次请求路径匹配 urlPatterns 配置的路径时,就会进入 doFilter() 方法进行具体的 请求 和 响应过滤。
     * 一个 过滤器链 对象可以按顺序注册多个 过滤器。符合当前过滤器过滤条件,即请求 过滤成功 直接放行,则交由下一个 过滤器 进行处理。
     * 所有请求过滤完成以后,由 IndexHttpServlet 处理并生成 响应,然后在 过滤器链 以相反的方向对 响应 进行后置过滤处理。
    */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        log.info("SecondIndexFilter预过滤请求");
        // 当 HTTP 请求携带 filter1 参数时,请求会被放行;否则,直接 过滤中断,结束请求处理。
        String filter = request.getParameter("filter2");
        if (isEmpty(filter)) {
            response.getWriter().println("请设置请求参数 \"filter2\"");
            return;
        }
        chain.doFilter(request, response);
        log.info("SecondIndexFilter对响应进行后筛选");
    }

    @Override
    public void destroy() {
        log.info("注销过滤器 {}", getClass().getName());
    }
}

拦截器

类似面向切面编程中的 切面通知,我们通过 动态代理对一个 service() 方法添加 通知进行功能增强。
比如说在方法执行前进行初始化处理,在方法执行后进行 后置处理。
拦截器 的思想和 AOP 类似,区别就是拦截器只能对 ControllerHTTP 请求进行拦截。

package com.blackcat.demo.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

import static org.springframework.util.ObjectUtils.isEmpty;

/**
 *  描述 :拦截器
 * @author : blackcat
 * @date : 2020/5/20 14:28
 *
 * 类似 面向切面编程 中的 切面 和 通知,我们通过 动态代理 对一个 service() 方法添加 通知 进行功能增强。比如说在方法执行前进行 初始化处理,在方法执行后进行 后置处理。
 * 拦截器 的思想和 AOP 类似,区别就是 拦截器 只能对 Controller 的 HTTP 请求进行拦截。
 *
 * 拦截器在做安全方面用的比较多,比如终止一些流程
 * 拦截器 Interceptor 只对 Handler 生效。Spring MVC 会为 Controller 中的每个 请求方法 实例化为一个 Handler对象,
 * 由 HandlerMapping 对象路由请求到具体的 Handler,然后由 HandlerAdapter 通过反射进行请求 处理 和 响应,这中间就穿插着 拦截处理。
 */
@Slf4j
public class FirstIndexInterceptor implements HandlerInterceptor {

    /**
     *  描述 : 在请求处理之前进行调用(Controller方法调用之前
     * @author : blackcat
     * @date  : 2020/5/20 14:32
     *
     * controller 接收请求、处理 request 之前执行,返回值为 boolean,
     * 返回值为 true 时接着执行 postHandle() 和 afterCompletion() 方法;
     * 如果返回 false 则 中断 执行。
    */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("进入preHandle");
        String interceptor = request.getParameter("interceptor1");
        if (isEmpty(interceptor)) {
            response.getWriter().println("请设置请求参数 \"interceptor1\"");
            return false;
        }
        return true;
    }

    /**
     *  描述 : 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * @author : blackcat
     * @date  : 2020/5/20 14:33
    */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("进入postHandle");
    }

    /**
     *  描述 : 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
     * @author : blackcat
     * @date  : 2020/5/20 14:33
    */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("进入afterCompletion");
    }
}

注册拦截器

前提: springboot启动类中 @ServletComponentScan开启扫描

package com.blackcat.demo.config;

import com.blackcat.demo.interceptor.FirstIndexInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 *  描述 :Web配置
 * @author : blackcat
 * @date : 2020/5/20 14:37
 */
@Slf4j
@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    /**
     *  描述 : 注册拦截器
     * @author : blackcat
     * @date  : 2020/5/20 14:39
     * 在 Spring Boot 中 配置拦截器,只需要实现 WebMvcConfigurer 接口,
     * 在 addInterceptors() 方法中通过 InterceptorRegistry 添加 拦截器 和 匹配路径 即可。
    */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器
        InterceptorRegistration first = registry.addInterceptor(new FirstIndexInterceptor());
        // 添加拦截请求
        first.addPathPatterns("/index/**");
        // 添加不拦截的请求
        first.excludePathPatterns("/login");

        // 简写格式
//        registry.addInterceptor(new FirstIndexInterceptor()).addPathPatterns("/index/**");
        log.info("注册拦截器");
    }
}

IndexController

package com.blackcat.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 *  描述 :控制器
 * @author : blackcat
 * @date : 2020/5/20 14:27
 */
@Slf4j
@Controller
@RequestMapping("/index")
public class IndexController {

    /**
     *  描述 :
     * @author : blackcat
     * @date  : 2020/5/22 12:57
     *
     * 测试连接:
     * http://localhost:8003/index/get?filter1=123&filter2=456&interceptor1=789
     * 少一个参数就无法返回 'ok'
    */
    @RequestMapping(value="/get")
    @ResponseBody
    public String get() {
        return "ok";
    }
}

代码结构

因为本文主要说明过滤器拦截器, ServletListener不多说,可以看注释。

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

测试

路径的拦截是根据 @WebFilter 注解 urlPatterns 进行匹配
例如: /index/* 就会拦截 index 下所有方法

启动项目

项目运行会根据 WebConfiguration 注册拦截器。测试工具 postman

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

过滤器测试

如果有多个过滤器,一个拦截器通过后,自动进入下一拦截器。必须所有过滤器全通过之后,才会执行拦截器代码。

FirstIndexFilter

测试链接:http://localhost:8003/index/get
测试结果:过滤器 filter1没有通过。后续代码不执行。

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)
SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

SecondIndexFilter

测试链接:http://localhost:8003/index/get?filter1=123
测试结果:过滤器 filter2没有通过。后续代码不执行。(原理同上)

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

拦截器测试

拦截原理同过滤器相同。
测试链接:http://localhost:8003/index/get?filter1=123&filter2=456
测试结果:拦截器 interceptor1未通过。后续代码不执行。

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

测试链接:http://localhost:8003/index/get?filter1=123&filter2=456&interceptor1=789
测试结果:拦截器 interceptor1通过。执行访问方法返回结果。

SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

示例源码

https://gitee.com/kylin_lawliet/learn-springboot/tree/master/filter-interceptor

Original: https://www.cnblogs.com/Kylin-lawliet/p/13373399.html
Author: 黑猫的黑猫黑猫
Title: SpringBoot 过滤器,拦截器初步学习整理(有示例代码)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/593617/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 根据表结构自动生成JavaBean,史上最强最专业的表结构转JavaBean的工具(第3版)

    这几天下班回家打鸡血赶进度,把第三版测试完成发布出来了! 欢迎访问TableGo官网:http://www.tablego.cn 同样对第2版的代码进行了维护和优化,对界面进行了完…

    Java 2023年6月9日
    079
  • SpringBoot自动装配初步浅理解

    Created time: May 15, 2022 6:36 PMDone: DoingLast edited time: May 25, 2022 6:13 PMTags: S…

    Java 2023年6月8日
    073
  • springboot项目Java轻松实现Excel导出

    Springboot项目Java轻松实现Excel导出 一、需求背景 要求Java后端实现一个Excel导出功能。 二、工程包引入 java;gutter:false; imple…

    Java 2023年5月29日
    057
  • 本地电脑视频播放器推荐PotPlayer、KMPlayer

    链接:https://pan.baidu.com/s/1aSfBFUtEm_XzDU2HGKDkQw _提取码:7z0d_ Original: https://www.cnblog…

    Java 2023年5月30日
    0105
  • 高端程序员上班摸鱼指南

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处。 哈喽大家好啊,我是Hydra。虽然说…

    Java 2023年6月5日
    0185
  • Mybatis中jdbcType和javaType的对应关系

    JDBC Type Java Type 2 CHAR String 3 VARCHAR String 4 LONGVARCHAR String 5 NUMERIC java.mat…

    Java 2023年5月29日
    0113
  • 一文总结高并发大数据量下MySQL开发规范【军规】

    在互联网公司中,MySQL是使用最多的数据库,那么在并发量大、数据量大的互联网业务中,如果高效的使用MySQL才能保证服务的稳定呢?根据本人多年运维管理经验的总结,梳理了一些核心的…

    Java 2023年6月16日
    088
  • CPU流水线与指令乱序执行

    青蛙见了蜈蚣,好奇地问:”蜈蚣大哥,我很好奇,你那么多条腿,走路的时候先迈哪一条啊?” 蜈蚣听后说:”青蛙老弟,我一直就这么走路,从没想过先迈哪…

    Java 2023年6月7日
    071
  • 浅谈-java GUI-基础理论

    GUI:Graphical User Interface(图形用户接口) 用图形的方式,用来显示计算机操作的界面 Java为GUI提供的API都存在java.awt和javax.S…

    Java 2023年6月15日
    081
  • 17、信号灯

    java;gutter:true; package com.syn; public class TestPc2 { public static void main(String[]…

    Java 2023年6月8日
    045
  • PoweJob高级特性-MapReduce完整示例

    由于网上搜索 PowerJob MapReduce 都是设计原理,demo也展示个空壳子,没有演示Map到Reduce结果怎么传递,对于没有MR开发经验的人来说并没有什么帮助,所以…

    Java 2023年6月6日
    074
  • 03、Swagger2和Springmvc整合详细记录(爬坑记录)

    时间 内容 备注 2018年6月18日 基本使用 spirngmvc整合swagger2 开始之前这个系列博文基本是,在项目的使用中一些模块的内容记录,但是后期逐渐优化,不单单是整…

    Java 2023年6月10日
    082
  • 2021 CCPC女生赛

    newbie,A了五题铜牌收工比赛时和队友悠哉游哉做题,想着干饭,最后幸好没滚出铜尾。贴一下比赛过的代码 队友A的,判断正反方向序列是否符合要求 /*** * @Author: _…

    Java 2023年6月5日
    082
  • SpringBoot 集成腾讯云短信服务

    开通腾讯云短信服务 注册腾讯云 个人实名认证 进入到控制台,在云产品中找到短信 默认是没有开通的,阅读服务协议后,点击开始接入 目前来说,只要实名认证过的,直接就可以开通短信服务 …

    Java 2023年5月30日
    071
  • 设计模式之装饰器模式

    装饰器模式又叫包装模式,数据结构型模式;是指在不改变现有对象结构的情况下,动态的给改对象增加一些职责(即增加其额外功能)的模式。 在星巴克咖啡店,有美式咖啡(LongBlack)、…

    Java 2023年6月5日
    085
  • Android框架式编程之JavaPoet框架

    一、JavaPoet 介绍 JavaPoet是Square推出的开源Java代码生成框架,提供Java Api生成.java源文件。这个框架功能非常有用,我们可以很方便的使用它根据…

    Java 2023年5月29日
    092
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球