spring boot: 拦截器与过滤器

本文部分内容来自 “过滤器 和 拦截器 6个区别,别再傻傻分不清了”

一 两者的区别
这两者在功能上有些类似,在具体技术实现方面还是有较大的差距的,这两者都是属于面向切面编程的具体实现,区别如下:
过滤器是依赖Servlet容器的,属于Servlet规范的一部分(也就是只能在web程序中使用),而拦截器则是独立存在的,在任何情况下都能使用
过滤器的执行由Servlet容器回调完成,而拦截器则通过动态代理的方式来执行
  • 在我们自定义的过滤器中都会实现一个 doFilter()方法,这个方法有一个FilterChain 参数,而实际上它是一个回调接口。ApplicationFilterChain是它的实现类, 这个实现类内部也有一个 doFilter() 方法就是回调方法。
    在这里插入图片描述
    在这里插入图片描述
  • ApplicationFilterChain里面能拿到我们自定义的xxxFilter类,在其内部回调方法doFilter()里调用各个自定义xxxFilter过滤器,并执行 doFilter() 方法。
  • 而每个xxxFilter 会先执行自身的 doFilter() 过滤逻辑,最后在执行结束前会执行filterChain.doFilter(servletRequest, servletResponse),也就是回调ApplicationFilterChain的doFilter() 方法,以此循环执行实现函数回调。
过滤器的生命周期由Servlet容器管理,而拦截器则可以通过Ioc容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用更加方便
过滤器 和 拦截器的触发时机也不同,我们看下边这张图。在这里插入图片描述
  • 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

  • 拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

二 注册过滤器
创建过滤器需要实现javax.servlet.Filter接口, 写接口中的方法.如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import java.io.IOException;

public class TestFilter implements Filter {

    private Logger log = LoggerFactory.getLogger(TestFilter.class);

   // 类的初始化方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("初始化过滤器");
    }

   // 类的销毁方法 
    @Override
    public void destroy() {
        log.info("销毁过滤器");
    }

   // 过滤器具体功能,如这里是对接口的执行时间进行计算
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long startTime = System.currentTimeMillis();
        log.info("进入接口时间:{}", startTime);
        filterChain.doFilter(servletRequest,servletResponse);
        long endTime = System.currentTimeMillis();
        log.info("接口完成时间:{},总用时:{}", endTime, endTime-startTime);
    }
}

SpringBoot中需要通过FilterRegistrationBean配置过滤器,如果是以前的web项目,则在web.xml中进行配置
import cn.xczh.basic_test.uitls.aop.TestFilter;
import cn.xczh.basic_test.uitls.aop.TestLogFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AopConfig {

    @Bean
    public FilterRegistrationBean registRunTimeFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        // 指定注入的过滤器
        registrationBean.setFilter(new TestFilter());
        // 过滤器所拦截的uri
        registrationBean.addUrlPatterns("/*");
        // 设置名字
        registrationBean.setName("runTimeFilter");
        // 设置优先级别,数字越小优先级越高
        registrationBean.setOrder(2);
        return registrationBean;
    }
}

或者是通过@WebFilter(urlPatterns = "/*", servletNames = "runtimeFilter")注解进行标记,为filter指定过滤的uri和servletName,如果使用这种方式的话无法控制过滤器的优先级别,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序排列,并且@WebFilter指定的过滤器优先级order默认为int最大值
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author :xcz 2020/6/8 14:43
 * 天靈靈地靈靈,代碼不要有問題
 * 测试过滤器,用于过滤接口运行时间
 */

@WebFilter(urlPatterns = "/*", filterName= "runtimeFilter")
public class TestRunTimeFilter implements Filter {

    private Logger log = LoggerFactory.getLogger(TestRunTimeFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("初始化过滤器");
    }

    @Override
    public void destroy() {
        log.info("销毁过滤器");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long startTime = System.currentTimeMillis();
        log.info("进入接口时间:{}", startTime);
        filterChain.doFilter(servletRequest,servletResponse);
        long endTime = System.currentTimeMillis();
        log.info("接口完成时间:{},总用时:{}", endTime, endTime-startTime);
    }
}

(ps:如果是在springboot中使用该注解的话,需要添加@Component或则是@Configuration注解将该类添加进入ioc容器,否则将无法生效,或则在application启动类上添加@ServletComponentScan该注解可以将@WebServlet、@WebFilter、@WebListener自动注入容器)
三 过滤器配置
创建拦截器类,实现 import org.springframework.web.servlet.HandlerInterceptor接口

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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


public class LogInterceptor implements HandlerInterceptor {

    Logger log = LoggerFactory.getLogger(LogInterceptor.class);

   // 这个方法将在请求处理之前进行调用。如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截器拦截,请求方法:{},请求方式:{}", request.getRequestURL(), request.getMethod());
        return true;
    }
// 只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 
返回渲染视图之前被调用。postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器  preHandle() 方法先执行,而postHandle()方法反而会后执行。
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("拦截器postHandle");
    }
// 只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束之后,  DispatcherServlet 渲染了对应的视图之后执行。
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("拦截器afterCompletion");
    }
}
对拦截器进行配置
import cn.xczh.basic_test.uitls.aop.LogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    // 注册拦截器,为其指定拦截的url
        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/*");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中的拦截过滤器有一些区别。拦截是Spring MVC自带的,不依赖于servlet容,而过滤器依赖于servlet容拦截是基于Java的反射机制,而过滤器是基于函数的回调。拦截只能对action请求起作用,而过滤器可以对几乎所有的请求起作用。拦截可以获取IOC容中的bean,而过滤器不可以。拦截是由Spring MVC提供的,可以在Controller中访问服务层。而过滤器是JavaEE标准,只需依赖servlet API,不需要依赖Spring。在Spring Boot中配置拦截可以使用@WebFilter注解,并在启动类中加上@ServletComponentScan注解指定扫描的包。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [Springboot--拦截过滤器 区别,作用,实现方法](https://blog.csdn.net/Dark_AK44/article/details/123746613)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [springboot过滤器拦截](https://blog.csdn.net/qq_42076204/article/details/125215984)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值