过滤器(filter)以及拦截器(interceptor)的使用方法

过滤器(filter)

目的

在 请求到达指定 url 前进行请求头的校验, 增删改以及校验请求头中的内容
链式结构, 会不断的往下一个 过滤器传递

使用方式

先创建一个自定义的 MyXXXFilter 实现 javax.servlet 包下面的 Filter 接口
  1. 自定义 MyEncodingFilter 过滤器
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

/**
 * * 自定义过滤器, 设置请求编码类型
 *
 * @author yxg
 * @date 2022/3/3 11:42
 */
@Slf4j
@Component
public class MyEncodingFilter implements Filter {
    private FilterConfig filterConfig = null;
    private String encoding = null;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        ServletContext context = this.filterConfig.getServletContext();
        context.log("=====> 设置请求编码格式");

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        
        String encoding = getEncoding();
        if (encoding == null) {
            encoding = "gb2312";
        }

        request.setCharacterEncoding(encoding);

        try {
            log.info("设置请求编码格式 过滤器被调用了.........请求地址为: {}",request.getRequestURI());
            chain.doFilter(request, response);
            context.log("=====> 设置请求编码格式 成功");
        } catch (Exception e) {
            log.error("=====> 调用过滤链异常,异常信息为: {}", e.getMessage());
        }

    }

    @Override
    public void destroy() {
        this.encoding = null;
    }

    public String getEncoding() {
        return encoding;
    }
}

  1. 在来一个 MyLogFilter 过滤器
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

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

/**
 * *过滤器的作用就是在请求来的时候拦截所有请求, 对其请求头进行校验, 以及 重新定义请求头里面的内容
 *
 * @author yxg
 * @date 2022/3/2 14:09
 */
@Slf4j
@Component
public class MyLogFilter implements Filter {

    String[] excludedUrl;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        excludedUrl = filterConfig.getInitParameter("excludedUrl").split(",");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        log.info("过滤器被调用了........");

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {

            String requestURI = request.getRequestURI();

            if (isExcludedUrl(requestURI)) {
                log.info("日志过滤器被调用了...是不需要处理的请求地址...请求地址为: {}", request.getRequestURI());
                // 不进行后续的链的操作
                return;
            }

            log.info("日志过滤器被调用了.........请求地址为: {}", request.getRequestURI());
            log.info("日志过滤器被调用了.........请求ip为: {}", request.getRemoteHost());
            log.info("日志过滤器被调用了.........请求端口port为: {}", request.getRemotePort());
            chain.doFilter(request, response);
        } catch (Exception e) {
            log.error("=====> 调用过滤链异常,异常信息为: {}", e.getMessage());
        }
    }

    private boolean isExcludedUrl(String url) {
        if (excludedUrl == null || excludedUrl.length <= 0) {
            return false;
        }
        for (String ex : excludedUrl) {
            url = url.trim();
            ex = ex.trim();
            if (url.toLowerCase().matches(ex.toLowerCase().replace("*", ".*"))) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void destroy() {
    }
}

  1. 最后创建一个 servlet 的配置类 WebConfiguration, 注意加上 @Configuration 注解
import com.nyist.myticket.web.filter.MyEncodingFilter;
import com.nyist.myticket.web.filter.MyLogFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * * 过滤器 配置
 *
 * @author yxg
 * @date 2022/3/3 10:56
 */
@Configuration
public class WebConfiguration {

	// 调用的顺序是 order 数值越小 , 越先执行
    // registrationBean.setOrder(1);

    @Bean
    public FilterRegistrationBean encodingFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();

        // 将自定义的 filter 注册进 filter 注册表
        registrationBean.setFilter(new MyEncodingFilter());
        // 添加 类型,
        // 过滤 应用程序中所有资源, 当前的应用程序根下的所有文件夹, * 前面要有 /
        registrationBean.addUrlPatterns("/*");
        // 过滤 指定类型的文件资源, 当前应用程序根目录下的所有 .html 文件, 注意 .html 前面没有 /
        //registrationBean.addUrlPatterns("*.html");
        // 过滤 指定目录下的所有文件, 当前应用程序根目录下的 controller 子目录下的所有文件
        registrationBean.addUrlPatterns("/controller/*");
        // 过滤指定文件
        registrationBean.addUrlPatterns("/index.html");
        // ...还可以有很多

        StringBuilder excludedUrl = new StringBuilder();

        //excludedUrl.append("/");
        //excludedUrl.append("/");

        registrationBean.addInitParameter("excludedUrl",excludedUrl.toString());
        registrationBean.setName("encodingFilter");
        // 数值越小 , 越先执行
        registrationBean.setOrder(1);

        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean loggerFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();

        // 将自定义的 filter 注册进 filter 注册表
        registrationBean.setFilter(new MyLogFilter());
        // 添加 类型,
        // 过滤 应用程序中所有资源, 当前的应用程序根下的所有文件夹, * 前面要有 /
        registrationBean.addUrlPatterns("/*");
        // 过滤 指定类型的文件资源, 当前应用程序根目录下的所有 .html 文件, 注意 .html 前面没有 /
        //registrationBean.addUrlPatterns(".html");
        // 过滤 指定目录下的所有文件, 当前应用程序根目录下的 controller 子目录下的所有文件
        registrationBean.addUrlPatterns("/controller/*");
        // 过滤指定文件
        registrationBean.addUrlPatterns("/index.html");
        // ...还可以有很多

        StringBuilder excludedUrl = new StringBuilder();
        excludedUrl.append("/userInfo");

        registrationBean.addInitParameter("excludedUrl","");
        registrationBean.setName("loggerFilter");
        // 数值越小, 级别越高
        registrationBean.setOrder(2);

        return registrationBean;
    }
}

拦截器

目的在请求指定的方法或者字段之前或者之后进行拦截操作, 添加日志或者校验

使用方式

  1. 先创建一个 自定义 拦截器 MyInterceptor 实现 import org.springframework.web.servlet.HandlerInterceptor; 下的 HandlerInterceptor 接口
import com.nyist.myticket.core.factory.GenerateCodeFactory;
import com.nyist.myticket.core.utils.constant.SysConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * *拦截器, 计算请求时间
 *
 * @author yxg
 * @date 2022/3/2 16:28
 */
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    public final static Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

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

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        logger.info("拦截器被调用了....preHandle");
        logger.info("================================  start   ================================");
        String logTraceId = request.getHeader(SysConstant.LOG_TRACE_ID);
        if (StringUtils.isBlank(logTraceId)) {
            Long snowflakeId = GenerateCodeFactory.snowflakeId();
            logTraceId = snowflakeId.toString();
        }

        MDC.put(SysConstant.LOG_TRACE_ID, logTraceId);

        long beginTime = System.currentTimeMillis(); // 1、开始时间
        timeThreadLocal.set(beginTime);              // 线程绑定变量(该数据只有当前请求的线程可见)
        return true;      // 继续流程
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
        logger.info("拦截器被调用了....postHandle");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        logger.info("拦截器被调用了....afterCompletion");

        long endTime = System.currentTimeMillis();// 2、结束时间
        long beginTime = timeThreadLocal.get();// 得到线程绑定的局部变量(开始时间)

        String requestURI = request.getRequestURI();

        long requestTime = endTime - beginTime;
        if (requestTime > 500) {// 此处认为处理时间超过500毫秒的请求为慢请求
            logger.warn(requestURI + " 比较耗时:" + requestTime);
        } else {
            logger.info("=====>请求地址为:" + requestURI + "  耗时为: {}", requestTime);
        }

        MDC.remove(SysConstant.LOG_TRACE_ID);
        logger.info("================================  end   ================================");
    }

}

  1. 在创建一个 mvc 的配置类 WebMvcConfig 也要加 @Configuration 注解
import com.nyist.myticket.web.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * * 拦截器配置类
 *
 * @author yxg
 * @date 2022/3/2 17:03
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;
    
    /**
     * 添加 拦截器注册表
     * @author yxg 
     * @date 2022/3/3 9:41
     * @param registry
     * @return void
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor)  // 添加自定义拦截器
                .addPathPatterns("/**");    // 添加拦截路径
    }
}

这样在 Springboot 启动的时候就会为我们配置好我们自己的 过滤器和拦截器

他们的请求流程如下图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
切面(Aspect) 明天继续研究

参考文章1-基础代码 = https://www.yht7.com/news/154190
参考文章2-多个过滤器配置 = https://blog.csdn.net/WoddenFish/article/details/84836824
参考文章3-图片来源 = https://www.cnblogs.com/panxuejun/p/7715917.html
参考文章4-拦截器 = https://zhuanlan.zhihu.com/p/408809649
参考文章5-区别 = https://blog.csdn.net/weixin_44502804/article/details/93139550
参考文章6-最后一张图来源 = https://developer.aliyun.com/article/636629

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值