web 过滤器 Filter、 Spring 拦截器 interceptor

1、过滤器(Filter)(在web.xml中注册过滤器)

  首先说一下Filter的使用地方,我们在配置web.xml时,总会配置下面一段设置字符编码,不然会导致乱码问题:

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encoding</filter-name>
    <servlet-name>/*</servlet-name>
</filter-mapping>

  配置这个地方的目的,是让所有的请求都需要进行字符编码的设置,下面来介绍一下Filter。

(1)过滤器(Filter):它依赖于servlet容器。在实现上,基于函数回调,它可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的,是用来做一些过滤操作,获取我们想要获取的数据,比如:在Javaweb中,对传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是:在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等。

public class CharacterEncodingFilter implements Filter {

    protected FilterConfig filterConfig;
    protected String encoding = null;
    protected boolean forceEncoding = true; // 默认为true

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("forceEncoding");
        if (value == null) {
            this.forceEncoding = true;
        } else if (value.equalsIgnoreCase("true")) {
            this.forceEncoding = true;
        } else if (value.equalsIgnoreCase("yes")) {
            this.forceEncoding = true;
        } else {
            this.forceEncoding = false;
        }
    }

    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest  request;
        try {
            request = (HttpServletRequest) req;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }

        String encoding = filterConfig.getInitParameter("encoding");
        if(encoding==null){
            encoding = "UTF-8";
        }
        //设置字符编码
        request.setCharacterEncoding(encoding);
        //将请求与响应传递给下个过滤器
        chain.doFilter(request, response);
    }

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

}

void init(FilterConfig paramFilterConfig) :  当容器初始化 Filter 时调用,该方法在 Filter 的生命周期只会被调用一次,一般在该方法中初始化一些资源,FilterConfig 是容器提供给 Filter 的初始化参数,在该方法中可以抛出 ServletException 。init 方法必须执行成功,否则 Filter 可能不起作用,出现以下两种情况时,web 容器中 Filter 可能无效: 1)抛出 ServletException 2)超过 web 容器定义的执行时间。 

doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) : Web 容器每一次请求都会调用该方法。该方法将容器的请求和响应作为参数传递进来, FilterChain 用来调用下一个 Filter。  

void destroy() :当容器销毁 Filter 实例时调用该方法,可以在方法中销毁资源,该方法在 Filter 的生命周期只会被调用一次。

注: 其中的FilterConfig对象提供对servlet环境及web.xml文件中指派的过滤器名的访问。
   FilterConfig对象具有一个getInitParameter方法,它能够访问部署描述符文件(web.xml)中分配的过滤器初始化参数。



二:拦截器

  拦截器(Interceptor):它依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制,属于面向切面编程(AOP)的一种运用,就是在service或者一个方法前,调用一个方法,或者在方法后,调用一个方法,比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

下面在一个项目中我们使用既有多个过滤器,又有多个拦截器,并观察它们的执行顺序:

  (1)第一个过滤器:

public class TestFilter1 extends Filter {  

        @Override
          protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //在DispatcherServlet之前执行
        System.out.println("############TestFilter1 doFilterInternal executed############");
        filterChain.doFilter(request, response);
        //在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("############TestFilter1 doFilter after############");
    }
}  

  (2)第二个过滤器:

public class TestFilter2 extends Filter {  

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //在DispatcherServlet之前执行
        System.out.println("############TestFilter2 doFilterInternal executed############");
        filterChain.doFilter(request, response);
        //在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("############TestFilter2 doFilter after############");
    }
}  

(3)在web.xml中注册这两个过滤器:

    <!-- 自定义过滤器:testFilter1 -->
       <filter>
            <filter-name>testFilter1</filter-name>
            <filter-class>com.scorpios.filter.TestFilter1</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>testFilter1</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- 自定义过滤器:testFilter2 -->
       <filter>
            <filter-name>testFilter2</filter-name>
            <filter-class>com.scorpios.filter.TestFilter2</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>testFilter2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

再定义两个拦截器:
(4)第一个拦截器:

public class BaseInterceptor implements HandlerInterceptor{  

    /**
     * 在DispatcherServlet之前执行
     * */
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("************BaseInterceptor preHandle executed**********");
        return true;
    }  

    /**
     * 在controller执行之后的DispatcherServlet之后执行
     * */
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
        System.out.println("************BaseInterceptor postHandle executed**********");
    }  

    /**
     * 在页面渲染完成返回给客户端之前执行
     * */
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("************BaseInterceptor afterCompletion executed**********");
    }
}

(5)第二个拦截器:

public class TestInterceptor implements HandlerInterceptor {  

    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("************TestInterceptor preHandle executed**********");
        return true;
    }  

    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
        System.out.println("************TestInterceptor postHandle executed**********");
    }  

    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
        System.out.println("************TestInterceptor afterCompletion executed**********");
    }
}  

(6)、在SpringMVC的配置文件中,加上拦截器的配置:

<!-- 拦截器 -->
    <mvc:interceptors>
        <!-- 对所有请求都拦截,公共拦截器可以有多个 -->
        <bean name="baseInterceptor" class="com.scorpios.interceptor.BaseInterceptor" />  

        <mvc:interceptor>
            <!-- 对/test.html进行拦截 -->
            <mvc:mapping path="/test.html"/>
            <!-- 特定请求的拦截器只能有一个 -->
            <bean class="com.scorpios.interceptor.TestInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>  

(7)、定义一个Controller控制器:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;  

@Controller
public class TestController {
    @RequestMapping("/test")
    public ModelAndView handleRequest(){
        System.out.println("---------TestController executed--------");
        return new ModelAndView("test");
    }
}  

(8)、测试结果:
  启动测试项目,地址如下:http://www.localhost:8080/demo,可以看到控制台中输出如下:

  这就说明了过滤器的运行是依赖于servlet容器,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关。

  接着清空控制台,并访问:http://www.localhost:8080/demo/test,再次看控制台的输出:

  从这个控制台打印输出,就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于多个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关。



三:结论

  对于上述过滤器和拦截器的测试,可以得到如下结论:
  (1)、Filter需要在web.xml中配置,依赖于Servlet;
  (2)、Interceptor需要在SpringMVC中配置,依赖于框架;
  (3)、Filter的执行顺序在Interceptor之前;

  (4)、两者的本质区别:拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。

原文地址:https://www.cnblogs.com/myseries/p/10801814.html

时间: 2024-10-25 07:34:19

web 过滤器 Filter、 Spring 拦截器 interceptor的相关文章

过滤器(Filter)、拦截器(Interceptor)、监听器(Listener)

一.Filter 过滤器 1.简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. 它主要用于对用户请求进行预处理,也可以对HttpServletResponse 进行后处理.使用Filter 的完整流程:Filter 对用户请求

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

1 .拦截器是基于java的反射机制的,而过滤器是基于函数回调. 2 .拦截器不依赖与servlet容器,过滤器依赖与servlet容器. 3 .拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用. 4 .拦截器可以访问action上下文.值栈里的对象,而过滤器不能访问. 5 .在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次. 6.拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,

spring拦截器(interceptor)简介

1. 拦截器用途 (1)拦截未登录用户直接访问某些链接 (2)拦截日志信息 (3)拦截非法攻击,比如sql注入 2. 涉及jar.类 (1)spring-webmvc.jar (2)HandlerInterceptor(org.springframework.web.servlet:接口).  AsyncHandlerInterceptor(org.springframework.web.servlet:接口).  HandlerInterceptorAdapter(org.springfram

过滤器 ;spring拦截器 切片 小结

1. springMVc的拦截器 实现HandlerInterceptor接口,如下: public class HandlerInterceptor1 implements HandlerInterceptor { // controller执行后且视图返回后调用此方法 // 这里可得到执行controller时的异常信息 // 这里可记录操作日志 @Override public void afterCompletion(HttpServletRequest arg0, HttpServle

详述 Spring MVC 框架中拦截器 Interceptor 的使用方法

1 前言 昨天新接了一个需要,"拦截 XXX,然后 OOO",好吧,说白了就是要用拦截器干点事(实现一个具体的功能).之前,也在网络上搜了很多关于Interceptor的文章,但感觉内容都大同小异,而且知识点零零散散,不太方便阅读.因此,正好借此机会,整理一篇关于拦截器的文章,在此分享给大家,以供大家参考阅读. 2 拦截器 2.1 概念 Java 里的拦截器是动态拦截 action 调用的对象.它提供了一种机制可以使开发者可以定义在一个 action 执行的前后执行的代码,也可以在一个

Spring MVC中的拦截器Interceptor

谈谈spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可以帮我们验证是否登陆.预先设置数据以及统计方法的执行效率等等.今天就来详细的谈一下spring中的拦截器.spring中拦截器主要分两种,一个是HandlerInterceptor,一个是MethodInterceptor. 一,HandlerInterceptor拦截器 HandlerInterceptor是springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行.实现一个Ha

Java三大器之拦截器(Interceptor)的实现原理及代码示例

前言:前面2篇博客,我们分析了Java中过滤器和监听器的实现原理,今天我们来看看拦截器. 1,拦截器的概念    java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式.在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作.目前,我们需要掌握的主要是Spring的拦截器,Struts2的拦截器

Spring拦截器

Spring的拦截器具备在web的前置和后置来处理各种请求. 拦截器接口-HandlerInterceptor 自定义的拦截器,需要继承HandlerInterceptor接口,并且实现HandlerInterceptor中提供的三个方法: 1. preHandle 方法会在请求处理前被调用.这个方法返回boolean值,如果返回true则继续往下执行,如果返回false则中断. 2. postHandle 方法会在请求处理后,继续调用. 3. afterCompletion 方法会在视图渲染之

spring拦截器中修改响应消息头

问题描述 前后端分离的项目,前端使用Vue,后端使用Spring MVC. 显然,需要解决浏览器跨域访问数据限制的问题,在此使用CROS协议解决. 由于该项目我在中期加入的,主要负责集成shiro框架到项目中作为权限管理组件,之前别的同事已经写好了部分接口,我负责写一部分新的接口. 之前同事解决跨域问题使用Spring提供的@CrossOrigin注解: @RequestMapping(value = "/list.do", method = RequestMethod.GET) @R