过滤器(Filter)和拦截器(Interceptor)

参考文章:https://blog.csdn.net/tszc95/article/details/129250183

Filter 过滤器

Filter 过滤器介绍

Filter是sun公司中servlet2.3后增加的一个新功能,在javaEE中定义了一个接口 javax.servlet.Filter(新版本包名:jakarta.servlet)来描述过滤器。

Filter主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序。它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求进行过滤。
Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。并且它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。

Filter工作原理

Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一处理等。

使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

  1. 当服务器启动,会创建Filter对象,并调用init方法,只调用一次。

  2. 当访问资源,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,

  3. 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作。

Filter应用场景

在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符、敏感词过滤、响应信息压缩、控制权限、控制转向、做一些业务逻辑判断等。

Filter代码示例

配置方式1:通过xml配置(自己查)

配置方式2:通过@WebFilter注解配置

创建一个filter包,以后我们的过滤器就放在这个包下,然后创建CommentFilter过滤器,实现Filter接口,通过@WebFilter注解,进行一些简单的配置

@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。

下面是一些属性解释:

  1. filterName:过滤器名
  2. urlPatterns:过滤器的URL匹配模式,这里可以配置你要过滤的请求
  3. initParam:设置一些初始参数
package com.demo.filter;
 
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.annotation.WebInitParam;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
// 通过WebFilter注解来配置过滤的范围
@WebFilter(filterName = "commentFilter",urlPatterns = "/comment/submit",initParams = {@WebInitParam(name = "sensitiveWord", value = "nt")})
public class CommentFilter implements Filter {
    private List<String> sensitiveWords = new ArrayList<>();
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //得到敏感词汇
        String word = filterConfig.getInitParameter("sensitiveWord");
        //加入集合
        sensitiveWords.add(word);
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //设置编码
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        //得到评论
        String message = servletRequest.getParameter("message");
        for (String sensitiveWord : sensitiveWords) {
            //对所有敏感词汇进行过滤
            if (message.contains(sensitiveWord)){
                //替换敏感词汇
                message = message.replace(sensitiveWord, "**");
            }
        }
        //存入request域
        servletRequest.setAttribute("comment",message);
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }
    
     @Override
    public void destroy() {
        // Filter的销毁方法
        System.out.println("TestFilter destroy");
        Filter.super.destroy();
    }
}
package com.demo.controller;
 
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class CommentController {
    /**
     * 跳转到评论网页
     */
    @RequestMapping("/comments")
    public String toCommentPage() {
 
        return "comment";
    }
 
    /**
     * 处理提交评论的请求
     * @param request
     * @param model
     * @return
     */
 
    @PostMapping("/comment/submit")
    public String getString(HttpServletRequest request, Model model) {
        //获取过滤器设置的Attribute
        String comment = (String) request.getAttribute("comment");
        //将其封装在model里面,以便前端使用Thymeleaf模板获取到
        model.addAttribute("comment", request.getAttribute("comment"));
        return "comment";
    }
}
package com.demo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
 
// 在启动类添加@ServletComponentScan:将过滤器注册到Spring容器中
@SpringBootApplication
@ServletComponentScan
public class ApplicationDemo {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationDemo.class,args);
 
    }
}

PS: 多个filter 实现@WebFilter,难以控制filter 的过滤顺序,与其包名和文件名有关,慎用。

配置方式3 :通过@Bean来配置

//1.初始化Filter
@Component
public class TestFilter2 implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter2 init");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //在DispatcherServlet之前执行
        System.out.println("doFilter2 before");
        filterChain.doFilter(servletRequest, servletResponse);
        // 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("doFilter2 after");
    }
 
    @Override
    public void destroy() {
        System.out.println("Filter2 destroy");
    }
}


@Component
public class TestFilter3 implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter3 init");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //在DispatcherServlet之前执行
        System.out.println("doFilter3 before");
        filterChain.doFilter(servletRequest, servletResponse);
        // 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("doFilter3 after");
    }
 
    @Override
    public void destroy() {
        System.out.println("Filter3 destroy");
    }
}
 
//2.注册到config
@Configuration
public class FilterConfig {
 
    @Bean
    public FilterRegistrationBean testFilter3RegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter2());
        registration.addUrlPatterns("/hello world");
        registration.setOrder(1); // 值越小越靠前,此处配置有效
        return registration;
    }
 
    @Bean
    public FilterRegistrationBean testFilter4RegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new TestFilter3());
        registration.addUrlPatterns("/hello world");
        registration.setOrder(2);
        return registration;
    }
}

Filter有三个阶段:

  1. 初始化阶段:当服务器启动时,我们的服务器(Tomcat)就会读取配置文件,扫描注解,然后来创建Filter
  2. 拦截和过滤节点:只要请求资源的路径和拦截的路径相同,那么过滤器就会对请求进行过滤,这个阶段在服务器运行过程中会一直循环
  3. 销毁阶段:当服务器(Tomcat)关闭时,服务器创建的Filter也会随之销毁

Interceptor 拦截器介绍(只针对spring介绍)

Interceptor 定义

拦截器(Interceptor)和Servlet无关,在SpringMVC中依赖于SpringMVC框架,由SpringMVC框架实现。它是一种可以让你在Action执行之前和Result执行之后进行一些功能处理的机制。

在实现上,基于Java的反射机制,属于**面向切面编程(AOP)**的一种运用。可以用于在某个方法或者字段被访问之前,进行拦截,然后在之前或者之后加入某些统一的处理方法。就是在action的前、后、甚至抛出异常时进行处理,比如动态代理就是拦截器的简单实现。

SpringMVC的拦截器基于HandlerInterceptor接口来实现,所以只要实现HandlerInterceptor接口或者继承它的实现类。

Interceptor 工作原理

拦截器的实现分为两步:

第一步,创建一个普通的拦截器,实现 HandlerInterceptor 接口,并重写接口中的相关方法;

第二步,将上一步创建的拦截器加入到 Spring Boot 的配置文件中。

preHandle()方法:该方法会在控制方法前执行,方法返回值表示是否知道如何写一个接口。中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)

postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步修改

afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作

Interceptor 应用场景

日志记录:记录请求操作日志(用户ip,访问时间等)

权限检查:判断用户是否有权限访问资源,如校验token 日志记录

性能监控:记录请求->响应时间,preHandle:记录开始时间,afterCompletion:记录结束时间,开始时间相减去结束时间

登录验证:判断用户是否登录

sign校验,封禁校验等

处理cookie,主题,国际化,本地化等

filter可以实现的功能intercepter基本上都能实现

Interceptor 代码实战

实现HandlerInterceptor接口的拦截器:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 目标方法执行之前
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        log.info("preHandle拦截的请求路径是{}",requestURI);

        //登录检查逻辑
        HttpSession session = request.getSession();

        Object loginUser = session.getAttribute("loginUser");

        if(loginUser != null){
            //放行
            return true;
        }

        // 拦截住。未登录。跳转到登录页
        request.setAttribute("msg","请先登录");
		// re.sendRedirect("/");
        request.getRequestDispatcher("/").forward(request,response);
        return false;
    }

    /**
     * 目标方法执行完成以后
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行{}",modelAndView);
    }

    /**
     * 页面渲染以后
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行异常{}",ex);
    }
}

拦截器注册到容器中

@Configuration
public class AdminWebConfig implements WebMvcConfigurer{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 拦截器注册到容器中
                .addPathPatterns("/**")  // 所有请求都被拦截包括静态资源
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**",
                        "/js/**","/aa/**"); // 放行的请求
}

拦截器和过滤器的使用场景?

拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:

  1. 登录验证,判断用户是否登录
  2. 权限验证,判断用户是否有权限访问资源,如校验token
  3. 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量
  4. 处理cookie、本地化、国际化、主题等
  5. 性能监控:监控请求的处理时长等

过滤器本质是函数回调(职责链),主要的应用场景包括:

  1. 过滤敏感词汇
  2. 设置字符编码
  3. URL级别的权限访问控制
  4. 压缩响应信息

通用行为:读取cookie得到用户信息并将用户对象放入请求,以便后续流程使用,还有提取Locale、Theme等信息,只要是多个处理器需要的即可使用拦截器实现


过滤器(Filter)和拦截器(Interceptor) 、servlet、controller的执行顺序

在这里插入图片描述


过滤器与拦截器区别

过滤器(Filter)和拦截器(Interceptor)它们的主要区别如下:

  1. 运行位置不同:

    ​ Filter在只在 Servlet 前后起作用,Filter 通常不考虑servlet 的实现。

    ​ 拦截器能够深入到Controller方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期

    在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现

  2. 执行顺序不同:

    过滤器的执行顺序是由其在web.xml文件中声明的顺序决定的,按照声明的顺序依次执行;

    而拦截器的执行顺序是根据其在配置文件中的声明顺序决定的,也就是说拦截器可以指定先后顺序。

  3. 功能不同:

    过滤器主要用于对请求进行预处理和过滤,例如设置字符集、登录验证、日志记录等操作;

    而拦截器则主要用于对请求进行流程控制,例如权限验证、参数注入、异常处理等操作。

  4. 依赖框架不同:

    过滤器是基于Servlet规范实现的,不依赖任何特定的框架;

    而拦截器则通常是针对特定的框架或库实现的,例如Spring MVC框架中的拦截器。

  5. 实现原理不同:

    过滤器的本质是函数回调

    拦截器是基于java反射机制(动态代理),本质是面向切面编程(AOP)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
filter过滤器拦截器是Web开发中常用的两种组件,它们在请求处理过程中起到了类似于"中间件"的作用,用于对请求进行处理和拦截。 Filter过滤器Servlet规范中定义的一种组件,它可以对请求进行预处理和后处理。Filter可以拦截特定的URL请求,对请求进行处理,并将请求传递给下一个过滤器ServletFilter可以用于对请求进行身份验证、日志记录、编码转换、资源过滤等等操作。一个应用可以配置多个Filter,它们按照配置的顺序依次执行。 拦截器是在Spring框架中使用的一种组件,它也可以对请求进行预处理和后处理。拦截器的使用更加灵活,可以对请求进行更加细粒度的控制。拦截器可以拦截Controller方法的调用,在方法执行前后做一些处理,例如身份验证、日志记录、性能监控等。一个应用可以配置多个拦截器,它们按照配置的顺序依次执行。 在使用上,filterinterceptor有一些区别: - Filter是基于Servlet规范的,而Interceptor是Spring框架提供的; - Filter可以对所有的请求进行拦截,而Interceptor可以对Controller方法进行拦截; - Filter只能通过web.xml或注解进行配置,而Interceptor可以通过Java代码进行配置; - Interceptor可以访问Spring的上下文,而Filter不能。 总结来说,filterinterceptor都可以用于对请求进行处理和拦截,但是它们的具体实现和使用方式有一些差异。在使用时,可以根据具体需求选择适合的组件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值