SpringBoot Filter过滤器和Interceptor拦截器

本文详细介绍了SpringBoot中Filter过滤器和Interceptor拦截器的使用,包括它们的前言、请求过程、主要代码实现及两者之间的区别。在Filter部分,讨论了过滤器的作用,如处理敏感信息、防止XSS等,并提供了JAVA config配置示例。Interceptor部分则阐述了其在SpringWebMVC中的角色,主要方法以及与Filter的不同,强调了执行顺序和生命周期。同时,通过源码分析加深了对它们工作原理的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Filter过滤器

前言

问:我们为什么要使用过滤器?
答:在web请求过程,过滤一些敏感词汇、验证Header请求头、防止XSS、SQL注入,能快速返回信息

问:过滤器是什么?
答:Filter是Servlet的一个组件在 请求到达 Servlet 之前,被一个或多个Filter处理。

请求过程

Filter执行过程

具体代码

自定义Filter

package com.nijo.example.web.filter;

import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;

/**
 * 自定义Filter过滤器
 * 可以用作请求前 信息头验证(没有token、或自定义头)、拦截xss、SQL注入
 * 这里提供2中方式注入 1.@webFilter() + @ServletComponentScan
 * 2.Bean java config模式
 */
public class CustomFilter implements Filter {

    /**
     * 项目启动时候值会运行一次
     * 可以用作当前数据初始化
     * eg init add  List<string>
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CustomFilter 初始化init()");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //可以做信息头的检测、xss检测、sql注入、记录请求
        System.out.println("start check RequestHeard.....");
        String token = ((HttpServletRequest) servletRequest).getHeader("token");
        if(Objects.isNull(token)||"".equals(token)){
            //参数有误 转发请求到参数合法直接返回
            servletRequest.getRequestDispatcher("/parameterException").forward(servletRequest,servletResponse);
        }
       else {
            //符合条件 请求目标方法
filterChain.doFilter(servletRequest,servletResponse);
        }
        System.out.println("返回response 过滤参数");
    }

    /**
     * 项目停止会调用该方法
     * */
    @Override
    public void destroy() {
        System.out.println("CustomFilter 销毁 destroy()");
    }
}

JAVA config 方式配置 上诉讲了@webFilter注入容器

package com.nijo.example.web.filter;

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

@Component
public class FilterConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        //自定义过滤器
        registrationBean.setFilter(new CustomFilter());
        //过滤/*所有路径
        registrationBean.addUrlPatterns("/*");
        //初始化数据 可以在dofilter()逻辑过滤不判断url
        //registrationBean.addInitParameter("noFilter","/1,/2");
        registrationBean.setName("customFilter");
        //存在多个过滤器 设置优先级
        registrationBean.setOrder(0);
        return registrationBean;
    }
}

测试 用例:http://127.0.0.1:8080/test

package com.nijo.example.web.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class UserController {

    @GetMapping("/parameterException")
    Map<String,String> parameterException(){
        Map<String,String> result=new HashMap<>();
        result.put("200","参数异常");
        return result;
    }

    @GetMapping("/test")
    Map<String,String> test(){
        Map<String,String> result=new HashMap<>();
        result.put("200","通许success");
        return result;
    }
}

结果

Filter测试返回结果

Interceptor

前言

SpringWebMVC 拦截器,跟Servlet过滤器有点相识,主要请求进入Controller之前进行一些前置判断,所谓前置判断(用户登陆状态、请求性能记录等等)。如果知道MVC请求流程,这个拦截器知识就很easy。

主要方法

方法描述
boolean preHandle()请求会先执行这个预处理方法,可以实现登陆状态、验权逻辑 返回true 进入下一个Interceptor false中断 不进入Controller
void postHandle()后置处理方法,在返回ModelAndView之前倒序执行每个Interceptor postHandle
void afterCompletion()请求完毕,即视图渲染完成回调方法 可以做一些请求时间结束记录

与Filter区别

1.Filter属于Servlet组件,Interceptor输入webMvc组件
2.执行流程不同,先执行Filter 在执行Interceptor
3.web加载顺序是listener–>filter–>servlet–>Spring Filter过滤器中@Autowired是会空指针异常,解决办法 在过滤器init()

//init()初始化filter时手动注入bean对象
		ServletContext context = filterConfig.getServletContext(); 
		ApplicationContext ac = WebApplicationContextUtils .getWebApplicationContext(context);

请求过程

1.请求会先到Interceptor下preHandle 方法,返回true 进入下一个Interceptor 可以设置Order 请求顺序 ,直到所有拦截器都返回true,请求到目标方法,中途任意一个拦截器返回false 后面拦截器都不执行。
2.Controller 返回ModelAndView前 会倒序执行Interceptor下post Handle方法,所谓倒序就是拦截器2–>拦截器1 方式依次执行
3.在视图解析器解析完成后,会回调Interceptor下afterCompletion方法,也是倒序执行

拦截器执行过程

源码

DispatcherServlet类 doDispatch方法

try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
//拦截器预处理preHandle
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				//调用具体Controller
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
  //处理PostHandle 方法
        mappedHandler.applyPostHandle(processedRequest, response, mv);
  }
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
//调用afterCompletion
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

applyPreHandle 方法

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		for (int i = 0; i < this.interceptorList.size(); i++) {
			HandlerInterceptor interceptor = this.interceptorList.get(i);
			if (!interceptor.preHandle(request, response, this.handler)) {
			//失败时触发afterCompletion的调用
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
		return true;
	}

实现方式

1.直接使用实现HandlerInterceptor接口 此方式必须重写接口内所有方法

2.继承 HandlerInterceptorAdapter 已经过时,此方式不用重写所有方法,用到什么方法重写即可。底层还是继承HandlerInterceptor接口,解决方法创建一个类 实现HandlerInterceptor

自定义拦截器

/**
 * 自定义拦截器
 * 用于请求性能检测
 * 继承 HandlerInterceptorAdapter 过时
 * */
public class CoustomInterceptor implements HandlerInterceptor {

    private ThreadLocal<Long> map = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        map.set(System.currentTimeMillis());
        System.out.println("记录请求URL:" + request.getRequestURI() + "开始");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //结束请求时间
        Long end = System.currentTimeMillis() - (map.get());
        System.out.println("请求URL:"+request.getRequestURI()+",耗时:"+end+"ms");
        map.remove();
    }
}

java config方式配置将拦截器加入Spring
这里有两种方式
1.实现WebMvcConfigurer
2.继承WebMvcConfigurationSupport

/**
 * 配置拦截器加入Spring
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CoustomInterceptor())
                .addPathPatterns("/*");//拦截路径
        WebMvcConfigurer.super.addInterceptors(registry);
    }

//    @Override
//    protected void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new CoustomInterceptor())
//                .addPathPatterns("/*");//拦截路径
//        super.addInterceptors(registry);
//    }
}

结果

拦截器运行结果

源码

Spring-Boot-Examples 目录:filter-Interceptor

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值