ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

过滤器和拦截器

2021-01-19 10:57:20  阅读:215  来源: 互联网

标签:拦截器 request Filter doFilter 过滤器 response


过滤器:Filter

描述:Filter对web服务器管理的所有资源进行拦截,例如实现URL级别的权限访问控制、过滤敏感词汇等。

大致流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter接口中有一个doFilter方法,里面编写我们的业务逻辑,配置对哪个资源进行拦截,在调用service方法之前,都会先调用一下filter的doFilter方法,也可以编写多个Filter,这些Filter组合起来称之为一个Filter链,也可以控制先调用哪个Filter。web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

public void init(FilterConfig filterConfig) //初始化

Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,
完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) //这个方法完成实际的过滤操作。
public void destroy() //销毁

OncePerRequestFilter

Spring的OncePerRequestFilter类实际上是一个实现了Filter接口的抽象类。spring对Filter进行了一些封装处理,能够确保在一次请求只通过一次filter,
而不需要重复执行,因为在执行完后会在request设置标识符。

@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
        throw new ServletException("OncePerRequestFilter just supports HTTP requests");
    }
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    //得到一个固定标识,这个标识的作用是标记:该过滤器是否被执行过。也就是这个来实现执行一次的操作。
    String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();

    //检测当前请求是否已经拥有了该标记,如果拥有该标记则代表该过滤器执行过了
    boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;

    //如果执行过,或者不在拦截范围直接跳过,
    if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
        filterChain.doFilter(request, response);
    }else {
        //往request设置标识。
        request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
        try {
            //这个方法是一个抽象方法需要子类去实现具体的过滤逻辑。
            doFilterInternal(httpRequest, httpResponse, filterChain);
        }finally {
            //移除该标记。什么时候会执行到这里?
            request.removeAttribute(alreadyFilteredAttributeName);
        }
    }
}

那么doFilterInternal应该做什么?

public class xxxx extends OncePerRequestFilter {
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain){
        //执行业务代码
		//根据需要是否调用doFilter
        filterChain.doFilter(requestToUse, response);
    }
}

所以回到上面为什么会在finally里面调用request.removeAttribute() 也就是在请求接口最后,在执行移除标识操作。

拦截器:

SpringBoot之HandlerInterceptorAdapter
在SpringBoot中我们可以使用HandlerInterceptorAdapter这个适配器来实现自己的拦截器。这样就可以拦截所有的请求并做相应的处理。
应用场景:请求日志,权限,JVM性能输出等。

在HandlerInterceptorAdapter中主要提供了以下的方法:

  1. preHandle:在方法被调用前执行。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行。
  2. postHandle:在方法执行后调用。
  3. afterCompletion:在整个请求处理完毕后进行回调,也就是调用方已经拿到响应时。

拦截器和过滤器的区别:

  • 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  • 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  • 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  • 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  • 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  • 拦截器可以获取ioc中的service bean实现业务逻辑,拦截器可以获取ioc中的service
    bean实现业务逻辑,在拦截器里注入一个service,可以调用业务逻辑。

触发时机:
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
总结:过滤器包裹住servlet,servlet包裹住拦截器

过滤器的触发时机是容器后,servlet之前,所以过滤器的
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
的入参是ServletRequest ,而不是httpservletrequest。因为过滤器是在httpservlet之前。

过滤器

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
    System.out.println("before...");
    chain.doFilter(request, response);
	System.out.println("after...");
}

chain.doFilter(request, response);这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在chain.doFilter(request, response);这个方法中进行的。

2.拦截器是被包裹在过滤器之中的。
拦截器的preHandle()方法是在过滤器的chain.doFilter(request, response)方法的前一步执行,不是doFilter(request,response,chain)之前。
postHandle()方法在return ModelAndView之前,可以操控Controller的内容。
afterCompletion()方法是在过滤器返回给前端前一步执行。也就是doFilter(request,response,chain)方法return之前执行。
在我们项目中用的最多是preHandle这个方法,而未用其他的,框架提供了一个已经实现了拦截器接口的适配器类HandlerInterceptorAdapter,继承这个类重写一下需要用到的方法就行了,可以少几行代码,这种方式Java中很多地方都有体现。

本文摘自:
https://www.cnblogs.com/panxuejun/p/7715917.html
https://www.cnblogs.com/weianlai/p/11358768.html
https://blog.csdn.net/u012554102/article/details/51462161
https://www.cnblogs.com/cainiao-chuanqi/p/11326793.html

标签:拦截器,request,Filter,doFilter,过滤器,response
来源: https://blog.csdn.net/weixin_37862824/article/details/112801422

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有