SpringBoot整合Web过滤器、监听器、拦截器

SpringBoot整合Web过滤器、监听器、拦截器_第1张图片

一、过滤器

过滤器是一个基于Servlet的程序,它先于Servlet或JSP执行,因此常常被用作请求前的信息检查,修改编码,重定向请求路径等功能。
SpringBoot整合Web过滤器、监听器、拦截器_第2张图片
SpringBoot定义一个web过滤器只需要其继承HttpFilter类,并在类上使用@WebFilter注解声明过滤路径。

@Slf4j
@WebFilter("/*") // 过滤器路径
public class MessageFilter extends HttpFilter {

    public void doFilter(HttpServletRequest request, HttpServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        log.info("[MessageFilter] 请求地址:" + request.getRequestURI());
        chain.doFilter(request, response);
    }

}

由于SpringBoot默认采用内嵌的tomcat,所以需要在启动类上添加@ServletComponentScan注解进行web组件的扫描。

@SpringBootApplication
@ServletComponentScan // 扫描Servlet组件
public class StartSpringBoot {
    public static void main(String[] args) {
        SpringApplication.run(StartSpringBoot.class, args);
    }
}

通过浏览器访问:http://localhost:8080/hello
SpringBoot整合Web过滤器、监听器、拦截器_第3张图片
发现控制台打出过滤器日志,说明过滤器配置成功:
在这里插入图片描述

在实际的项目开发中,一个访问路径前可能存在多个过滤器组成的过滤链。传统的Java WEB项目会有一个web.xml的配置文件,可以在其中配置过滤器的过滤路径,如果一个访问路径在多个过滤器的过滤路径下,那么过滤器的执行顺序就和配置文件的编写顺序有关了:

  
  <filter>
    <filter-name>Filter1filter-name>
    <filter-class>com.it.filter.Filter1filter-class>
  filter>
  <filter-mapping>
    <filter-name>Filter1filter-name>
    <url-pattern>/*url-pattern> 
  filter-mapping>
  
  <filter>
    <filter-name>Filter2filter-name>
    <filter-class>com.it.filter.Filter2filter-class>
  filter>
  <filter-mapping>
    <filter-name>Filter2filter-name>
    <url-pattern>/*url-pattern> 
  filter-mapping>

以上面的配置为例,如果要访问:http://localhost:8080/hello,那么一定会是以下的顺序:

浏览器
Filter1
Filter2
处理请求的Action

而SpringBoot的目标就是减少传统java web项目繁杂的配置文件,配置信息可以在application.yml中编写,也可以自定义配置类,通过代码的方式进行配置。
删除MessageFilter类上的@WebFilter注解:

@Slf4j
public class MessageFilter extends HttpFilter {

    public void doFilter(HttpServletRequest request, HttpServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        log.info("[MessageFilter] 请求地址:" + request.getRequestURI());
        chain.doFilter(request, response);
    }

}

再编写一个ValidateFilter:

@Slf4j
public class ValidateFilter extends HttpFilter {
    public void doFilter(HttpServletRequest request, HttpServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        log.info("[ValidateFilter] 请求地址:" + request.getRequestURI());
        chain.doFilter(request, response);
    }
}

编写一个配置类控制Filter的执行顺序:

@Configuration
public class WebFilterConfig {

    /**
     * 配置MessageFilter的执行顺序
     * @return FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean getMessageRegistration() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MessageFilter()); // 过滤器类实例对象
        filterRegistrationBean.setName("MessageFilter"); // 过滤器名
        filterRegistrationBean.addUrlPatterns("/*"); // 过滤路径
        filterRegistrationBean.setOrder(2); // 执行顺序
        return filterRegistrationBean;
    }
    
    @Bean
    public FilterRegistrationBean getValidateRegistration() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new ValidateFilter());
        filterRegistrationBean.setName("ValidateFilter");
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(5);
        return filterRegistrationBean;
    }
}

通过FilterRegistrationBean 类的order属性可以指定过滤器的执行顺序,order值越小则越先执行。
直接访问:http://localhost:8080/发现ValidateFilter比MessageFilter先执行。
在这里插入图片描述

二、监听器

监听器就是监听某个对象的的状态变化的组件,按照被监听的对象可划分为:ServletRequest域 、HttpSession域、 ServletContext域。按照监听的内容可分为:域对象的创建与销毁、域对象的属性变化。

ServletRequest ServletRequest ServletRequest
域对象的创建与销毁 ServletContextListener HttpSessionListener ServletRequestListener
域对象的属性变化 ServletContextAttributeListener HttpSessionAttributeListener ServletRequestAttributeListener

以监听Servlet初始化为例,定义一个监听器类并实现ServletContextListener接口,在类上添加@WebListener注解。

@Slf4j
@WebListener
public class DefaultServletListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent sce) {
        log.info("[DefaultServletListener] " + sce.getServletContext().getServerInfo());
        log.info("[DefaultServletListener] " + sce.getServletContext().getRealPath("/"));
        log.info("[DefaultServletListener] " + sce.getServletContext().getVirtualServerName());
    }
}

由于使用了@WebListener注解,所以需要在SpringBoot启动类上添加@ServletComponentScan注解扫描Servlet组件。

@SpringBootApplication
@ServletComponentScan({"com.it.listener"})
public class StartSpringBoot {
    public static void main(String[] args) {
        SpringApplication.run(StartSpringBoot.class, args);
    }
}

启动项目,发现Servlet初始化监听生效:

在这里插入图片描述

三、拦截器

拦截器是基于java反射机制实现的java程序,其不依赖于Servlet 容器,通常用于service层方法调用前后的处理。
SpringBoot整合Web过滤器、监听器、拦截器_第4张图片

值得注意的是:

  1. 拦截器是基于 java 的反射机制的,因此拦截器可以访问 action 上下文、值栈里的对象,而过滤器是基于函数回调,不能访问。
  2. 拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用。

SpringBoot整合拦截器只需要实现HandlerInterceptor接口。

@Slf4j
public class DefaultInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        log.info("------------------------------   DefaultInterceptor   ------------------------------");
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            log.info("[控制器实例]" + handlerMethod.getBean());
            log.info("[控制器类型]" + handlerMethod.getBeanType());
            log.info("[控制器方法]" + handlerMethod.getMethod());
        }
        log.info("------------------------------------------------------------------------------------");
        return true;
    }
}

定义好的拦截器需要在配置类中进行启用。

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    /**
     * 注册拦截器
     * @param registry InterceptorRegistry
     */
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getDefaultInterceptor()) // 添加拦截器
                .addPathPatterns("/**"); // 配置拦截器路径
    }

    @Bean
    public HandlerInterceptor getDefaultInterceptor() {
        return new DefaultInterceptor();
    }
}

启动项目,访问任意Action类:
在这里插入图片描述

四、AOP拦截器

基于AspectJ切面表达式实现的AOP处理是Spring的一个重要特性,AOP拦截器可以直接进行指定类结构的拦截处理。
SpringBoot如果想要使用AOP,则需要添加依赖支持:

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-aopartifactId>
    <version>2.5.5version>
dependency>

新建IMessageService业务层接口和实现类:

public interface IMessageService {
    String echo(String message);
}
public class MessageServiceImpl implements IMessageService {
    @Override
    public String echo(String message){
        return "[echo] : " + message;
    }
}

再aspect包下新建ServiceAspect类并配置业务层环绕拦截。

@Slf4j
@Aspect
@Component
public class ServiceAspect { // AOP切面管理
    /**
     * service环绕切面
     * @param point
     * @throws Throwable
     */
    @Around("execution(* *..service..*.*(..))") // 配置所有service生效
    public Object aroundInvoke(ProceedingJoinPoint point) throws Throwable {
        log.info("[invoke before] " + Arrays.toString(point.getArgs()));
        Object obj = point.proceed(point.getArgs()); // 调用真实业务
        log.info("[invoke after] return: " + obj);
        return obj; // 业务执行的结果
    }
}

新建RestController测试AOP拦截结果:

@RestController
@RequestMapping("/message/*")
public class MessageAction {
    private final IMessageService messageService;

    public MessageAction(IMessageService messageService) {
        this.messageService = messageService;
    }

    @RequestMapping("/get")
    public String getMessage(String message) {
        return messageService.echo(message);
    }
}

访问:http://localhost:8080/message/get?message=hello,查看控制台日志:

在这里插入图片描述

你可能感兴趣的