1.什么是过滤器?

过滤器的英文名称为Filter,是Servlet技术中最实用的技术。如同它的名字一样,过滤器是处于客户端与服务器资源文件之间的一道过滤网,帮助我们过滤一些不符合要求的请求。通常它被用作Session校验,判断用户权限,如果不符合设定条件,就会被拦截到特殊的地址或者给予特殊的响应。

2.如何使用过滤器?

使用过滤器很简单,只需要实现Filter接口即可,然后重写它的三个方法,方法描述如下:
void init(FilterConfig filterConfig):过滤器的初始化方法,在容器中创建过滤器的时候会自动调用此方法
boolean doFilter(ServletRequest request, ServletResponse response, FilterChain chain):当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法
void destroy:在容器中销毁当前过滤器时自动调用此方法

  1. package com.fly.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.http.HttpServletRequest;
  4. import java.io.IOException;
  5. /**
  6. * 自定义过滤器
  7. */
  8. public class TestFilter implements Filter {
  9. /**
  10. * 过滤器的初始化方法,在容器中创建过滤器的时候会自动调用此方法
  11. */
  12. @Override
  13. public void init(FilterConfig filterConfig) throws ServletException {
  14. System.out.println("初始化过滤器");
  15. }
  16. /**
  17. * 当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法。
  18. * ServletRequest:servlet请求对象,可以通过ServletRequest获取到HttpServletRequest
  19. * ServletResponse:servlet响应对象,可以通过ServletResponse获取HttpServletResponse
  20. * FilterChain:该接口用于定义一个 Filter 链的对象应该对外提供的方法,这个接口只定义了一个 doFilter 方法
  21. */
  22. @Override
  23. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  24. System.out.println("请求被过滤器拦截");
  25. //获取HttpServletRequest对象
  26. HttpServletRequest httpServletRequest=(HttpServletRequest) request;
  27. //获取请求地址
  28. String url=httpServletRequest.getRequestURI();
  29. System.out.println("请求地址是:"+url);
  30. }
  31. /**
  32. * 在容器中销毁当前过滤器时自动调用此方法
  33. */
  34. @Override
  35. public void destroy() {
  36. System.out.println("过滤器销毁");
  37. }
  38. }

3.什么是拦截器?

拦截器英文是Interceptor,用于拦截请求、权限校验、资源控制等等功能,实现拦截器有2种方式,第一种是实现HandlerInterceptor接口,第二种是继承实现了HandlerInterceptor接口的子类,例如HandlerInterceptorAdapter类
HandlerInterceptor接口三个重要方法说明:

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):截处理程序的执行。在HandlerMapping确定适当的处理程序对象之后但在HandlerAdapter调用处理程序之前调用,preHandle方法是进行处理器拦截用的,表示是否允许通过拦截,为true则允许通过,该方法为true时才会执行postHandle方法,该方法将在Controller处理之前进行调用,该方法进行请求的预处理,可以进行编码、安全控制、权限校验等处理,Object handler表示拦截的对象

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception:postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面),Exception可以获取DispatcherServlet处理请求后抛出的异常

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
  * @Des:自定义拦截器
  * @Author:z乘风
  * @Date:2020/5/6
  */
public class TestInterceptor implements HandlerInterceptor {

    /**
     *  作用:拦截处理程序的执行。在HandlerMapping确定适当的处理程序对象之后但在HandlerAdapter调用处理程序之前调用
     *  preHandle方法是进行处理器拦截用的,表示是否允许通过拦截,为true则允许通过,该方法为true时才会执行postHandle方法
     * ,该方法将在Controller处理之前进行调用,
     *  预处理,可以进行编码、安全控制、权限校验等处理
     *  Object handler表示拦截的对象
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    /**
     * postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之后,也就是在Controller的方法调用之后执行,
     * 但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作
     */

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("处理器处理完毕后执行");
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面)
     * Exception可以获取DispatcherServlet处理请求后抛出的异常
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("DispatcherServlet处理完毕后调用");
    }
}

4.什么是监听器?

监听器的英文是Listener,监听器liju就是监听某个对象的的状态变化的组件。

5.监听器的相关概念

事件源:被监听的对象 ——- 三个域对象 request session servletContext

监听器:监听事件源对象 事件源对象的状态的变化都会触发监听器 ——

注册监听器:将监听器与事件源进行绑定

响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 —— 程序员编写代码

6.监听器有哪些(下面列举的都是接口)?

根据被监听的对象来分:

ServletRequestListener:用于监听Request对象的操作
HttpSessionListener:用于监听web应用中的session对象,通常用于在线统计
ServletContextListener:用于监听ServletContext对象的操作,比如ServletContext对象的创建和销毁

根据被监听的内容来分:
ServletRequestAttributeListener:用于监听Request对象属性的操作
HttpSessionAttributeListener:用于监听web应用中session对象的属性操作
ServletContextAttributeListener:用于监听ServletContext对象的属性操作

实现在线统计人数案例:

package com.fly.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
  * @Des:自定义监听器,实现在线人数统计
  * @Author:z乘风
  * @Date:2020/5/6
  */
public class TestListener implements HttpSessionListener {

    private  static int count=0;

    /**
     * session创建时调用
     */
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        count++;
        System.out.println("当前在线人数为:"+count+"人");
    }

    /**
     *  session销毁时调用
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        count--;
        System.out.println("当前在线人数为:"+count+"人");
    }
}

7.创建一个全局SpringBoot mvc 配置类

WebMvcConfigurer接口是用来全局制定 Spring Boot 的 mvc 特性。开发者通过实现 WebMvcConfigurer 接口来配置应用的 MVC 全局特性

首先我先把刚刚自定义的过滤器、拦截器、监听器代码摆上
TestFilter.class

package com.fly.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 自定义过滤器
 */
public class TestFilter implements Filter {

    /**
     * 过滤器的初始化方法,在容器中创建过滤器的时候会自动调用此方法
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化过滤器");
    }

    /**
     * 当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法。
     * ServletRequest:servlet请求对象,可以通过ServletRequest获取到HttpServletRequest
     * ServletResponse:servlet响应对象,可以通过ServletResponse获取HttpServletResponse
     * FilterChain:该接口用于定义一个 Filter 链的对象应该对外提供的方法,这个接口只定义了一个 doFilter 方法
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("请求被过滤器拦截");
            //获取HttpServletRequest对象
            HttpServletRequest httpServletRequest=(HttpServletRequest) request;
            //获取请求地址
            String url=httpServletRequest.getRequestURI();
            System.out.println("请求地址是:"+url);
    }

    /**
     *  在容器中销毁当前过滤器时自动调用此方法
     */
    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

TestInterceptor.class

 package com.fly.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
  * @Des:自定义拦截器
  * @Author:z乘风
  * @Date:2020/5/6
  */
public class TestInterceptor implements HandlerInterceptor {

    /**
     *  作用:拦截处理程序的执行。在HandlerMapping确定适当的处理程序对象之后但在HandlerAdapter调用处理程序之前调用
     *  preHandle方法是进行处理器拦截用的,表示是否允许通过拦截,为true则允许通过,该方法为true时才会执行postHandle方法
     * ,该方法将在Controller处理之前进行调用,
     *  预处理,可以进行编码、安全控制、权限校验等处理
     *  Object handler表示拦截的对象
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器允许通过!");
        return true;
    }

    /**
     * postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之后,也就是在Controller的方法调用之后执行,
     * 但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作
     */

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("处理器处理完毕后执行");
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面)
     * Exception可以获取DispatcherServlet处理请求后抛出的异常
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("DispatcherServlet处理完毕后调用");

    }

}

TestListener.class

package com.fly.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
  * @Des:自定义监听器,实现在线人数统计
  * @Author:z乘风
  * @Date:2020/5/6
  */
public class TestListener implements HttpSessionListener {

    public  static Integer count=0;

    /**
     * session创建时调用
     */
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("当前在线人数为:"+count+"人");
        count++;
    }

    /**
     *  session销毁时调用
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("当前在线人数为:"+count+"人");
        count--;
    }
}

创建SpringBoot mvc配置类,WebConfig.class:

package com.fly.config;

import com.fly.filter.TestFilter;
import com.fly.interceptor.TestInterceptor;
import com.fly.listener.TestListener;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.*;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 注入过滤器注册bean
     */
    @Bean
    FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean registrationBean=new FilterRegistrationBean();
        registrationBean.setFilter(new TestFilter());
        //过滤以/开头的请求
        registrationBean.addUrlPatterns("/**");
        return  registrationBean;
    }

    /**
     * 注入监听器注册bean
     */
    @Bean
    ServletListenerRegistrationBean listenerRegistrationBean(){
        ServletListenerRegistrationBean registrationBean=new ServletListenerRegistrationBean();
        registrationBean.setListener(new TestListener());
        return registrationBean;
    }

    /**
     * 注入拦截器注册器
     * @return
     */
    @Bean
    InterceptorRegistration interceptorRegistration(){
        InterceptorRegistration registration = new InterceptorRegistration(new TestInterceptor());

        /**
         * registration.addPathPatterns():添加拦截路径
         * registration.excludePathPatterns():排除监听路径
         */
        registration.addPathPatterns("/**");
        return registration;
    }



    /**
     * 添加拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加拦截器
        registry.addInterceptor(new TestInterceptor());
    }


    /**
     * 添加跨域处理
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //允许以/**开头的url请求跨域
        registry.addMapping("/**")
                .allowedHeaders("*")
                .allowedMethods("POST","GET")
                .allowedOrigins("*");
    }

    /**
     * 添加静态资源处理
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    }

    /**
     * 页面跳转处理
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

    }

    /**
     * 默认静态资源处理器
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

    }

    /**
     * 视图解析器
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {

    }

    /**
     * 信息转换器
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

    }
}

TestController.class:

package com.fly.controller;

import com.fly.listener.TestListener;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
public class TestController {
    @RequestMapping("/test")
    public String test(){return "123";}

    @RequestMapping("/addSession")
    public String addSession(HttpServletRequest request){
        HttpSession session = request.getSession();
        session.setAttribute("name","zxp");
        return  "当前人数为:"+ TestListener.count+"人";
    }

    @RequestMapping("/removeSession")
    public String removeSession(HttpServletRequest request){
        HttpSession session = request.getSession();
        //使session无效
        session.invalidate();
        return  "当前人数为:"+ TestListener.count+"人";
    }

    @RequestMapping("/getCount")
    public String getCount(){
        return  "当前人数为:"+ TestListener.count+"人";
    }
}

测试过滤器、拦截器效果。浏览器访问localhost:8080/test 结果如下图:

过滤器、拦截器、监听器 - 图1

测试在线人数统计案例。首先用谷歌浏览器访问localhost:8080/addSession ,然后在用其他浏览器访问此接口

过滤器、拦截器、监听器 - 图2

过滤器、拦截器、监听器 - 图3

过滤器、拦截器、监听器 - 图4