【总结】SpringBoot 中过滤器、拦截器、监听器的基本使用

过滤器 Filter 与 拦截器 Interceptor

Filter 与 Interceptor 的执行顺序

在这里插入图片描述

Filter 与 Interceptor 的应用场景

过滤器对 Servlet 容器调用 service 的过程进行拦截,其基本使用场景如下:

  • 统一设置字符编码

  • 过滤敏感字符

  • 进行登录校验以及 url 级别的访问权限控制

拦截器本质上是面向切面编程 AOP,符合切面编程的关注点都可以通过拦截器来实现,其基本使用场景如下:

  • 登陆验证以及权限验证

  • 进行日志记录

  • 对 cookie 进行处理

  • 性能监控,记录请求处理时长

Filter 与 Interceptor 在 SpringBoot 中的使用

过滤器 Filter

构造过滤器,实现Filter接口,编写过滤逻辑

/**
 * 自定义过滤器1
 *
 * @author zqf
 */
public class MyFilter1 implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 进入过滤器前处理逻辑
        System.out.println("===过滤器1前处理===");
        // 执行 doFilter() 方法
        filterChain.doFilter(servletRequest, servletResponse);
        // Controller 返回之后,客户端返回之前处理逻辑
        System.out.println("===过滤器1后处理===");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

配置过滤器,对过滤器的过滤请求路径以及执行顺序进行配置,此处配置了两个过滤器,过滤逻辑完全一致

/**
 * 配置过滤器
 *
 * @author zqf
 */
@Configuration
public class FilterConfig {
    /**
     * 过滤路径
     */
    private static final String[] URLS = new String[]{"/test/filter", "/test/all"};

    @Bean("myFilter1")
    public FilterRegistrationBean<Filter> myFilter1() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(new MyFilter1());
        // 配置要应用过滤器的路径,若存在多个则传入 String[]
        registrationBean.addUrlPatterns(URLS);
        // 设置执行顺序,数值越小,越先执行,服务器返回客户端时则相反
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean("myFilter2")
    public FilterRegistrationBean<Filter> myFilter2() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(new MyFilter2());
        registrationBean.addUrlPatterns(URLS);
        registrationBean.setOrder(2);
        return registrationBean;
    }

}

拦截器 Interceptor

构造拦截器实现HandlerInterceptor接口,编写拦截逻辑

/**
 * 自定义拦截器1
 *
 * @author zqf
 */
public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * 在 controller 执行之前进行拦截,返回结果将决定后续操作是否执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 编写拦截器逻辑
        System.out.println("===拦截器1前处理===");
        return true;
    }

    /**
     * 在执行完 controller 的方法后进行拦截,可对 model 和 view 进行修改
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("===拦截器1后处理===");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 在整个请求完成之后执行,即视图渲染之后执行,若返回 json 数据则不会执行此方法
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

配置拦截器实现WebMvcConfigurer接口,配置拦截路径以及拦截顺序,此处同样配置了两个拦截逻辑相同的拦截器

/**
 * 配置拦截器
 *
 * @author zqf
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 拦截路径
        String[] urls = new String[]{"/test/interceptor", "/test/all"};
        // 配置自定义的拦截器,配置路径以及顺序
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns(urls).order(1);
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns(urls).order(2);
    }
}

测试 Filter/Interceptor

编写控制器进行测试

/**
 * @author zqf
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/filter")
    public String testFilter() {
        System.out.println("===执行 controller===");
        System.out.println("===调用 service 进行业务处理===");
        System.out.println("===执行 return===");
        return "测试过滤器~";
    }

    @GetMapping("/interceptor")
    public String testInterceptor() {
        System.out.println("===执行 controller===");
        System.out.println("===调用 service 进行业务处理===");
        System.out.println("===执行 return===");
        return "测试拦截器~";
    }

    @GetMapping("/all")
    public String testAll() {
        System.out.println("===执行 controller===");
        System.out.println("===调用 service 进行业务处理===");
        System.out.println("===执行 return===");
        return "测试过滤器and拦截器~";
    }

}

过滤器 Filter 测试结果

在这里插入图片描述
拦截器 Interceptor 测试结果
在这里插入图片描述
同时测试,验证过滤器和拦截器的执行顺序

在这里插入图片描述

监听器 Litener

Listener 的应用场景

监听器是 Servlet 中的类,可以帮助我们监听 web 中的特定事件,比如ServletContextHttpSessionServletRequest的创建和销毁或者变量的创建、销毁和修改,其使用场景主要包括:

  • 监听 Servlet 进行数据的初始化

  • 监听 HttpSession 获取实时在线人数

  • 监听客户端请求的 ServletRequest 对象以获取用户的访问信息

Listener 在 SpringBoot 中的使用

新建一个 User 实体类,模拟从数据库查询到数据的过程

/**
 * 实体类
 *
 * @author zqf
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String username;

    private String password;

}

构造自定义事件继承ApplicationEvent

/**
 * 自定义事件
 *
 * @author zqf
 */
public class MyEvent extends ApplicationEvent {

    private User user;

    public MyEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }

}

构造自定义监听器继承ApplicationListener,编写监听事件发生后的处理逻辑

/**
 * 自定义事件监听器
 *
 * @author zqf
 */
@Component
public class MyListener implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        // 监听到相应事件后的处理逻辑
        User user = myEvent.getUser();
        System.out.println("监听到事件发生>>> User 对象创建");
        System.out.println("username>>>  " + user.getUsername());
        System.out.println("password>>>  " + user.getPassword());
    }
}

测试 Listener

利用 SpringBoot 定时任务定时发布事件,查看监听器监听到事件后的处理,记得在启动类上允许定时任务@EnableScheduling

/**
 * @author zqf
 */
@Service
public class ListenerService {

    @Resource
    private ApplicationContext applicationContext;

    /**
     * 定时任务模拟时间发生进行测试
     *
     * 5s 执行一次
     */
    @Scheduled(cron = "*/10 * * * * ?")
    public void testListenerEvent() {
        // 模拟事件发生
        System.out.println("模拟事件发生>>> User 对象创建");
        User user = User.builder()
                .username("test" + Math.random())
                .password("123@qq.com")
                .build();
        // 手动发布事件
        MyEvent myEvent = new MyEvent(this, user);
        applicationContext.publishEvent(myEvent);
    }

}

监听器测试结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值