SpringBoot实现拦截器、过滤器、监听器过程解析

这篇文章主要介绍了SpringBoot实现拦截器、过滤器、监听器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

过滤器

过滤器简介

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

过滤器的使用

首先需要实现 Filter接口然后重写它的三个方法

  • init 方法:在容器中创建当前过滤器的时候自动调用
  • destory 方法:在容器中销毁当前过滤器的时候自动调用
  • doFilter 方法:过滤的具体操作

我们先引入 Maven 依赖,其中 lombok 是用来避免每个文件创建 Logger 来打印日志

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

我们首先实现接口,重写三个方法,对包含我们要求的四个请求予以放行,将其它请求拦截重定向至/online,只要在将MyFilter实例化后即可,我们在后面整合代码中一起给出。

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

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

@Log4j2
public class MyFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    log.info("初始化过滤器");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest)servletRequest;
    HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) response);
    String requestUri = request.getRequestURI();
    log.info("请求地址是:"+requestUri);
    if (requestUri.contains("/addSession")
      || requestUri.contains("/removeSession")
      || requestUri.contains("/online")
      || requestUri.contains("/favicon.ico")) {
      filterChain.doFilter(servletRequest, response);
    } else {
      wrapper.sendRedirect("/online");
    }
  }

  @Override
  public void destroy() {
    //在服务关闭时销毁
    log.info("销毁过滤器");
  }
}

拦截器

拦截器介绍

Java中的拦截器是动态拦截 action 调用的对象,然后提供了可以在 action 执行前后增加一些操作,也可以在 action 执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。

  • 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面,当然大型项目中都不采用这种方式,都是调单点登录系统接口来验证用户。
  • 记录系统日志:我们在常见应用中,通常要记录用户的请求信息,比如请求 ip,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算 PV、性能调优等。
  • 通用处理:在应用程序中可能存在所有方法都要返回的信息,这是可以利用拦截器来实现,省去每个方法冗余重复的代码实现。

使用拦截器

我们需要实现 HandlerInterceptor 类,并且重写三个方法

  • preHandle:在 Controoler 处理请求之前被调用,返回值是 boolean类型,如果是true就进行下一步操作;若返回false,则证明不符合拦截条件,在失败的时候不会包含任何响应,此时需要调用对应的response返回对应响应。
  • postHandler:在 Controoler 处理请求执行完成后、生成视图前执行,可以通过ModelAndView对视图进行处理,当然ModelAndView也可以设置为 null。
  • afterCompletion:在 DispatcherServlet 完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Log4j2
@Component
public class MyInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("【MyInterceptor】调用了:{}", request.getRequestURI());
    request.setAttribute("requestTime", System.currentTimeMillis());
    return true;
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response,
              Object handler, ModelAndView modelAndView) throws Exception {
    if (!request.getRequestURI().contains("/online")) {
      HttpSession session = request.getSession();
      String sessionName = (String) session.getAttribute("name");
      if ("haixiang".equals(sessionName)) {
        log.info("【MyInterceptor】当前浏览器存在 session:{}",sessionName);
      }
    }
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                Object handler, Exception ex) throws Exception {
    long duration = (System.currentTimeMillis() - (Long)request.getAttribute("requestTime"));
    log.info("【MyInterceptor】[{}]调用耗时:{}ms",request.getRequestURI(), duration);
  }
}

监听器

监听器简介

监听器通常用于监听 Web 应用程序中对象的创建、销毁等动作的发送,同时对监听的情况作出相应的处理,最常用于统计网站的在线人数、访问量等。

监听器大概分为以下几种:

  • ServletContextListener:用来监听 ServletContext 属性的操作,比如新增、修改、删除。
  • HttpSessionListener:用来监听 Web 应用种的 Session 对象,通常用于统计在线情况。
  • ServletRequestListener:用来监听 Request 对象的属性操作。

监听器的使用

我们通过 HttpSessionListener来统计当前在线人数、ip等信息,为了避免并发问题我们使用原子int来计数。

ServletContext,是一个全局的储存信息的空间,它的生命周期与Servlet容器也就是服务器保持一致,服务器关闭才销毁。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。因此我们这里用ServletContext来存储在线人数sessionCount最为合适。

我们下面来统计当前在线人数

import lombok.extern.log4j.Log4j2;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.concurrent.atomic.AtomicInteger;

@Log4j2
public class MyHttpSessionListener implements HttpSessionListener {

  public static AtomicInteger userCount = new AtomicInteger(0);

  @Override
  public synchronized void sessionCreated(HttpSessionEvent se) {
    userCount.getAndIncrement();
    se.getSession().getServletContext().setAttribute("sessionCount", userCount.get());
    log.info("【在线人数】人数增加为:{}",userCount.get());

    //此处可以在ServletContext域对象中为访问量计数,然后传入过滤器的销毁方法
    //在销毁方法中调用数据库入库,因为过滤器生命周期与容器一致
  }

  @Override
  public synchronized void sessionDestroyed(HttpSessionEvent se) {
    userCount.getAndDecrement();
    se.getSession().getServletContext().setAttribute("sessionCount", userCount.get());
    log.info("【在线人数】人数减少为:{}",userCount.get());
  }
}

过滤器、拦截器、监听器注册

实例化三器

import com.anqi.tool.sanqi.filter.MyFilter;
import com.anqi.tool.sanqi.interceptor.MyInterceptor;
import com.anqi.tool.sanqi.listener.MyHttpRequestListener;
import com.anqi.tool.sanqi.listener.MyHttpSessionListener;
import org.springframework.beans.factory.annotation.Autowired;
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.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
  @Autowired
  MyInterceptor myInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(myInterceptor);
  }

  /**
   * 注册过滤器
   * @return
   */
  @Bean
  public FilterRegistrationBean filterRegistrationBean(){
    FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
    filterRegistration.setFilter(new MyFilter());
    filterRegistration.addUrlPatterns("/*");
    return filterRegistration;
  }

  /**
   * 注册监听器
   * @return
   */
  @Bean
  public ServletListenerRegistrationBean registrationBean(){
    ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean();
    registrationBean.setListener(new MyHttpRequestListener());
    registrationBean.setListener(new MyHttpSessionListener());
    return registrationBean;
  }
}

测试

import com.anqi.tool.sanqi.listener.MyHttpSessionListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class TestController {

  @GetMapping("addSession")
  public String addSession(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.setAttribute("name", "haixiang");
    return "当前在线人数" + session.getServletContext().getAttribute("sessionCount") + "人";
  }

  @GetMapping("removeSession")
  public String removeSession(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.invalidate();
    return "当前在线人数" + session.getServletContext().getAttribute("sessionCount") + "人";
  }

  @GetMapping("online")
  public String online() {
    return "当前在线人数" + MyHttpSessionListener.userCount.get() + "人";
  }

}

以下是监听请求的监听器

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;

public class MyHttpRequestListener implements ServletRequestListener {

  @Override
  public void requestDestroyed(ServletRequestEvent sre) {
    System.out.println("request 监听器被销毁");
  }

  @Override
  public void requestInitialized(ServletRequestEvent sre) {
    HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
    String requestURI = req.getRequestURI();
    System.out.println(requestURI+"--"+"被调用");
  }
}

拦截器与过滤器的区别

1.参考标准

  • 过滤器是 JavaEE 的标准,依赖于 Servlet 容器,生命周期也与容器一致,利用这一特性可以在销毁时释放资源或者数据入库。
  • 拦截器是SpringMVC中的内容,依赖于web框架,通常用于验证用户权限或者记录日志,但是这些功能也可以利用 AOP 来代替。

2.实现方式

  • 过滤器是基于回调函数实现,无法注入 ioc 容器中的 bean。
  • 拦截器是基于反射来实现,因此拦截器中可以注入 ioc 容器中的 bean,例如注入 Redis 的业务层来验证用户是否已经登录。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot配置拦截器及实现跨域访问的方法

    拦截器功能强大,能够深入方法前后,常应用于日志记录.权限检查和性能检测等,几乎是项目中不可或缺的一部分,本文就来实现Spring Boot自定义拦截器的配置. 理论指导 问:Spring Boot怎么配置拦截器? 答:配置一个拦截器需要两步完成. 自定义拦截器,实现HandlerInterceptor这个接口.这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,afterCompletion是

  • spring boot设置过滤器、监听器及拦截器的方法

    前言 其实这篇文章算不上是springboot的东西,我们在spring普通项目中也是可以直接使用的 设置过滤器: 以前在普通项目中我们要在web.xml中进行filter的配置,但是只从servlet 3.0后,我们就可以在直接在项目中进行filter的设置,因为她提供了一个注解@WebFilter(在javax.servlet.annotation包下),使用这个注解我们就可以进行filter的设置了,同时也解决了我们使用springboot项目没有web.xml的尴尬,使用方法如下所示 @

  • Spring boot项目中异常拦截设计和处理详解

    背景: 项目运行过程中会出现各种各样的问题,常见的有以下几种情况: 业务流程分析疏漏,对业务流程的反向操作.边界分析设计不充分 调用外部服务.调用外部系统出现的超时.错误.返回值与预期不符 外部资源连通性问题,db等服务器出现的网络抖动或宕机 无论是分析设计.开发.测试.线上都需要能够准确定位问题并制定解决方案. 目的: 规范化异常的处理过程,避免异常被吞和到处都在捕获异常的情况 准确的反馈异常信息,为定位问题提供依据 通用性异常全局处理,降低业务开发关注度 对异常情况进行预警,以便能够及时响应

  • 详解SpringBoot开发使用@ImportResource注解影响拦截器

    问题描述 今天在给SpringBoot项目配置拦截器的时候发现怎么都进不到拦截器的方法里面,在搜索引擎上看了无数篇关于配置拦截器的文章都没有找到解决方案. 就在我准备放弃的时候,在 CSDN 上发现了一篇文章,说的是SpringBoot 用了@ImportResource 配置的拦截器就不起作用了.于是我就赶紧到Application启动类看了一眼,果然项目中使用了@ImportResource 注解用于配置系统的参数. 代码如下: 启动类配置 package com.xx.xxx; impor

  • Springboot项目使用拦截器方法详解

    1. 创建一个拦截器并实现HandlerInterceptor接口 package com.leiyuan.bs.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.h

  • SpringBoot定义过滤器、监听器、拦截器的方法

    一.自定义过滤器 创建一个过滤器,实现javax.servlet.Filter接口,并重写其中的init.doFilter.destory方法. package com.example.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.Se

  • SpringBoot拦截器实现登录拦截的方法示例

    源码 GitHub:https://github.com/291685399/springboot-learning/tree/master/springboot-interceptor01 SpringBoot拦截器可以做什么 可以对URL路径进行拦截,可以用于权限验证.解决乱码.操作日志记录.性能监控.异常处理等 SpringBoot拦截器实现登录拦截 pom.xml: <?xml version="1.0" encoding="UTF-8"?> &

  • 解决Spring boot2.0+配置拦截器拦截静态资源的问题

    第一次遇到这个问题的时候,简直是一脸蒙逼,写了一个拦截器以后,静态资源就不能访问了,到处查找才知道是版本问题 解决办法: 第一步:定义一个类实现 实现WebMvcConfigurer的类中拦截器中添加放行资源处添加静态资源文件路径: @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(sessionInterceptor).addPathPatterns("/&

  • springboot注册拦截器所遇到的问题

    问题1 springboot注册拦截器过滤器方法 注册拦截器:在启动类中注册bean @EnableWebMvc @Configuration static class MvcConfigurer implements WebMvcConfigurer { //在拦截器中需要使用这个bean,如果直接在拦截器中注入的话会失败,所以选择有参构造的方式传入 @Autowired CacheService cacheService; @Override public void addIntercept

  • SpringBoot实现拦截器、过滤器、监听器过程解析

    这篇文章主要介绍了SpringBoot实现拦截器.过滤器.监听器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 过滤器 过滤器简介 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术.如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 Session 校验,判断用户权限,如果不符合设定条件,则会被拦截到特殊的地址或者基于特殊的响应. 过滤器的使用 首

  • SpringBoot 过滤器、拦截器、监听器对比及使用场景分析

    一.关系图理解 二.区别 1.过滤器 过滤器是在web应用启动的时候初始化一次, 在web应用停止的时候销毁 可以对请求的URL进行过滤, 对敏感词过滤 挡在拦截器的外层 实现的是 javax.servlet.Filter 接口 ,是 Servlet 规范的一部分 在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后 依赖Web容器 会多次执行 过滤器简介 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术.如同它的名字一样,过滤器

  • SpringBoot使用过滤器、拦截器和监听器的案例代码(Springboot搭建java项目)

    目录 SpringBoot使用过滤器.拦截器和监听器 一.SpringBoot使用过滤器 Spring boot过滤器的使用(两种方式) 方式一: 方式二: 二.SpringBoot使用拦截器 三.过滤器和拦截器的执行顺序 四.SpringBoot使用监听器 1.统计网站最多在线人数监听器的例子 2.springboot监听器的使用(以实现异步Event监听为例子) SpringBoot使用过滤器.拦截器和监听器 一.SpringBoot使用过滤器 Spring boot过滤器的使用(两种方式)

  • springboot创建拦截器过程图解

    这篇文章主要介绍了springboot创建拦截器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.创建一个MyIntercepor实现HandlerInterceptor接口的类 二.创建一个WebMvcConfig实现WebMvcConfigurer的类 三.创建Controller以供访问 四.效果图 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • SpringBoot配置拦截器实现过程详解

    目录 如何配置拦截器 拦截器设置容易出现的问题 如何取消拦截操作 实例-登录验证 如何配置拦截器 step1: 自定义拦截器 /** * 自定义拦截器 */ public class MyInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class); /** * 在请求匹配controller之前执行,返回t

  • Spring Boot拦截器和过滤器实例解析

    这篇文章主要介绍了Spring Boot拦截器和过滤器实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想.在面向对象编程的过程中,我们很容易通过继承.多态来解决纵向扩展. 但是对于横向的功能,比如,在所

  • 解决SpringBoot自定义拦截器和跨域配置冲突的问题

    目录 SpringBoot自定义拦截器和跨域配置冲突 技术栈 问题引出 原代码 新代码 SpringBoot 拦截器和addCorsMappings冲突 SpringBoot自定义拦截器和跨域配置冲突 技术栈 vue-cli3,springboot 2.3.2.RELEASE 问题引出 在做毕业设计过程中用到了自定义拦截器验证登录.同时在springboot配置类中设置了跨域问题,出现跨域失败的情况. 原代码 @Configuration public class WebConfig exten

  • springboot config 拦截器使用方法实例详解

    本文介绍Spring-Boot中使用拦截器,一般在拦截器中处理跨域处理,允许跨域访问项目,拦截器使用详细资料请查阅官网. 实现自定义拦截器步骤: 1.创建一个类并实现HandlerInterceptor接口. 2.创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法. 2.将自定义的拦截器交由spring管理,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加). 创建拦截器类 package com.exam

  • Python自定义计算时间过滤器实现过程解析

    这篇文章主要介绍了Python自定义计算时间过滤器实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在写自定义的过滤器时,因为django.template.Library.filter()本身可以作为一个装饰器,所以可以使用: register = django.template.Library() @register.filter 代替 register.filter("过滤器名","函数名") 如果

随机推荐