Springboot项目快速实现过滤器功能
作者:凡夫贩夫 发布时间:2023-08-11 18:30:02
前言
很多时候,当你以为掌握了事实真相的时间,如果你能再深入一点,你可能会发现另外一些真相。比如面向切面编程的最佳编程实践是AOP,AOP的主要作用就是可以定义切入点,并在切入点纵向织入一些额外的统一操作,避免与业务代码过度耦合。熟悉java web项目的都知道,另外还有过滤器(filter)、 * (interceptor)也有类似AOP的功能特性,那么问题来了:为什么一般说面向切面编程就是指AOP,而不是过滤器和 * ?过滤器和 * 在Spring boot中怎么实现?这三者之间有什么区别?Springboot项目快速实现Aop功能中分享了AOP的相关实现,下面将再用两到三篇文章,分别和大家分享一下过滤器、 * 的实现,以及AOP、过滤器、 * 之间的横向对比,以便在业务开发中,能够快速、正确选对具体实现方法。
环境配置
jdk版本:1.8
开发工具:Intellij iDEA 2020.1
springboot:2.3.9.RELEASE
Filter简介
Filter, 中文意思是过滤器,Filter的全限定类名是javax.servlet.Filter,可以看出这是与servelt相关的一个接口;SpringMVC核心是DispatcherServlet,而DispatcherServlet又继承了Servlet,进而可以推测出Filter与SpringMVC也是关联关系。
事实上这样的推测也是正确的,在SpringMVC项目中,filter在浏览器与服务器之间起过滤的作用,可以截取客户端和服务端之间的请求和响应信息,并根据这些请求-响应信息作一些其他的操作,但是要注意,filter并不能改变请求-响应信息;
核心类
Filter
Filter接口的全限定类名是javax.servlet.Filter,该接口有三个方法,分别是
1、init(...):用于初始化Filter;
2、doFilter(...):过滤请求和拦截响应信息的具体实现在这个方法里;
3、destroy(...):Filter对象被销毁时触发,主要用于做一些收尾工作,如资源的释放等;
FilterConfig
FilterConfig接口的全限定类名是javax.servlet.FilterConfig,该接口主要有四个方法,分别是:
1、getFilterName() 获取Filter的名字;
2、getServletContext() 获取ServletContext对象(即application);
3、getInitParameter() 获取Filter的初始化参数;
4、getInitParameterNames() 获取所有初始化参数的名字;
FilterChain
FilterChainr接口的全限定类名是javax.servlet.FilterChain,该接口只有一个方法,是doFilter()方法,用于调用Filter链上的下一个过滤器,如果当前过滤器为最后一个或只有一个过滤器,则该过滤器则将请求发送到目标资源。
MyFilter2是自己实现的过滤器,实现了Filter接口;Filter接口依赖FilterChain接口和FilterConfig接口,其中FilterChain接口的实现类是org.apache.catalina.core.ApplicationFilterChain,FilterConfig接口的实现类是org.apache.catalina.core.ApplicationFilterConfig;
工作原理
1、项目启动的时候,先执行Filter的构造方法,完成相关Filter对象的注册;
2、紧接着,Filter对象的init()方法被调用,开始对Filter做一些初始化操作;
3、项目启动完成后,客户端每次向服务端发起请求时,如果请求地址与过滤器定义的地址匹配,则会执行Filter的doFilter();如果匹配上多个过滤器,则会形成一个链路,依次调用各个过滤器对象的doFilter();服务端作出响应后,也会再次执行到各个过滤器对象的doFilter();请求和响应时,过滤器链的执行顺序是先进后出;
4、服务器停止时调用Filter的destroy()方法,用来释放资源。
实现方式
Springboot项目中一般有两种方式:
1、@WebFilter注解,即javax.servlet.annotation.WebFilter;
2、FilterRegistrationBean,即org.springframework.boot.web.servlet.FilterRegistrationBean;
两种方式,都需要在启动类上增加注解@ServletComponentScan,用于开启servlet相关bean的扫描,其中包含有过滤器(Filter);
@SpringBootApplication
@ServletComponentScan
public class FanfuApplication {
public static void main(String[] args) {
SpringApplication.run(FanfuApplication.class, args);
}
}
代码实现
1、WebFilter注解里,定义一下过滤器的名字,以及要对哪些请求进行过滤,“/*”表示对所有的请求都过滤,在实际业务中,可具体对待;如果在初始化的时候,需要携带一些初始化的参数,可以在initParams属性上,使用@WebInitParam注解来定义初始化参数名称和具体的值,这些参数可以在filter对象初始化的时候获取到;MyFIlter1和MyFIlter2使用的注解方式定义的过滤器;
@Slf4j
@WebFilter(filterName = "myFilter1", urlPatterns = "/*", initParams = {@WebInitParam(name = "creator", value = "fanfu")})
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("//myFilter1初始化开始");
String creator = filterConfig.getInitParameter("creator");
log.info("//初始化参数creator:{}",creator);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("//myFilter1开始执行");
chain.doFilter(request, response);
log.info("//myFilter1结束执行");
}
@Override
public void destroy() {
log.info("//myfilter1被销毁");
}
}
@Slf4j
@WebFilter(filterName = "myFilter2", urlPatterns = "/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("//myFilter2初始化开始");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("//myFilter2开始执行");
chain.doFilter(request, response);
log.info("//myFilter2结束执行");
}
@Override
public void destroy() {
log.info("//myFilter2被销毁");
}
}
2、FilterRegistrationBean方式
在Springboot项目的配置类中,使用FilterRegistrationBean来包装自定义的过滤器,这种方式的最大好处就是可以自定义过滤器的执行顺序,数字越小,执行时的优先级就越高;MyFIlter3和MyFIlter4是使用FilterRegistrationBean方式定义的过滤器;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean filterRegistration1() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter3());
filterRegistrationBean.addUrlPatterns("/*");//定义过滤器对哪些请求路径进行过滤,/*表示对所有请求都过滤
filterRegistrationBean.setOrder(2);//定义过滤器的执行优先级,数据越小优先级越高
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistration2() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter4());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}
@Slf4j
public class MyFilter3 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("//MyFilter3初始化开始");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("//MyFilter3开始执行");
chain.doFilter(request,response);
log.info("//MyFilter3结束执行");
}
@Override
public void destroy() {
log.info("//MyFilter3被销毁");
}
}
@Slf4j
public class MyFilter4 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("//MyFilter4初始化开始");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("//MyFilter4开始执行");
chain.doFilter(request,response);
log.info("//MyFilter4结束执行");
}
@Override
public void destroy() {
log.info("//MyFilter4被销毁");
}
}
未定义myFilter3、myFilter4的执行优先级,即采取自然排序时的执行结果:在请求前myFilter3的执行时机早于myFilter4,响应后myFilter3的执行时机要晚于myFilter4;
定义myFilter4的优先级高于myFilter3时,执行结果:在请求前myFilter4的执行时机早于myFilter3,响应后的myFilter4的执行时机要晚于myFilter3;
来源:https://blog.csdn.net/fox9916/article/details/129672773
猜你喜欢
- 接收到这样一个需求,就是英文名字中firstName和lastName,其中任何一个为null,就返回Empty。刚拿到需求,这不简单,if
- 注意是maven的webapp:选择maven下一步下一步。maven下载过慢在setting中加入镜像。 我也有疑问这是什么鬼格式,但是证
- 前几篇主要集中在注册中心eureka的使用上,接下来可以创建服务提供者provider来注册到eureka。demo源码见: https:/
- 走马灯是一种常见的效果,本文讲一下如何用 PageView 在 Flutter 里实现一个走马灯, 效果如下,当前页面的高度比其它页面高,切
- 表述在一次服务更新后发现每天凌晨0点3秒服务准时挂,开始的时候认为是maven依赖中存在system.exit(3)类似这样的代码,但是我想
- 在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较
- Android 显示GIF图片实例详解gif图动画在Android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以
- 先看看效果Like This↓一、公共WiFi 公用电脑什么的在我们日常在线上工作、玩耍时,不论开电脑、登录淘宝、玩网游统统都会用到键盘输入
- 工作中有做过手机App项目,前端和android或ios程序员配合完成整个项目的开发,开发过程中与ios程序配合基本没什么问题,而andro
- 一、Monkey 是什么?Monkey 就是SDK中附带的一个工具。二、Monkey 测试的目的?:该工具用于进行压力测试。 然后开发人员结
- 1、什么是servlet异步请求Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:(1)、Servlet 接收
- 如下所示: /** * 判断某个界面是否在前台 * * @param context
- 1)首先启动hadoop2个进程,进入hadoop/sbin目录下,依次启动如下命令[root@node02 sbin]# pwd/usr/
- 最近要给一个 Winform 项目添加功能,需要一个能显示进度条的弹窗,还要求能够中止任务,所以就做了一个,在此做个记录总结。虽然用的是比较
- 更新了AS 3.1.2之后,发现新建Kotlin类,类注释依然木有,没办法只有自己动手了。方法很简单,编辑File Header就可以啦。只
- 本文实例讲述了C#获取网页源代码的方法。分享给大家供大家参考。具体如下:public string GetPageHTML(string u
- 一、@Value读取application.properties配置文件中的值application.properties配置文件fileN
- 背景后台系统需要接入 企业微信登入,满足企业员工快速登入系统流程图简单代码说明自定义一套 springsecurity 认证逻辑主要就是 根
- package cn.response;import java.awt.Color;import java.awt.Font;import
- 之前我们在使用vue进行 h5 表单录入的过程中,遇到了Android软键盘弹出,覆盖 h5页面 输入框 问题,在此进行回顾并分享给大家:系