过滤器和拦截器

介绍

过滤器和拦截器都是基于AOP面向切面编程思想实现的,用来解决项目中某一类问题的两种“工具”。

 

 

 

过滤器与拦截器的区别

 

过滤器关注的是web请求,对所有访问进行增强,做请求前和响应后处理

拦截器关注的是方法调用,做方法增强,围绕处理器前后使用

Filter 属于Servlet技术,基于函数回调,依赖Tomcat等容器,只能在web程序中使用

Interceptor属于SpringMVC技术,基于反射,是一个Spring组件,由spring容器管理,不依赖Tomat等容器,可以单独使用,不仅能在web程序中,也可以用于Application等程序。

 

过滤器是在请求进入容器后但在进入servlet之前进行预处理,请求结束是在servlet处理完成之后。

拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理,Controller完成后,后置处理完请求结束

 

 

 

 

 

 

 

 

过滤器

主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。

依赖于servlet容器,对所有请求起作用,在一个Action周期中,只能在容器初始化时调用一次

 

使用Filter的完整流程:

Filter对用户请求进行预处理

将请求交给servlet进行处理并生成响应

最后Filter对服务器进行后处理

 

Filter 功能:

  • 在HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest 。 根据需要检查 HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
  • 在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 根据需要检查 HttpServletResponse ,也可以修改HttpServletResponse头和数据。

 

Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的

  • 调用目标资源之前,让一段代码执行。
  • 是否调用目标资源(即是否让用户访问web资源)

web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

 

 

 

 

常见场景

  • 统一设置编码格式
  • 身份验证
  • 访问权限控制
  • 日志记录
  • 敏感数据过滤
  • 防止XSS攻击的过滤

 

实现

实现方式一:使用配置版

      在web.xml文件中进行配置
         <filter>
           <filter-name>testFilter</filter-name>
           <filter-class>com.bj.filter.TestFilter</filter-class>
          </filter>
          <filter-mapping>
           <filter-name>testFilter</filter-name>
           <url-pattern>/*</url-pattern>
  </filter-mapping>

 

 

实现方式二:使用@WebFilter注解配置 并通过@Order指定执行顺序

常用OverWrite =》 init、doFilter、destroy

init:filter初始化方法

dofilter:具体的过滤逻辑,FilterChian参数是用来调用下一个过滤器或者执行下一个流程  形成过滤链

destroy:用于filter销毁前完成相关资源的回收

import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@Component
@WebFilter(urlPatterns = "/*")
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器:执行 init 方法。");
    }
    @Override
    public void doFilter(ServletRequest servletRequest,
                         ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器:开始执行 doFilter 方法。");
        // 请求放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器:结束执行 doFilter 方法。");
    }
    @Override
    public void destroy() {
        System.out.println("过滤器:执行 destroy 方法。");
    }
}

作者:Java中文社群
链接:https://juejin.cn/post/7155069405993369631
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

执行具体逻辑

 在某个类上进行使用注解即可
    @WebFilter( 
            filterName = "characterFilter",
            urlPatterns = "/*",
            initParams = {
            @WebInitParam(name = "encoding", value = "UTF-8")
    })
    或者直接
        @WebFilter("/*")
    案列配置拦截地址
         //进行判断Session是否有数据
        HttpServletRequest  httpRequest=(HttpServletRequest)request;
        HttpServletResponse  httpResponse=(HttpServletResponse)response;
            String name=(String)httpRequest.getSession().getAttribute("name");
            String pwd=    (String)httpRequest.getSession().getAttribute("pwd");
            String  url=httpRequest.getRequestURI();
              if(name !=null  && pwd !=null) {
             chain.doFilter(request, response);
              }else if(url.contains("TestLongServlet")) {
                 chain.doFilter(request, response);
              }else if(url.contains("TestImgServlet")) {
                     chain.doFilter(request, response);
                }else {
                      System.out.println("@WebFilter:  httpRequest.getRequestDispatcher(\"list.jsp\").forward(request, response); ");
                         httpRequest.getRequestDispatcher("/list.jsp").forward(request, response); 
                }
      }    

 

字符集过滤器

 

 

 

地址过滤器

 

 

 

 

 

拦截器Interceptor

参考:https://juejin.cn/post/6844903550829461511

基于java反射原理实现

不依赖与servlet容器

针对Action ,方法调用,可以多次使用 如:在Controller前后增加拦截器进行调用方法时的前后处理逻辑   即增强方法

拦截器的加载时间点是在springContext之前

 

 

 

应用场景

1)、日志记录:可以记录请求信息的日志,以便进行信息监控、信息统计等。

2)、权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面。

3)、性能监控:典型的是慢日志。

 

源码

SpringMVC下

//继承spring的拦截接口,实现以下三个方法
public interface HandlerInterceptor {
    // 在业务处理器处理请求之前被调用
    boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    // 在业务处理器处理请求完成之后,生成视图之前执行
    void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
    // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源,日志打印
    void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}

 

 

 

 

 

 

 

 

 

实现

实现HandlerInterceptor或者继承HandlerInterceptorAdapter,重写preHandle()   自定义拦截器

实现WebMvcConfigurer,重写addCorsMappings()方法和addInterceptor()方法  注册拦截器

(HandlerInterceptorAdapter已经废弃,推荐直接实现WebMvcConfigurer或者继承WebMvcConfigurationSupport

 

WebMvcConfigurer是MVC的注解配置方式等同于xml配置

  • addInterceptors添加拦截器
  • addCorsMappings跨域
  • addViewControllers页面跳转(不用像现在我们要写一个Controller进行映射就可实现跳转)
  • addResourceHandlers静态资源(自定义静态资源映射目录)
  • configureDefaultServletHandling默认静态资源处理器
  • configureViewResolvers视图解析器(配置请求视图映射,配置了以后我们返回一个页面路径的字符串时,解析器会帮我们拼装前缀和后缀等信息)
  • configureMessageConverters信息转换器(比如我们入参的信息直接转换成json或者转换成对应的bean类就具体在这里配置)
/**
 * @author yhwang
 * 自定义拦截器 判断用户是否登录
 * @date 2021年06月28日 19:03
 */
public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行了Interceptor的preHandle方法");
        try {
            //统一拦截(查询当前session是否存在Usser用户信息)(这里User会在每次登陆成功后,写入session)
            User user = (User) request.getSession().getAttribute("User");
            if (user != null) {
                return true;
            }
            //这里设置拦截以后重定向的页面,一般设置为登陆页面地址
            response.sendRedirect(request.getContextPath() + "/demo/loginPage");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;//如果设置为false时,被请求时,拦截器执行到此处将不会继续操作
        //如果设置为true时,请求将会继续执行后面的操作
    }
    
    
    /***
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行了拦截器的postHandle方法");
    }
 
    /***
     * 整个请求结束之后被调用,也就是在DispatchServlet渲染了对应的视图之后执行(主要用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行了拦截器的afterCompletion方法");
    }
}

作者:yhwang0505
链接:https://juejin.cn/post/7038396711047266317
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

@Configuration //标识此为一个配置类
public class MyWebConfigurer implements WebMvcConfigurer {

    /**
     * 重写addInterceptors()实现拦截器
     * 配置:要拦截的路径以及不拦截的路径
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration registration = registry. addInterceptor (new LoginInterceptor()) ;
        //addPathPatterns() 方法 添加需要拦截的路径
        registration.addPathPatterns("/**");
        //addPathPatterns() 方法 添加不需要拦截的路径
        registration.excludePathPatterns(
                "/**/*.html",
                "/**/*.js"
        );
    }

    /**
     * 重写addCorsMapping()解决跨域问题
     * 配置:允许http请求进行跨域访问
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//指哪些接口url需要藏家跨域设置
            .allowedOrigins("*")//指的是前端哪些页面允许被跨域
                .allowCredentials(true)//需要嗲cookie等凭证,设置为true,就会把cookie的相关信息带上
                .allowedMethods("GET","POST","PUT","DELETE","OPTIONS","HEAD")//指的是允许哪些方法
                .maxAge(3600);//cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就会失效
    }
}

作者:yhwang0505
链接:https://juejin.cn/post/7038396711047266317
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

posted on 2023-03-19 14:36  or追梦者  阅读(180)  评论(0编辑  收藏  举报