spring项目--过滤器,拦截器,监听器

一、http请求后台执行的顺序

启动顺序:监听器 > 过滤器 > 拦截器(context-param-->listener-->filter-->servlet-->interceptor)

记忆技巧:接到命令,监听电报,过滤敌情,拦截行动。

二、区别和理解

如果我们现在大海就是我们启动的项目,那么监听器就能够听到整个大海的声音,过滤器就是能够过滤出其中的鱼,而拦截器则是拦截其中的部分鱼,并且作标记。所以当需要监听到项目中的一些信息,并且不需要对流程做更改时,用监听器;当需要过滤掉其中的部分信息,只留一部分时,就用过滤器;当需要对其流程进行更改,做相关的记录时用拦截器。

三、详细概念

context-param:就是一些需要初始化的配置,放入context-param中,从而被监听器(这里特指org.springframework.web.context.ContextLoaderListener)监听,然后加载;

监听器(listener):就是对项目起到监听的作用,它能感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;

过滤器(filter):就是对请求起到过滤的作用,它在监听器之后,作用在servlet之前,对请求进行过滤;

servlet:就是对request和response进行处理的容器,它在filter之后执行,servlet其中的一部分就是controller层(标记为servlet_2),还包括渲染视图层(标记为servlet_3)和进入controller之前系统的一些处理部分(servlet_1),另外我们把servlet开始的时刻标记为servlet_0,servlet结束的时刻标记为servlet_4。

拦截器(interceptor):就是对请求和返回进行拦截,它作用在servlet的内部,具体来说有三个地方:

1)servlet_1和servlet_2之间,即请求还没有到controller层

2)servlet_2和servlet_3之间,即请求走出controller层次,还没有到渲染时图层

3)servlet_3和servlet_4之间,即结束视图渲染,但是还没有到servlet的结束

它们之间的关系,可以用一张图来表示:

四、用途

监听器的用途:

1.通常使用Web监听器做以下的内容:
  2.统计在线人数,利用HttpSessionLisener
  3.加载初始化信息:利用ServletContextListener
  4.统计网站访问量
  5.实现访问监控

servlet的监听接口,
1)ServletContextListener监听web应用的启动和关闭
2)ServletContextAttributeListener监听ServletContext范围内属性的改变
3)ServletRequestListener监听用户的请求
4)ServletRequestAttributeListener监听ServletRequest范围内(request)内属性的变化
5)HttpSessionListener监听用户session的开始和结束
6)HttpSessionAttributeListener监听HttpSession范围内session内属性的改变。
springmvc的监听器ContextLoaderListener(实现ServletContextListener)用于加载spring容器的配置文件。
 

过滤器的用途:

1、对请求参数request,response等设置字符编码或者其他响应头

2、对用户登录信息获取,没有重定向到登录页,实现用户权限访问

3、对一些非法请求过滤处理,如敏感参数等

拦截器:

对通过过滤的指定拦截的请求,做一些特殊处理,如aop的模式(性能分析, 权限检查, 日志记录)

五、java代码实现

过滤器:

定义一个TimeFilter类,实现javax.servlet.Filter:
public class TimeFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("开始执行过滤器");
        Long start = new Date().getTime();
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("【过滤器】耗时 " + (new Date().getTime() - start));
        System.out.println("结束执行过滤器");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}
TimeFilter重写了Filter的三个方法,方法名称已经很直白的描述了其作用,这里不再赘述。要使该过滤器在Spring Boot中生效,还需要一些配置。这里主要有两种配置方式。

配置方式一
可通过在TimeFilter上加上如下注解:
@Component
@WebFilter(urlPatterns = {"/*"})
public class TimeFilter implements Filter {
   ...
}

@Component注解让TimeFilter成为Spring上下文中的一个Bean,@WebFilter注解的urlPatterns属性配置了哪些请求可以进入该过滤器,/*表示所有请求。

配置方式二
除了在过滤器类上加注解外,我们也可以通过FilterRegistrationBean来注册过滤器。

定义一个WebConfig类,加上@Configuration注解表明其为配置类,然后通过FilterRegistrationBean来注册过滤器:
@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean timeFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        TimeFilter timeFilter = new TimeFilter();
        filterRegistrationBean.setFilter(timeFilter);

        List<String> urlList = new ArrayList<>();
        urlList.add("/*");

        filterRegistrationBean.setUrlPatterns(urlList);
        return filterRegistrationBean;
    }
}
 

FilterRegistrationBean除了注册过滤器TimeFilter外还通过setUrlPatterns方法配置了URL匹配规则。重启项目访问

通过过滤器我们只可以获取到servletRequest对象,所以并不能获取到方法的名称,所属类,参数等额外的信息。

拦截器:

定义一个TimeInterceptor类,实现org.springframework.web.servlet.HandlerInterceptor接口:
public class TimeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("处理拦截之前");
        httpServletRequest.setAttribute("startTime", new Date().getTime());
        System.out.println(((HandlerMethod) o).getBean().getClass().getName());
        System.out.println(((HandlerMethod) o).getMethod().getName());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("开始处理拦截");
        Long start = (Long) httpServletRequest.getAttribute("startTime");
        System.out.println("【拦截器】耗时 " + (new Date().getTime() - start));
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("处理拦截之后");
        Long start = (Long) httpServletRequest.getAttribute("startTime");
        System.out.println("【拦截器】耗时 " + (new Date().getTime() - start));
        System.out.println("异常信息 " + e);
    }
}

TimeInterceptor实现了HandlerInterceptor接口的三个方法。preHandle方法在处理拦截之前执行,postHandle只有当被拦截的方法没有抛出异常成功时才会处理,afterCompletion方法无论被拦截的方法抛出异常与否都会执行。

通过这三个方法的参数可以看到,相较于过滤器,拦截器多了Object和Exception对象,所以可以获取的信息比过滤器要多的多。但过滤器仍无法获取到方法的参数等信息,我们可以通过切面编程来实现这个目的,具体可参考https://mrbird.cc/Spring-Boot-AOP%20log.html。

要使拦截器在Spring Boot中生效,还需要如下两步配置:

1.在拦截器类上加入@Component注解;

2.在WebConfig中通过InterceptorRegistry注册过滤器:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private TimeInterceptor timeInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }
}
监听器:

第一种:在初始化的时候添加监听器 app.addListeners(new MyApplicationListener());

第二种:

第三种:在application.propertiies 添加

context.listener.classes=com.boot.enable.addlistener.MyApplicationListener

第四种:

@Component
public class HandlerEvent {

    @EventListener
    public void evendListener(MyApplicationEvent event){
        System.out.println("监听了-----"+event.getSource());
        System.out.println("监听了-----"+event.getClass());
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章