Spring过滤器

Spring过滤器

工作原理

  • 过滤器依赖于 Servlet容器, 基于函数回调来实现

工作流程

  • 用户请求时在 HttpServletRequest到 Servlet之前预处理相关事务 比如 修改或判断 HttpServletRequest头信息和数据. 然后 Servlet之后返回给用户 HttpServletResponse之前又处理相关事务并返回

使用场景

  • 比较常见的有拦截过滤图片地址, URL地址, 敏感词汇, 检查头信息, 压缩响应信息, 权限验证, 设置字符编码

Spring过滤器的基本结构

  • Spring Web包的过滤器核心接口及抽象类基本结构

javax.servlet.Filter -> org.springframework.web.filter -> GenericFilterBean -> OncePerRequestFilter -> AbstractRequestLoggingFilter

  1. 抽象类 GenericFilterBean继承了一系列接口, 主要实现了可以从 web.xml中取已定义的 init-param的值或 application.properties等环境文件中取值, 然后初始化 Filter
  2. 抽象类 OncePerRequestFilter继承了 GenericFilterBean, 继承 OncePerRequestFilter的自定义类, 主要实现每次接收请求时确保每个 Filter只执行一次, 以及实现抽象方法 doFilterInternal, 在此方法中决定过滤之前和之后执行的事件

import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class CustomOncePerRequestFilter1 extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        System.out.println("CustomOncePerRequestFilter1 Environment custom-key: " + getEnvironment().getProperty("custom-key"));
        try {
        filterChain.doFilter(request, response);
        } finally {
            System.out.println("CustomOncePerRequestFilter1 Finally");
        }
    }

}

  1. 抽象类 AbstractRequestLoggingFilter继承了 OncePerRequestFilter, 继承 AbstractRequestLoggingFilter的自定义类, 主要遗传了父类的过滤之前和之后执行的事件, 实现抽象方法 beforeRequest和 afterRequest

import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import javax.servlet.http.HttpServletRequest;

@Configuration
public class CustomAbstractRequestLoggingFilter extends AbstractRequestLoggingFilter {
    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        String ipAddress = request.getHeader("X-FORWARDED-FOR");
        if (ipAddress == null) {
            ipAddress = request.getRemoteAddr();
        }
        System.out.println("CustomAbstractRequestLoggingFilter > beforeRequest -> ipAddress: " + ipAddress);
        System.out.println("CustomAbstractRequestLoggingFilter > beforeRequest -> url: " + request.getRequestURI());
        System.out.println("CustomAbstractRequestLoggingFilter > beforeRequest -> name: " + request.getParameter("name"));
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        System.out.println("CustomAbstractRequestLoggingFilter > afterRequest -> name: " + request.getParameter("name"));
    }

}

  • 测试控制器 http://127.0.0.1:8080/test.do?name=林爷

@RestController
public class TestController {
    @GetMapping(value = "/test.do")
    public Map<String, String> test(@RequestParam(value="name", required=false, defaultValue="全爷") String name) {
        System.out.println("TestController -> name: " + name);
        return new HashMap<>();
    }
}

输出:
CustomAbstractRequestLoggingFilter > beforeRequest -> ipAddress: 127.0.0.1
CustomAbstractRequestLoggingFilter > beforeRequest -> url: /test.do
CustomAbstractRequestLoggingFilter > beforeRequest -> name: 林爷
CustomOncePerRequestFilter1 Environment custom-key: abc123
TestController -> name: 林爷
CustomOncePerRequestFilter1 Finally
CustomAbstractRequestLoggingFilter > afterRequest -> name: 林爷

  1. 配置多个过滤器并排执行顺序

import com.example.demo.controller.CustomAbstractRequestLoggingFilter;
import com.example.demo.controller.CustomOncePerRequestFilter1;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.Filter;

@Configuration
public class FilterConfig {
    @Bean
    public Filter customOncePerRequestFilter1() {
        return new CustomOncePerRequestFilter1();
    }

    @Bean
    public FilterRegistrationBean _customOncePerRequestFilter1() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DelegatingFilterProxy("customOncePerRequestFilter1"));
        registration.addUrlPatterns("/*");                      // 拦截路径
        registration.setOrder(0);                               // 顺序
        return registration;
    }

    @Bean
    public Filter customAbstractRequestLoggingFilter() {
        return new CustomAbstractRequestLoggingFilter();
    }

    @Bean
    public FilterRegistrationBean _customAbstractRequestLoggingFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DelegatingFilterProxy("customAbstractRequestLoggingFilter"));
        registration.addUrlPatterns("/*");                      // 拦截路径
        registration.setOrder(1);                               // 顺序
        return registration;
    }

}

输出:
CustomOncePerRequestFilter1 Environment custom-key: abc123
CustomAbstractRequestLoggingFilter > beforeRequest -> ipAddress: 127.0.0.1
CustomAbstractRequestLoggingFilter > beforeRequest -> url: /test.do
CustomAbstractRequestLoggingFilter > beforeRequest -> name: 林爷
TestController -> name: 林爷
CustomAbstractRequestLoggingFilter > afterRequest -> name: 林爷
CustomOncePerRequestFilter1 Finally

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

发布了62 篇原创文章 · 获赞 325 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qcl108/article/details/104870054