前言
本文记录一下在SpringBoot项目中是如何使用Filter过滤器
代码、测试
Filter过滤器是servlet包下面的东西,因此我们不需要再额外引包
方法一
直接实现Filter接口,并使用@Component注解标注为组件自动注入bean
package cn.huanzi.qch.springbootfilter.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; System.out.println("TestFilter,"+request.getRequestURI()); //执行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
查看日志可以发现,SpringBoot已经帮我们注入了一个filter,拦截路径是/*,拦截所有,如果我们需要进一步拦截具体的则需要我们自己在代码里控制
方法二
实现Filter接口,用@WebFilter注解,指定拦截路径以及一些参数,同时需要在启动类使用@ServletComponentScan扫描带@WebFilter、@WebServlet、@WebListener并将帮我们注入bean
package cn.huanzi.qch.springbootfilter.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; //配置拦截路径 @WebFilter(filterName = "testFilter",urlPatterns = {"/test"}) public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; System.out.println("TestFilter,"+request.getRequestURI()); //执行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
package cn.huanzi.qch.springbootfilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; //自动扫描与当前类的同包以及子包 @ServletComponentScan @SpringBootApplication public class SpringbootFilterApplication { public static void main(String[] args) { SpringApplication.run(SpringbootFilterApplication.class, args); } }
查看日志发现,以及帮我们注入了testFilter,拦截路径是/test
只指定拦截路径,不设置filterName一样可以注入
//配置拦截路径 @WebFilter({"/test"})
方法三
当然了,我们也可以既使用@Component同时也使用@WebFilter
package cn.huanzi.qch.springbootfilter.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; //配置拦截路径 @WebFilter(filterName = "testFilter",urlPatterns = {"/test"}) @Component public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; System.out.println("TestFilter,"+request.getRequestURI()); //执行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
package cn.huanzi.qch.springbootfilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; //自动扫描与当前类的同包以及子包 @ServletComponentScan @SpringBootApplication public class SpringbootFilterApplication { public static void main(String[] args) { SpringApplication.run(SpringbootFilterApplication.class, args); } }
但是做会注入两个bean,如果你的@WebFilter没有指定filterName或者指定的名称与类名相同,由于注入两个相同名称的bean,程序启动报错,叫我们修改其中一个的名字,或者启用覆盖bean
这里建议如果你硬要采用第三种方法,最好启用覆盖,因为改名将会注入两个bean,处理逻辑一样但拦截路径不一样,这并不是我们想要的,例如:
启用覆盖
#启用覆盖同名bean spring.main.allow-bean-definition-overriding=true
PS:这里额外说一点,如果我们采用第三种方法,@ServletComponentScan放在TestFilter类上@WebFilter也会被扫描到,不需要放在启动类,第二种方法如果也这样做就不行,估计是受到了@Component注解的影响
//配置拦截路径 @WebFilter(filterName = "testFilter",urlPatterns = {"/test"}) @ServletComponentScan @Component public class TestFilter implements Filter
分享大师风采
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | package org.springframework.web.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.util.ClassUtils; public class CharacterEncodingFilter extends OncePerRequestFilter{ private static final boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod( class $javax$servlet$http$HttpServletResponse, "setCharacterEncoding" , new Class[] { String. class }); // 需要设置的编码方式,为了支持可配置,Spring把编码方式设置成了一个变量 private String encoding; // 是否强制使用统一编码,也是为了支持可配置 private boolean forceEncoding; // 构造器,在这里,Spring把forceEncoding的值默认设置成了false public CharacterEncodingFilter(){ this .forceEncoding = false ; } // encoding/forceEncoding的setter方法 public void setEncoding(String encoding){ this .encoding = encoding; } public void setForceEncoding( boolean forceEncoding){ this .forceEncoding = forceEncoding; } // Spring通过GenericFilterBean抽象类,对Filter接口进行了整合, protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{ if (( this .encoding != null ) && ((( this .forceEncoding) || (request.getCharacterEncoding() == null )))) { request.setCharacterEncoding( this .encoding); if (( this .forceEncoding) && (responseSetCharacterEncodingAvailable)) { response.setCharacterEncoding( this .encoding); } } filterChain.doFilter(request, response); } } |
补充案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import java.io.IOException; import java.util.Enumeration; import javax.servlet.FilterChain; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.springframework.web.filter.CharacterEncodingFilter; /* * InvalidCharacterFilter:过滤request请求中的非法字符,防止脚本攻击 * InvalidCharacterFilter继承了Spring框架的CharacterEncodingFilter过滤器,当然,我们也可以自己实现这样一个过滤器 */ @Component public class InvalidCharacterFilter extends CharacterEncodingFilter{ // 需要过滤的非法字符 private static String[] invalidCharacter = new String[]{ "script" , "select" , "insert" , "document" , "window" , "function" , "delete" , "update" , "prompt" , "alert" , "create" , "alter" , "drop" , "iframe" , "link" , "where" , "replace" , "function" , "onabort" , "onactivate" , "onafterprint" , "onafterupdate" , "onbeforeactivate" , "onbeforecopy" , "onbeforecut" , "onbeforedeactivateonfocus" , "onkeydown" , "onkeypress" , "onkeyup" , "onload" , "expression" , "applet" , "layer" , "ilayeditfocus" , "onbeforepaste" , "onbeforeprint" , "onbeforeunload" , "onbeforeupdate" , "onblur" , "onbounce" , "oncellchange" , "oncontextmenu" , "oncontrolselect" , "oncopy" , "oncut" , "ondataavailable" , "ondatasetchanged" , "ondatasetcomplete" , "ondeactivate" , "ondrag" , "ondrop" , "onerror" , "onfilterchange" , "onfinish" , "onhelp" , "onlayoutcomplete" , "onlosecapture" , "onmouse" , "ote" , "onpropertychange" , "onreadystatechange" , "onreset" , "onresize" , "onresizeend" , "onresizestart" , "onrow" , "onscroll" , "onselect" , "onstaronsubmit" , "onunload" , "IMgsrc" , "infarction" }; protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{ String parameterName = null ; String parameterValue = null ; // 获取请求的参数 @SuppressWarnings ( "unchecked" ) Enumeration<String> allParameter = request.getParameterNames(); while (allParameter.hasMoreElements()){ parameterName = allParameter.nextElement(); parameterValue = request.getParameter(parameterName); if ( null != parameterValue){ for (String str : invalidCharacter){ if (StringUtils.containsIgnoreCase(parameterValue, str)){ request.setAttribute( "errorMessage" , "非法字符:" + str); RequestDispatcher requestDispatcher = request.getRequestDispatcher( "/error.jsp" ); requestDispatcher.forward(request, response); return ; } } } } super .doFilterInternal(request, response, filterChain); } } |
参考文献
https://blog.csdn.net/reggergdsg/article/details/52821502
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix