# 实现Filter接口
过滤器 Filter 由 Servlet 提供,基于函数回调实现链式对网络请求与响应的拦截与修改。由于基于 Servlet ,其可以对web服务器管理的几乎所有资源进行拦截(JSP、图片文件、HTML 文件、CSS文件等)。
Filter 的生命周期
- init(): 初始化Filter 实例,Filter 的生命周期与 Servlet 是相同的,也就是当 Web 容器(tomcat)启动时,调用 init() 方法初始化实例,Filter只会初始化一次。需要设置初始化参数的时候,可以写到init()方法中。
- doFilter(): 业务处理,拦截要执行的请求,对请求和响应进行处理,一般需要处理的业务操作都在这个方法中实现
- destroy() : 销毁实例,关闭容器时调用 destroy() 销毁 Filter 的实例。
方式① 使用Filter接口
1、在启动类添加注解@ServletComponentScan ,让 Spring 可以扫描到。
2、通过 @WebFilter 注解,将类声明为 Bean 过滤器类。此时可以指定要拦截的url , 但是不能指定过滤器执行顺序。
@Slf4j@WebFilter(urlPatterns ="/*")publicclassMyFilterimplementsFilter{@ResourceprivateRedisTemplate redisTemplate;@Overridepublicvoidinit(FilterConfig filterConfig)throwsServletException{Filter.super.init(filterConfig);}@OverridepublicvoiddoFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throwsIOException,ServletException{HttpServletRequest request =(HttpServletRequest) servletRequest;//获取访问 ip 地址String ipAddr =getIpAddr(request);// 存入缓存10s不允许访问String key =newStringBuilder().append("bizKey").append(ipAddr).toString();if(redisTemplate.hasKey(key)){// 访问次数自增1
redisTemplate.opsForValue().increment(key,1);
log.warn("访问过快,存在强刷行为!key={}", key);}else{// 第一次访问
redisTemplate.opsForValue().set(key,1,10,TimeUnit.SECONDS);}try{
filterChain.doFilter(servletRequest, servletResponse);}catch(Exception e){
log.warn("认证失败,e:{},url:{},parameters:{}", e,request.getRequestURL(),request.getParameterMap());
servletResponse.setContentType("application/json");
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.getWriter().write(JSONUtil.toJsonStr(Result.fail("业务执行报错~")));}}@Overridepublicvoiddestroy(){Filter.super.destroy();}publicstaticStringgetIpAddr(HttpServletRequest request){String ipAddress =null;try{
ipAddress = request.getHeader("X-Forwarded-For");if(ipAddress !=null&& ipAddress.length()!=0&&!"unknown".equalsIgnoreCase(ipAddress)){// 多次反向代理后会有多个ip值,第一个ip才是真实ipif(ipAddress.indexOf(",")!=-1){
ipAddress = ipAddress.split(",")[0];}}if(ipAddress ==null|| ipAddress.length()==0||"unknown".equalsIgnoreCase(ipAddress)){
ipAddress = request.getHeader("Proxy-Client-IP");}if(ipAddress ==null|| ipAddress.length()==0||"unknown".equalsIgnoreCase(ipAddress)){
ipAddress = request.getHeader("WL-Proxy-Client-IP");}if(ipAddress ==null|| ipAddress.length()==0||"unknown".equalsIgnoreCase(ipAddress)){
ipAddress = request.getHeader("HTTP_CLIENT_IP");}if(ipAddress ==null|| ipAddress.length()==0||"unknown".equalsIgnoreCase(ipAddress)){
ipAddress = request.getRemoteAddr();}}catch(Exception e){}return ipAddress;}}
方式② 使用@Component注解
使用@Component注解后,可以使用@Order注解保证过滤器执行顺序,@Order 注解用于指定组件的执行顺序,其中值越小的组件优先执行。
@Component@Order(1)publicclassMyFilter1implementsFilter{// ...}@Component@Order(2)publicclassMyFilter2implementsFilter{// ...}
注意: 1、不使用@Order注解,则按照filter类名的字母顺序来执行
2、方式②可以保证执行顺序, 但是过滤器不能指定拦截的url , 只能默认拦截全部
方式③ Java Config 配置类
使用 @Configuration + @Bean 配置类,注解声明Bean,交由 Spring 容器管理。此方式既能拦截Url,也能指定执行顺序
Java Config 的方式可以通过 @Bean 配置顺序或 FilterRegistrationBean.setOrder() 决定 Filter 执行顺序。(在启动类配置拦截器,此时自定义过滤器不加注解,为普通类即可) 可以指定过滤器要拦截的url 和 过滤器执行顺序, 但需要代码方式实现.
publicclassMyFilter1implementsFilter{// ...}publicclassMyFilter2implementsFilter{// ...}
通过在springboot的configuration中配置不同的FilterRegistrationBean实例,来注册自定义过滤器
这里创建一个configuration类
@ConfigurationpublicclassDemoConfiguration{@BeanpublicFilterRegistrationBeanRegistTest1(){//通过FilterRegistrationBean实例设置优先级可以生效//通过@WebFilter无效FilterRegistrationBean bean =newFilterRegistrationBean();
bean.setFilter(newTest1Filter());//注册自定义过滤器
bean.setName("flilter1");//过滤器名称
bean.addUrlPatterns("/*");//过滤所有路径
bean.setOrder(1);//优先级,最顶级return bean;}@BeanpublicFilterRegistrationBeanRegistTest2(){//通过FilterRegistrationBean实例设置优先级可以生效//通过@WebFilter无效FilterRegistrationBean bean =newFilterRegistrationBean();
bean.setFilter(newTest2Filter());//注册自定义过滤器
bean.setName("flilter2");//过滤器名称
bean.addUrlPatterns("/test/*");//过滤所有路径
bean.setOrder(6);//优先级,越低越优先return bean;}}
版权归原作者 Hi Bug 所有, 如有侵权,请联系我们删除。