欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

过滤器(Filter)与拦截器(Interceptor )区别

程序员文章站 2024-02-05 10:10:04
...

1.过滤器(Filter)

Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是设置字符集、控制权限、控制转向、做一些业务逻辑判断等。其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。

Filter可以认为是Servlet的一种“加强版”,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

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

2.Filter的简单实现

字面意思:过滤器就是过滤的作用,在web开发中过滤一些我们指定的url
那么它能帮我们过滤什么呢?
那功能可就多了:
比如过拦截掉我们不需要的接口请求
修改请求(request)和响应(response)内容
完成CORS跨域请求等等

demo1:

<filter>
        <description>字符集过滤器</description>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>字符集编码</description>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

demo2

现在我们来实现一个简单的过滤器:
可以新建一个filter包,随着项目的扩大过滤器会越来越多
在这里我新建了一个TestFilter类,实现Filter接口

@Component
@WebFilter(urlPatterns = "/Blogs",filterName = "blosTest")
public class TestFilter implements Filter{}

我们一步步来
[email protected]就是把这个类注入到IOC容器中
[email protected](urlPatterns = “/Blogs”,filterName = “blosTest”)说明这是一个web过滤器,它拦截的url为/Blogs,过滤器名字为blogsTest

下面贴出实现接口之后的三个重构方法:

@Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request= (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        System.out.printf("过滤器实现");
        filterChain.doFilter(request,response);
    }
 
    @Override
    public void destroy() {
 
    }

初始化(init)和摧毁(destroy)方法一般不会用到,具体使用看下源码便知
doFilter()是过滤器的核心
注意:在实现接口方法之后,我们要转换request和response类型至HttpServlet,否则接下去的操作可能会报错。
如果过滤通过,执行filterChain.doFilter(request,response);
说明这个url已经经过了我们的Filter

可以看到,只需要一个类我们就实现了一个简单的过滤器

当然可以不用注解的方式,配置启动类

//过滤器
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        List<String> urlPatterns = new ArrayList<String>();
 
        TestFilter testFilter = new TestFilter();   //new过滤器
        urlPatterns.add("/Blogs");      //指定需要过滤的url
        filterRegistrationBean.setFilter(testFilter);       //set
        filterRegistrationBean.setUrlPatterns(urlPatterns);     //set
 
        return filterRegistrationBean;
    }

3.拦截器(Interceptor)

拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制。是普通的java类,在本地就可运行

拦截是AOP的一种实现策略

拦截器将Action共用的行为独立出来,在Action执行前后执行。这也就是我们所说的AOP,它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。

当你提交对Action(默认是.action结尾的url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被Interceptor截取,Interceptor在Action执行前后执行。

SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

4.拦截器(Interceptor)使用

interceptor 的执行顺序大致为:
1.请求到达 DispatcherServlet
2.DispatcherServlet 发送至 Interceptor ,执行 preHandle
3.请求达到 Controller
4.请求结束后,postHandle 执行

Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,实现 HandlerInterceptor 接口需要实现下面三个方法:

  • preHandle() – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。
  • postHandle() – 在handler执行之后, 可以在返回之前对返回的结果进行修改
  • afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等

我们同样可以新建一个interceptor包
在里面新建一个名为MyInterceptor的类

public class MyInterceptor implements HandlerInterceptor {}

这个类实现了HandleInterceptor接口
直接贴类代码,我会在代码中注释功能

public class MyInterceptor implements HandlerInterceptor {
    //在请求处理之前进行调用(Controller方法调用之前
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.printf("preHandle被调用");
        return true;    //如果false,停止流程,api被拦截
    }
 
    //请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle被调用");
    }
 
    //在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("afterCompletion被调用");
    }
}

它依次实现了三个方法
相比过滤器,拦截器还需要在springmvc中注入
所以我们打开启动类,写入以下代码

public class WarApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(WarApplication.class, args);
    }
 
    //mvc控制器
    //@Configuration
    static class WebMvcConfigurer extends WebMvcConfigurerAdapter{
        //增加拦截器
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new MyInterceptor())    //指定拦截器类
                    .addPathPatterns("/Handles");        //指定该类拦截的url
        }
    }
}

4.区别:

过滤器和拦截器非常相似,但是它们有很大的区别

  • Filter 接口定义在 javax.servlet 包中 接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中
  • Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。 而拦截器是在 Spring容器内的,是Spring框架支持的。过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境
  • 过滤器可以修改request,而拦截器不能
  • 拦截器可以调用IOC容器中的各种依赖,而过滤器不能
  • 过滤器只能在请求的前后使用,而拦截器可以详细到每个方法
  • Filter 是被 Server(like Tomcat) 调用 Interceptor 是被 Spring 调用 , 因此Filter总比Inteceptor先执行

5.拦截器(Interceptor)和过滤器(Filter)的执行顺序

过滤前-拦截前-Action处理-拦截后-过滤后