springboot(11)过滤器Filter

Posted 汤姆猫-0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot(11)过滤器Filter相关的知识,希望对你有一定的参考价值。

文章目录

1.过滤器介绍

过滤器的英文名称为Filter,是Servlet技术中最实用的技术。如同它的名字一样,过滤器是处于客户端与服务器资源文件之间的一道过滤网,帮助我们过滤一些不符合要求的请求。通常它被用作 Session校验,判断用户权限,如果不符合设定条件,就会被拦截到特殊的地址或者给予特殊的响应。

Spring Boot过滤器可以用于拦截请求并在它们到达目标资源之前执行一些操作。过滤器通常用于修改请求或响应、验证请求参数或头部、记录请求日志等。

2.Filter生命周期

使用过滤器很简单,只需要实现Filter类,然后重写它的3个方法即可。

  • init方法:程序启动调用Filter的init()方法(永远只调用一次);在容器中创建当前过滤器的时候自动调用这个方法。
  • destory方法:程序停止调用Filter的destroy()方法(永远只调用一次);在容器中销毁当前过滤器的时候自动调用这个方法。
  • doFilter方法:doFilter()方法每次的访问请求如果符合拦截条件都会调用(程序第一次运行,会在servlet调用init()方法以后调用;不管第几次,都在调用doGet(),doPost()方法之前)。这个方法有3个参数,分别是ServletRequest、ServletResponse和FilterChain可以从参数中获取HttpServletReguest和HttpServletResponse对象进行相应的处理操作。

4.1注解方式实现过滤器

4.1.1 @WebFilter

@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )

@WebFilter注解用于定义过滤器,它可以应用于Servlet、JSP或静态资源等Web资源。@WebFilter注解有以下几个属性:

  • filterName:用于指定过滤器的名称。
  • urlPatterns:用于指定需要过滤的URL模式,可以指定多个URL模式。
  • value:与urlPatterns作用相同,也是用于指定需要过滤的URL模式。
  • servletNames:用于指定需要过滤的Servlet名称,可以指定多个Servlet名称。
  • dispatcherTypes:用于指定过滤器的拦截类型,包括:FORWARD、INCLUDE、REQUEST、ASYNC、ERROR。
  • initParams:用于指定过滤器的初始化参数,可以指定多个初始化参数。
属性名类型描述
filterNameString指定过滤器的名称
urlPatternsString[]指定需要过滤的URL模式,可以指定多个URL模式
valueString[]与urlPatterns作用相同,也是用于指定需要过滤的URL模式
servletNamesString[]指定需要过滤的Servlet名称,可以指定多个Servlet名称
dispatcherTypesDispatcherType[]指定过滤器的拦截类型,包括:FORWARD、INCLUDE、REQUEST、ASYNC、ERROR
initParamsWebInitParam[]指定过滤器的初始化参数,可以指定多个初始化参数

例如,以下代码定义了一个名为MyFilter的过滤器,它会拦截名为myServlet的Servlet,以及URL模式为/mypage的请求:

@WebFilter(filterName = "MyFilter",
        servletNames = "myServlet",
        urlPatterns = "/mypage")
public class MyFilter implements Filter 
    // ...

4.1.2 @Order

@Order()注解是用于指定过滤器链中过滤器的执行顺序的注解。当有多个过滤器时,@Order值小的过滤器先执行。如果没有指定@Order注解,则默认按照过滤器名称的字母顺序执行。

4.1.3 @ServletComponentScan

@ServletComponentScan注解是用于扫描指定包或类下的Servlet、Filter、Listener等Web组件,并将其注册到Servlet容器中的注解。在Spring Boot项目中,使用该注解可以让Spring Boot自动扫描并注册Servlet、Filter和Listener,而不需要手动进行配置。默认情况下,@ServletComponentScan会扫描主应用程序类所在的包及其子包下的所有类。

例如,以下代码演示了如何使用@ServletComponentScan注解来自动注册Servlet、Filter和Listener:

@ServletComponentScan(basePackages = "com.example.servlets", "com.example.filters")
@SpringBootApplication
public class MyApp 
    public static void main(String[] args) 
        SpringApplication.run(MyApp.class, args);
    

在上面的例子中,@ServletComponentScan注解会扫描com.example.servletscom.example.filters包下的所有Servlet和Filter,并将它们注册到Servlet容器中。同时,Spring Boot还会自动扫描并注册位于主应用程序类所在包及其子包下的所有组件。

需要注意的是,@ServletComponentScan注解只能在Spring Boot项目中使用,在普通的Servlet项目中是无效的。

4.1.4 使用

首先使用@ServletComponentScan注解来扫描过滤器类

@SpringBootApplication
@ServletComponentScan
public class ApplicationStarter 
  public static void main(String[] args) 
      SpringApplication.run(ApplicationStarter.class,args);
  

接下来在过滤器类上使用@WebFilter注解来定义过滤器,例如:

@WebFilter(urlPatterns = "/user/*", filterName = "testFilter")
@Order(1)
public class TokenFilter implements Filter 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
        Filter.super.init(filterConfig);
    

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException 
        System.out.println("doFilter");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader("token");
        System.out.println("token");
        //该方法执行后直接运行至下一个过滤器
        if(token!=null)
            filterChain.doFilter(servletRequest, servletResponse);
        else
            servletResponse.setCharacterEncoding("UTF-8");
            servletResponse.setContentType("application/json; charset=utf-8");
            PrintWriter out = servletResponse.getWriter();
            JSONObject res = new JSONObject();
            res.put("msg", "错误");
            res.put("success", "false");
            out.append(res.toString());
        
    

    @Override
    public void destroy() 
        Filter.super.destroy();
    

这段代码是一个Java Servlet Filter,用于拦截所有url以/user/开头的请求。它的过滤器名称是testFilter,使用urlPatterns参数指定了要拦截的URL模式。

这个过滤器的作用是检查请求头中是否有名为token的值,如果有则直接运行至下一个过滤器;否则返回一个JSON格式的错误信息。

doFilter方法中,首先获取请求对象的token值,然后判断是否为空。如果不为空,则调用filterChain.doFilter方法,该方法会将请求传递给下一个过滤器或目标资源。如果为空,则返回一个JSON格式的错误信息给客户端。

除了doFilter方法,这个过滤器还实现了initdestroy方法,分别在过滤器被初始化和销毁时调用。

4.2用配置类实现过滤器

4.2.1 方式(一)

这是一个使用Spring Boot配置类实现的过滤器。首先,我们需要创建一个类,用@Configuration注解标记它,以指示Spring Boot该类包含配置信息。然后,使用@Bean注解创建一个名为testFilter的过滤器。在这个过滤器中,我们需要实现Filter接口,并重写doFilter方法。

doFilter方法中,我们可以像Java Servlet Filter一样执行过滤器逻辑。如果需要添加更多的过滤器,可以使用filterChain.doFilter方法将请求传递给下一个过滤器。

以下是示例代码:

@Configuration
public class TestFilterConfig 

    @Bean
    public FilterRegistrationBean<TestFilter> testFilter() 
        FilterRegistrationBean<TestFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TestFilter());
        registrationBean.addUrlPatterns("/user/*");
        return registrationBean;
    

    public class TestFilter implements Filter 

        @Override
        public void init(FilterConfig filterConfig) throws ServletException 
            // 过滤器初始化逻辑
        

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
            // 过滤器逻辑
            chain.doFilter(request, response); // 将请求传递给下一个过滤器或目标资源
        

        @Override
        public void destroy() 
            // 过滤器销毁逻辑
        
    

4.2.2 方式(二)

4.2.2.1 Filter代码
package com.buba.filter;


import com.alibaba.fastjson.JSONObject;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;

public class TestFilter implements Filter 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
        System.out.println("init");
    

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException 
        System.out.println("doFilter");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader("token");
        System.out.println("token");
        //该方法执行后直接运行至下一个过滤器
        if(token!=null)
            filterChain.doFilter(servletRequest, servletResponse);
        else
            servletResponse.setCharacterEncoding("UTF-8");
            servletResponse.setContentType("application/json; charset=utf-8");
            PrintWriter out = servletResponse.getWriter();
            JSONObject res = new JSONObject();
            res.put("msg", "错误");
            res.put("success", "false");
            out.append(res.toString());
        
    

    @Override
    public void destroy() 
        System.out.println("destroy");
    

4.2.2.2 Filter配置类代码
package com.buba.config;

import com.buba.filter.TestFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig 
    // 创建 TestFilter 实例
    @Bean
    public TestFilter myFilter() 
        return new TestFilter();
    

    // 注册过滤器
    @Bean
    public FilterRegistrationBean getFilterRegistrationBean(TestFilter myFilter) 
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(myFilter);
        // 设置过滤器执行顺序
        filterRegistrationBean.setOrder(1);
        // 配置要过滤的 URL 模式
        filterRegistrationBean.addUrlPatterns("/test/*");
        // 设定过滤器名称
        filterRegistrationBean.setName("myFilter");
        return filterRegistrationBean;
    


这段代码是一个过滤器的配置类,用于将 TestFilter 实例注册到 Spring Boot 中的过滤器链中。以下是对代码中每个部分的解释:

  • @Configuration:这个注解表明这是一个 Spring 配置类,它会被 Spring 自动扫描并加载;
  • @Bean:这个注解表明这个方法会返回一个 Bean 实例,它会被 Spring 管理;
  • public TestFilter myFilter():这是一个方法,用于创建 TestFilter 实例;
  • public FilterRegistrationBean getFilterRegistrationBean(TestFilter myFilter):这也是一个方法,用于将 TestFilter 实例注册到 Spring Boot 中的过滤器链中;
  • filterRegistrationBean.setFilter(myFilter):这个方法将 myFilter 设置为过滤器实例;
  • filterRegistrationBean.setOrder(1):设置过滤器执行顺序,这个过滤器将会在其他过滤器之前执行;
  • filterRegistrationBean.addUrlPatterns("/test/*"):配置要过滤的 URL 模式;
  • filterRegistrationBean.setName("myFilter"):设定过滤器名称,这个名称会在控制台输出过滤器执行日志时使用。

SpringBoot SpringBoot过滤器Filter

1、SpringBoot启动默认加载的Filter
  characterEncodingFilter

  hiddenHttpMethodFilter

  httpPutFormContentFilter

  requestContextFilter

2、Filter优先级(Ordered.HIGHEST_PRECEDENCE  Ordered.LOWEST_PRECEDENCE)

低位值意味着更高的优先级 Higher values are interpreted as lower priority

自定义Filter,避免和默认的Filter优先级一样,不然会冲突

 

3、自定义Filter
1)使用Servlet3.0的注解进行配置

2)启动类里面增加 @ServletComponentScan,进行扫描

3)新建一个Filter类,implements Filter,并实现对应的接口

4) @WebFilter 标记一个类为filter,被spring进行扫描,urlPatterns:拦截规则,支持正则

5)控制chain.doFilter的方法的调用,来实现是否通过放行 不放行,web应用resp.sendRedirect("/index.html");

场景:权限控制、用户登录(非前端后端分离场景)等

 1 @WebFilter(urlPatterns = "/api/*", filterName = "loginFilter")
 2 public class LoginFilter  implements Filter{
 3     
 4     
 5     
 6      /**
 7       * 容器加载的时候调用
 8       */
 9       @Override
10       public void init(FilterConfig filterConfig) throws ServletException {
11           System.out.println("init loginFilter");
12       }
13 
14       
15       /**
16        * 请求被拦截的时候进行调用
17        */
18       @Override
19       public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
20           System.out.println("doFilter loginFilter");
21           
22           HttpServletRequest req = (HttpServletRequest) servletRequest;
23           HttpServletResponse resp = (HttpServletResponse) servletResponse;
24           String username = req.getParameter("username");
25           
26           if ("admin".equals(username)) {
27               filterChain.doFilter(servletRequest,servletResponse);
28           } else {
29               resp.sendRedirect("/index.html");
30               return;
31           }
32 
33       }
34 
35       /**
36        * 容器被销毁的时候被调用
37        */
38       @Override
39       public void destroy() {
40           System.out.println("destroy loginFilter");
41       }
42 
43 }

启动日志里,已经启动默认加载的Filter和自定义的Filter

官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners

 

以上是关于springboot(11)过滤器Filter的主要内容,如果未能解决你的问题,请参考以下文章

身份验证过滤器不适用于 Spring Boot

Springboot 过滤器

SpringBoot SpringBoot过滤器Filter

Spring Boot 过滤器顺序:WebLogic 12c vs Tomcat 8

如何在 Spring Boot 中设置过滤器链?

基于Springboot搭建java项目(二十三)——SpringBoot使用过滤器拦截器和监听器