问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

SpringBoot实现过滤器Filter的三种方式

创作时间:
作者:
@小白创作中心

SpringBoot实现过滤器Filter的三种方式

引用
1
来源
1.
https://www.cnblogs.com/Chary/p/18699115

过滤器 Filter 是 Web 三大组件之一,也是项目常用到的工具,本文主要介绍一下 Filter的概念以及常见的使用方式。

过滤器Filter

过滤器 Filter 由 Servlet 提供,基于函数回调实现链式对网络请求与响应的拦截与修改。由于基于 Servlet ,其可以对web服务器管理的几乎所有资源进行拦截(JSP、图片文件、HTML 文件、CSS文件等)。

定义一个过滤器,需要实现 javax.servlet.Filter 接口。

Filter 并不是一个 Servlet,它不能直接向客户端生成响应,只是拦截已有的请求,对不需要或不符合的信息资源进行预处理。

过滤器可以定义多个,按照过滤器链顺序调用:

Filter 的生命周期

init(): 初始化Filter 实例,Filter 的生命周期与 Servlet 是相同的,也就是当 Web 容器(tomcat)启动时,调用 init() 方法初始化实例,Filter只会初始化一次。需要设置初始化参数的时候,可以写到init()方法中。

doFilter(): 业务处理,拦截要执行的请求,对请求和响应进行处理,一般需要处理的业务操作都在这个方法中实现

destroy() : 销毁实例,关闭容器时调用 destroy() 销毁 Filter 的实例。

过滤器的使用方式

首先要实现 javax.servlet.Filter 接口,之后将 Filter 声明为 Bean 交由 Spring 容器管理。以 SpringBoot 为示例:

方式一:@WebFilter注解

通过 @WebFilter 注解,将类声明为 Bean 过滤器类,在启动类添加注解 @ServletComponentScan ,让 Spring 可以扫描到。

@WebFilter
public class WebVisitFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    /**
     * 输出访问 ip
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        //获取访问 ip 地址
        HttpServletRequest req = (HttpServletRequest) request;
        String visitIp = req.getRemoteAddr();
        visitIp = "0:0:0:0:0:0:0:1".equals(visitIp) ? "127.0.0.1" : visitIp;
        // 每次拦截到请求输出访问 ip
        System.out.println("访问 IP = " + visitIp);
        chain.doFilter(req, response);
    }
    @Override
    public void destroy() {
    }
}
@SpringBootApplication
@ServletComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}  

@WebFilter作用
Tomcat 的 servlet 包下的注解,通过 @WebFilter 注解可以将指定类声明为过滤器。

@WebFilter 属性中没有配置顺序的,其执行顺序和 Filter 类名称字符排序有关,如果需要设置执行顺序,可以在命名的时候注意一下。

方式二:@Component注解

使用 @Component 将类声明为 Bean ,配合使用 @Order 注解可以设置过滤器执行顺序。

@Order(1)
@Component
public class WebVisitFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    /**
     * 输出访问 IP
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 业务处理
    }
    @Override
    public void destroy() {
    }
}  

方式三:Java Config 配置类

使用 @Configuration + @Bean 配置类,注解声明Bean,交由 Spring 容器管理。

Java Config 的方式可以通过 @Bean 配置顺序或 FilterRegistrationBean.setOrder() 决定 Filter 执行顺序。

public class WebVisitFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 业务处理
    }
    
    @Override
    public void destroy() {
    }
}
@Configuration
public class WebVisitFilterConfig {
    /**
     * 注册 过滤器 Filter
     */
    @Bean
    public FilterRegistrationBean<Filter> webVisitFilterConfigRegistration() {
        //匹配拦截 URL
        String urlPatterns = "/admin/*,/system/*";
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<Filter>();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new WebVisitFilter());
        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
        //设置名称
        registration.setName("webVisitFilter");
        //设置过滤器链执行顺序
        registration.setOrder(3);
        //启动标识
        registration.setEnabled(true);
        //添加初始化参数
        registration.addInitParameter("enabel", "true");
        return registration;
    }
}  

FilterChain 的作用

过滤器链是一种责任链模式的设计实现,在一个Filter 处理完成业务后,通过 FilterChain 调用过滤器链中的下一个过滤器。

流程如下:

FilterChain 接口定义了 doFilter 方法

public interface FilterChain {
    
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException;
    
}  

ApplicationFilterChain类实现了 FilterChain 接口,管理所有的 Filter 的执行与调用

public final class ApplicationFilterChain implements FilterChain {
    // 数组存储所有的过滤器链
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    
    // 类中实现 doFilter() 方法 调用 调用 internalDoFilter(req,res) 方法
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        // ...
        //调用 internalDoFilter
        internalDoFilter(request,response);
        
    }
}  

internalDoFilter(req,res) 方法中实现 Filter 调用的具体的操作,如下:

//取得数组中下一个过滤器实例
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
// ...
//调用下一个过滤器的 doFilter() 方法
filter.doFilter(request, response, this);  

通过这种方式完成整个过滤器链的调用执行。

常见应用场景

  • 登录验证
  • 统一编码处理
  • 敏感字符过滤

过滤器链抛出异常处理方式

在过滤器进行拦截操作时,如发生异常,与业务类相同需要捕获异常进行记录并处理。如果想继续执行业务,可以通过 chain.doFilter(req, response); 对之后的过滤器进行调用。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号