FilterRegistrationBean过滤器注册(spring boot)

前言: 看一百本书不如去把一本书弄懂, 实践才能出真知. 话不多说, 上代码吧:

自定义Filter

#### FilterDemo1 ####
package com.huntkey.rx.sceo.filter;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * @description: Servlet 过滤器(功能: 对所有web资源(图片,页面等)拦截, 实现URL过滤,过滤敏感词汇、压缩响应信息等)
 *
 *             开发步骤:
 *             1. 实现servlet(不是druid)中的Filter接口, 实现doFilter方法
 *             2. 通过SpringBoot中的 FilterRegistrationBean 进行实例注册
 *
 *             Filter 生命周期
 *             创建(init): WEB服务器创建(Spring boot内置的tomcat), 在程序启动时, tomcat服务器创建Filter
 *                        实例对象(只创建一次), 并调用init方法(只执行一次), 准备拦截
 *             运行(doFilter): 1. 在目标调用资源前, 对request/response做预处理
 *                            2. filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行
 *                            3. 在目标调用资源后, 对response 数据再加工
 *             销毁(destroy): WEB服务器销毁, 释放资源
 *
 *             Filter 参数介绍
 *             filterConfig: { getFilterName: filter名称
 *                            getServletContext: Servlet上下文对象的引用
 *                            getInitParameter: 初始化参数(在xml或其他地方定义的数据 参考: ./file/filterConfig.txt)
 *                            getInitParameterNames: 返回过滤器的所有初始化参数的名字的枚举集合 }
 *            FilterChain 过滤链: { WEB 根据 Filter在 springboot 中的注册顺序(FilterRegistrationBean 中的order)
 *                              决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链
 *                              的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter
 *                              方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,
 *                              如果没有,则调用目标资源 }
 *
 *
 * @author: wangml
 * @date: 2021/7/21 14:41
 */
public class FilterDemo1 implements Filter {

    private static Logger logger = LoggerFactory.getLogger(FilterDemo1.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("-------------WEB服务器初始化init过滤器FilterDemo1-----------");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 将ServletRequest 转为Http请求
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

        accessResourceBefore(httpRequest, servletResponse);

        filterChain.doFilter(httpRequest, servletResponse);

        accessResourceAfter(servletResponse);
    }

    @Override
    public void destroy() {
        logger.info("-------------WEB服务器destroy过滤器FilterDemo1-----------");
    }

    /**
     * @description: request/response请求预处理
     *
     * @author: wangml
     * @date: 16:21 2021/7/21
     * @param: [request, response]
     * @return: void
     */
    private void accessResourceBefore(HttpServletRequest request, ServletResponse response) throws UnsupportedEncodingException {
        logger.info("-------------FilterDemo1处理前(预处理)-------------");
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
    }

    /**
     * @description: response加工
     *
     * @author: wangml
     * @date: 16:21 2021/7/21
     * @param: [servletResponse]
     * @return: void
     */
    private void accessResourceAfter(ServletResponse response) {
        logger.info("-------------FilterDemo1处理完成后(加工)-------------");
        // 随便写的, 不要深究(自己按功能处理)
        response.setCharacterEncoding("UTF-8");
    }
}

#### FilterDemo2 ####
package com.huntkey.rx.sceo.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import java.io.IOException;

/**
 * @description: 过滤器FilterDemo2
 * @author: wangml
 * @date: 2021/7/21 16:30
 */
public class FilterDemo2 implements Filter {

    private static Logger logger = LoggerFactory.getLogger(FilterDemo2.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("###############WEB服务器初始化init过滤器FilterDemo2#############");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("######### FilterDemo2处理前 #########");
        // TODO: 自己定义判断逻辑,比如MD5算法校验jwt是否正确
        Boolean flag = true;
        if (flag) {
            logger.info("######### FilterDemo2放行前 #########");
            filterChain.doFilter(servletRequest, servletResponse);
        }
        logger.info("######### FilterDemo2处理后 #########");
    }

    @Override
    public void destroy() {
        logger.info("##################WEB服务器destroy过滤器FilterDemo2##############");
    }
}

#### FilterDemo3 ####
package com.huntkey.rx.sceo.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import java.io.IOException;

/**
 * @description: 过滤器FilterDemo3
 * @author: wangml
 * @date: 2021/7/21 16:30
 */
public class FilterDemo3 implements Filter {

    private static Logger logger = LoggerFactory.getLogger(FilterDemo3.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("$$$$$$$$$$$$$$ WEB服务器初始化init过滤器 FilterDemo3 $$$$$$$$$$$");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        logger.info("$$$$$$$$$$$$$$ FilterDemo3处理前 $$$$$$$$$$$$$$");
        // TODO: 自己定义判断逻辑,比如MD5算法校验jwt中令牌是否正确
        Boolean flag = true;
        if (flag) {
            logger.info("$$$$$$$$$$$$$$ FilterDemo3放行前 $$$$$$$$$$$$$$");
            filterChain.doFilter(servletRequest, servletResponse);
        }
        logger.info("$$$$$$$$$$$$$$ FilterDemo3处理后 $$$$$$$$$$$$$$");
    }

    @Override
    public void destroy() {
        logger.info("$$$$$$$$$$$$$$ WEB服务器destroy过滤器FilterDemo3 $$$$$$$$$$$");
    }
}

过滤器注册

package com.huntkey.rx.sceo.filter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @description: 过滤器注册
 * @author: wangml
 * @date: 2021/7/21 14:34
 */
@Configuration
public class FilterCite {

    @Bean
    public FilterRegistrationBean registerFilterDemo1() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new FilterDemo1());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean<FilterDemo2> registerFilterDemo2() {
        FilterRegistrationBean<FilterDemo2> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new FilterDemo2());
        registrationBean.addUrlPatterns("/filter/*");
        registrationBean.setOrder(10);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean registerFilterDemo3() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new FilterDemo3());
        registrationBean.addUrlPatterns("/filter/*");
        registrationBean.setOrder(20);
        return registrationBean;
    }
}

测试

package com.huntkey.rx.sceo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @description: 测试filter使用
 * @author: wangml
 * @date: 2021/7/21 16:51
 */
@RestController
@RequestMapping(value = "/filter")
public class FilterTestController {

    private static Logger logger = LoggerFactory.getLogger(FilterTestController.class);

    @GetMapping("/load")
    public String load() {
        logger.info("************控制器方法**********");
        return "万古剑道长如夜, 天不生我wml";
    }
}

启动项目, 可以查看到如下信息, 说明在web启动完成后, 是会去调用filter中的init方法初始化过滤器

2021-07-22 09:29:38.819  INFO 6120 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-07-22 09:29:38.819  INFO 6120 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1537 ms
2021-07-22 09:29:38.884  INFO 6120 --- [  restartedMain] com.huntkey.rx.sceo.filter.FilterDemo2   : ###############WEB服务器初始化init过滤器FilterDemo2#############
2021-07-22 09:29:38.884  INFO 6120 --- [  restartedMain] com.huntkey.rx.sceo.filter.FilterDemo1   : -------------WEB服务器初始化init过滤器FilterDemo1-----------
2021-07-22 09:29:38.884  INFO 6120 --- [  restartedMain] com.huntkey.rx.sceo.filter.FilterDemo3   : $$$$$$$$$$$$$$ WEB服务器初始化init过滤器 FilterDemo3 $$$$$$$$$$$

浏览器 访问 http://localhost:8080/filter/load 显示 万古剑道长如夜, 天不生我wml, 控制台显示如下

2021-07-22 09:57:21.592  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo1   : -------------FilterDemo1处理前(预处理)-------------
2021-07-22 09:57:21.593  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo2   : ######### FilterDemo2处理前 #########
2021-07-22 09:57:21.593  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo2   : ######### FilterDemo2放行前 #########
2021-07-22 09:57:21.593  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo3   : $$$$$$$$$$$$$$ FilterDemo3处理前 $$$$$$$$$$$$$$
2021-07-22 09:57:21.593  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo3   : $$$$$$$$$$$$$$ FilterDemo3放行前 $$$$$$$$$$$$$$
2021-07-22 09:57:21.596  INFO 6120 --- [nio-8080-exec-5] c.h.r.s.controller.FilterTestController  : ************控制器方法**********
2021-07-22 09:57:21.600  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo3   : $$$$$$$$$$$$$$ FilterDemo3处理后 $$$$$$$$$$$$$$
2021-07-22 09:57:21.600  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo2   : ######### FilterDemo2处理后 #########
2021-07-22 09:57:21.600  INFO 6120 --- [nio-8080-exec-5] com.huntkey.rx.sceo.filter.FilterDemo1   : -------------FilterDemo1处理完成后(加工)-------------

三个过滤器都会拦截, 实际上最后只通过 优先级最低的过滤器进行放行, 和我们的要求相符合, 优先级高的过滤器先拦截, 满足要求的话才能继续往下继续

总结

  1. 过滤器过滤代码的过程相当于一个闭环过程, 参考上面例子说明: FilterDemo1(前, 中, 后), FilterDemo2(前, 中, 后) FilterDemo3(前, 中, 后), 划分节点是 filterChain.doFilter 执行(中), 具体的过程就可表示为 FilterDemo1前 -> FilterDemo2 前 -> FilterDemo3 前 -> FilterDemo3中 -> FilterDemo3后 -> FilterDemo2后 -> FilterDemo1后
  2. 每次过滤最多只会执行 filterChain.doFilter 一次
  3. 在定义过滤器的时候最好不要多次在doFilter 前后定义对请求和响应的处理, 否则根本不知道问题出在哪, 最好在 /* 路径下对请求和响应添加相应处理(防止覆盖)

参考
https://www.cnblogs.com/ixixi/p/11685269.html

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot允许你使用过滤器来拦截和处理HTTP请求和响应。过滤器是一种在请求进入servlet容器之前或响应离开容器之前执行操作的组件。 在Spring Boot中,你可以通过实现`javax.servlet.Filter`接口来创建一个过滤器。以下是一个简单的示例: ```java import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class MyFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 执行你的过滤操作,例如检查请求头或参数等 // 将请求传递给下一个过滤器或目标资源 filterChain.doFilter(request, response); } // 其他方法如init()和destroy()可以根据需要实现 } ``` 要将过滤器应用到Spring Boot应用程序中,你可以将其声明为一个Bean,并使用`@WebFilter`注解指定该过滤器的URL模式。例如: ```java import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyFilterConfig { @Bean public FilterRegistrationBean<MyFilter> myFilterRegistrationBean() { FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MyFilter()); registrationBean.addUrlPatterns("/api/*"); // 设置URL模式 return registrationBean; } } ``` 在上面的示例中,我们创建了一个名为`MyFilter`的过滤器,并使用`FilterRegistrationBean`将其注册到应用程序中。`addUrlPatterns`方法指定了要拦截的URL模式,例如`/api/*`表示所有以`/api/`开头的URL都会被该过滤器拦截处理。 请注意,这只是一个简单的示例,你可以根据自己的需求进行更复杂的过滤操作。同时,你也可以使用其他方式来注册过滤器,如使用`@ServletComponentScan`注解或通过`FilterRegistrationBean`的其他方法来设置过滤器的顺序等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值