📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻一周,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,如需交流,欢迎留言评论。👍
文章目录
- 写在前面的话
- 过滤器 Filter
- 前置概念介绍
- 如何自定义过滤器
- OncePerRequestFilter
- 如何注册过滤器
- 非SB项目实现过滤器
- SB3.x实现过滤器
- 实际过滤器示例
- 过滤器和拦截器区别
- 总结陈词
写在前面的话
- 过滤器(Filter)是一种用来过滤每个 HTTP 请求和响应的组件,它可以对请求和响应进行预处理和后处理,例如进行日志记录、安全检查、编码转换等操作。
- 过滤器 Filter 是主要是基于 Servlet API 的概念,并不是 Spring 独有的。Servlet Filter 是 Java Web 应用程序中用来对请求和响应进行预处理和后处理的组件,定义在 Servlet 规范中。Spring 基于 Servlet API 提供了对过滤器的支持,使其可以更方便地集成和配置。 只不过,Spring Boot 提供了简单的方式来配置和使用过滤器。
- 过滤器 Filter 是 JavaWeb 三大组件(Servlet,Filter,Listener)之一,关于拦截器上文刚介绍完,参考《知识点扫盲 · 拦截器 Interceptor》,接下来开始过滤器。
过滤器 Filter
前置概念介绍
1、 Servlet 中的过滤器 Filter 是实现了 javax.servlet.Filter 接口的服务器端程序,通过Filter技术可以对 WEB 服务器的文件进行拦截,从而实现一些特殊的功能。
2、 传统 SpringMVC 项目,只要你在 web.xml 文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对在传入控制器前对请求或响应(Request、Response) 做一些前置处理,它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。
3、 使用场景:登录状态判断、编码格式设置、访问权限控制、敏感字符过滤、跨域处理。
如何自定义过滤器
过滤在 SpringBoot 中的实现有两种方式,基础都是需要实现Filter。
public class CustomFilter implements Filter {@Overridepublic void init(FilterConfig config) throws ServletException {if (log.isInfoEnabled()) {log.info("CustomFilter初始化......");}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {chain.doFilter(request, response);}@Overridepublic void destroy() {if (log.isInfoEnabled()) {log.info("CustomFilter过滤器销毁......");}}
}
OncePerRequestFilter
在Spring框架中推荐使用 OncePerRequestFilter ,它是Spring框架提供的一个抽象类,用于确保过滤器只在每个请求中被调用一次。它继承自 GenericFilterBean 类,并在 doFilter 方法中添加了对请求是否已被过滤的判断逻辑。
OncePerRequestFilter 和 Filter 的根本区别在于 OncePerRequestFilter 提供了一个确保过滤器只在每个请求中被调用一次的机制,而 Filter 接口本身并没有提供这样的机制。
Tips:使用起来区别不大。
public class MyOncePerRequestFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {// 过滤器逻辑System.out.println("Filter executed once per request");// 继续过滤器链filterChain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化逻辑(可选)}@Overridepublic void destroy() {// 销毁逻辑(可选)}
}
如何注册过滤器
第一种是使用如下注解,这种方式需要启动类上搭配注解@ServletComponentScan,该注解用于注解用于扫描 @WebFilter、@WebListener 和 @WebServlet 注解。
@Component
@WebFilter(filterName = "customFilter", urlPatterns = "/*")
@Order(value = 1)
第二种是利用FilterRegistrationBean来注册,具体下面代码。
@Bean
public FilterRegistrationBean filterRegist() {FilterRegistrationBean frBean = new FilterRegistrationBean();frBean.setFilter(new CustomFilter());frBean.addUrlPatterns("/*");frBean.addInitParameter("encoding", "UTF-8");frBean.addInitParameter("baseUrl", baseUrl);frBean.setName("sessionFilter");return frBean;
}
非SB项目实现过滤器
<!--添加包装request-->
<filter><filter-name>wrapRequestFilter</filter-name><filter-class>com.zoe.optimus.core.common.web.filter.WrapParameterFilter</filter-class>
</filter>
<filter-mapping><filter-name>wrapRequestFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
SB3.x实现过滤器
1、创建过滤器类,实现 jakarta.servlet.Filter 接口,重写 doFilter 方法;
Tips:从SB3.0开始,改为jakarta.servlet.Filter,而不是java.servlet.Filter。
2、为自定义类添加过滤器注解@WebFilter
3、为启动类添加扫描@ServletComponentScan
4、启动项目后,访问任意接口,即可测试效果
实际过滤器示例
WrapParameterFilter:自定义的包装参数过滤器,解析特定格式的参数。
CorsFilter:自定义的跨域处理过滤器。
CharacterEncodingFilter:SpringMVC 字符编码过滤器。
public class CorsFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) servletResponse;response.setHeader("Access-Control-Allow-Origin", "*");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers","operator, apiKey, requestId, deptCode, langType, orgCode, clientId, clientIp, districtCode, reqToken");filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}
过滤器和拦截器区别
1、Filter 依赖于Servlet容器,属于Servlet规范的一部分,生命周期由Servlet容器管理,可拦截所有Web资源(包括JSP、Servlet、静态资源等);
2、Interceptor 依赖于SpringMVC框架,通过IOC容器来管理,可通过注入等方式来获取其Bean的实例,只能拦截Controller;
3、两者在功能上类似,前置拦截效果基本可以实现,但拦截器还支持后置操作;
总结陈词
上文介绍了过滤器的用法,仅供参考。过滤器主要针对请求前后做出处理,没有像拦截器那样出现在很多库,同时,两者的实际适用场景其实存在若干重叠。
选择使用过滤器还是拦截器,取决于具体需求和处理的阶段。过滤器更适合全局的请求和响应处理,而拦截器更适合与控制器方法紧密相关的处理。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。