Spring Boot 系列:过滤器+拦截器+监听器
原
Swagger
文章合并到 Spring Boot 系列:配置 Swagger2
一、过滤器 - Filter
过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求。
1.1 过滤器介绍
过滤器依赖于
Servlet
容器
过滤器可以拦截到方法的请求和响应(ServletRequest request
, ServletResponse response
),并对请求/响应做出过滤操作。
1.2 过滤器用途
用来做一些过滤操作,获取我们想要获取的数据:
- 在过滤器中修改字符编码;
- 在过滤器中修改
HttpServletRequest
的一些参数,包括:过滤低俗文字、危险字符等; - 用作
Session
校验,判断用户权限。
一个过滤器实例只能在容器初始化时调用一次。
1.3 过滤器的使用
Filter
随Web
应用的启动而启动,只初始化一次,随Web
应用的停止而销毁。
- 启动服务器时加载过滤器的实例,并调用
init()
方法来初始化实例; - 每一次请求时都只调用方法
doFilter()
进行处理; - 停止服务器时调用
destroy()
方法,销毁实例。
1.4 示例代码
首先需要实现 Filter.java
接口然后重写它的三个方法,对包含我们要求的请求予以放行,将其它请求拦截并重定向。
@Slf4j
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 启动服务器时加载log.info("MyFilter init()");}// 每次请求都会调用该方法@Overridepublic 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("/getUserCount")) {filterChain.doFilter(servletRequest, response);} else {// 除了以上三个链接,其他请求转发到 /redirectUrlwrapper.sendRedirect("/redirectUrl");}}@Overridepublic void destroy() {// 在服务关闭时销毁log.info("MyFilter destroy()");}
}
二、拦截器
Java
中的拦截器是动态拦截 Action
调用的对象,然后提供了可以在 Action
执行前后增加一些操作,也可以在 Action
执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。
2.1 拦截器介绍
依赖于 Web
框架,在 Spring
中依赖于 SpringMVC
框架。在实现上,基于 Java
的反射机制,属于面向切面编程(AOP
)的一种运用,就是在一个方法前,调用一个方法,或者在方法后,调用一个方法。
2.2 拦截器的用途
- 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面;
- 记录系统日志:记录用户的请求信息,如请求
Ip
,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算PV
、性能调优等; - 通用处理:如将接口封装成统一结果集返回。
2.3 拦截器的使用
我们需要实现 HandlerInterceptor
类,并且重写三个方法
preHandle()
:在Controoler
处理请求之前被调用,返回值是boolean
类型,如果是true
就进行下一步操作;若返回false
,则证明不符合拦截条件。在失败的时候不会包含任何响应,此时需要调用对应的response
返回对应响应;postHandler()
:在Controoler
处理请求执行完成后、生成视图前执行,可以通过ModelAndView
对视图进行处理,当然ModelAndView
也可以设置为null
;afterCompletion()
:在DispatcherServlet
完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。
2.4 示例代码
@Component
@Slf4j
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("【MyInterceptor】调用了:{}", request.getRequestURI());request.setAttribute("requestTime", System.currentTimeMillis());return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView modelAndView) throws Exception{if (!request.getRequestURI().contains("/getUserCount")) {HttpSession session = request.getSession();String sessionName = (String) session.getAttribute("name");if ("Van".equals(sessionName)) {log.info("【MyInterceptor】当前浏览器存在 session:{}",sessionName);}}}@Overridepublic 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);}
}
- 当
Controoler
内部有异常,posthandler
方法是不会执行的; - 不管
Controoler
内部是否有异常,都会执行afterCompletion
方法;此方法还会有个Exception ex
这个参数;如果有异常,ex
会有异常值;没有异常 此值为null
; - 如果
Controoler
内部有异常,但异常被@ControllerAdvice
异常统一捕获的话,ex
也会为null
。
三、监听器
3.1 监听器介绍
监听器通常用于监听 Web
应用程序中对象的创建、销毁等动作的发送,同时对监听的情况作出相应的处理,最常用于统计网站的在线人数、访问量等。
3.2 监听器的用途
大概分为以下几种:
ServletContextListener
:用来监听ServletContext
属性的操作,比如新增、修改、删除;HttpSessionListener
:用来监听Web
应用中的Session
对象,通常用于统计在线情况;ServletRequestListener
:用来监听Request
对象的属性操作。
3.3 监听器的使用
HttpSessionListener
通常用来统计当前在线人数、ip
等信息,为了避免并发问题我们使用AtomicInteger
来计数。
ServletContext
是一个全局的储存信息的空间,它的生命周期与 Servlet
容器也就是服务器保持一致,服务器关闭才销毁。request
,一个用户可有多个;session
,一个用户一个;而 ServletContext
,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext
中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。因此我们用 ServletContext
来存储在线人数最为合适。
3.4 示例代码
@Slf4j
public class MyHttpSessionListener implements HttpSessionListener {/*** 在线人数*/public static AtomicInteger userCount = new AtomicInteger(0);@Overridepublic synchronized void sessionCreated(HttpSessionEvent se) {userCount.getAndIncrement();se.getSession().getServletContext().setAttribute("sessionCount", userCount.get());log.info("【在线人数】人数增加为:{}",userCount.get());}@Overridepublic synchronized void sessionDestroyed(HttpSessionEvent se) {userCount.getAndDecrement();se.getSession().getServletContext().setAttribute("sessionCount", userCount.get());log.info("【在线人数】人数减少为:{}",userCount.get());}
}
Spring Boot
中监听器也可通过实现ApplicationListener
接口实现,这里就不演示了。
四、过滤器、拦截器、监听器
4.1 过滤器与拦截器的区别
1. 参考标准
- 过滤器是
JavaEE
的标准,依赖于Servlet
容器,生命周期也与容器一致,利用这一特性可以在销毁时释放资源或者数据入库; - 拦截器是
SpringMVC
中的内容,依赖于Web
框架,通常用于验证用户权限或者记录日志,但是这些功能也可以利用AOP
来代替。
2. 实现方式
- 过滤器是基于回调函数实现,无法注入
IOC
容器; - 拦截器是基于反射来实现,因此拦截器中可以注入
IOC
容器中。
4.2 实例化三器
@Configuration
public class WebConfig implements WebMvcConfigurer {@ResourceMyInterceptor myInterceptor;/*** 注册过滤器* @return*/@Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean filterRegistration = new FilterRegistrationBean();filterRegistration.setFilter(new MyFilter());filterRegistration.addUrlPatterns("/*");return filterRegistration;}/*** 注册拦截器* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor);}/*** 注册监听器* @return*/@Beanpublic ServletListenerRegistrationBean registrationBean(){ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean();registrationBean.setListener(new MyHttpSessionListener());return registrationBean;}
}
4.3 测试接口
@RestController
@RequestMapping("")
public class TestController {/*** 增加在线人数* @param request*/@GetMapping("/addSession")public void addSession(HttpServletRequest request) {HttpSession session = request.getSession();session.setAttribute("name", "Van");}/*** 减少在线人数* @param request*/@GetMapping("/removeSession")public void removeSession(HttpServletRequest request) {HttpSession session = request.getSession();session.invalidate();}/*** 统计在线人数* @return*/@GetMapping("/getUserCount")public String getUserCount() {return "当前在线人数" + MyHttpSessionListener.userCount.get() + "人";}/*** 重定向的地址* @return*/@GetMapping("/redirectUrl")public String redirectUrl() {return "欢迎关注:风尘博客!";}}
五、测试
- 启动项目,过滤器成功加载:
...
cn.van.fil.filter.MyFilter : MyFilter init()
....
5.1 查看在线人数
- 接口链接
http://localhost:8080/getUserCount
- 返回结果:
当前在线人数0人
- 控制台日志:
c.v.fil.listener.MyHttpRequestListener : 接口:/getUserCount被调用
cn.van.fil.filter.MyFilter : 本次请求地址是:/getUserCount
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】调用了:/getUserCount
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】[/getUserCount]调用耗时:1ms
c.v.fil.listener.MyHttpRequestListener : request 监听器被销毁
5.2 增加在线人数
- 接口链接
http://localhost:8080/addSession
无返回结果:
控制台日志:
cn.van.fil.filter.MyFilter : 本次请求地址是:/addSession
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】调用了:/addSession
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】当前浏览器存在 session:Van
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】[/addSession]调用耗时:16ms
5.3 再次请求 5.1
查看在线人数接口
当前在线人数1人
- 控制台日志:
cn.van.fil.filter.MyFilter : 本次请求地址是:/getUserCount
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】调用了:/getUserCount
cn.van.fil.interceptor.MyInterceptor : 【MyInterceptor】[/getUserCount]调用耗时:2ms
5.4 减少在线人数
http://localhost:8080/removeSession
六、总结
Github 示例代码
参考文章:SpringBoot使用拦截器、过滤器、监听器
6.1 日常求赞
博主祖传秘籍 Spring Boot 葵花宝典 开源中,欢迎前来吐槽,提供线索,告诉博主接下来更新哪方面文章,共同进步!
6.2 文化交流
- 风尘博客
- 风尘博客-掘金
- 风尘博客-博客园
- 风尘博客-CSDN
- Github
最新文章,欢迎关注:公众号-风尘博客;交流观点,欢迎添加:个人微信
Spring Boot 系列:过滤器+拦截器+监听器相关推荐
- Spring Boot实战:拦截器与过滤器
一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...
- Spring Boot 实现登录拦截器,这才是正确的姿势!!
原文:https://blog.csdn.net/qq_27198345/article/details/111401610 对于管理系统或其他需要用户登录的系统,登录验证都是必不可少的环节,在Spr ...
- java web 过滤器 拦截器 监听器_Java中的拦截器和过滤器,可不是同一个东西
过滤器(Filter) 过滤器就如上面的水质过滤器一样,把管道中的水进行一遍过滤再使用.过滤器基于filter接口中的doFilter回调函数,主要的用途是设置字符集.控制权限.控制转向.做一些业务逻 ...
- Spring Boot笔记-设置拦截器为false时返回的Body
以preHandle拦截器为例: @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse ...
- Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理
Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理 参考文章: (1)Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理 ( ...
- spring 两次进入拦截器_过滤器和拦截器的 6 个区别,别再傻傻分不清了
点击上方 肉眼品世界,选择 设为星标 深度价值体系传递 作者 :程序员内点事 来源 :toutiao.com/i6834310440495874563 毕竟这两种工具开发中用到的频率都相当高,应用起来 ...
- Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用
转载自 https://www.cnblogs.com/EasonJim/p/7704740.html 一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filt ...
- 国内最全的Spring Boot系列之二
历史文章 <国内最全的Spring Boot系列之一> 视频&交流平台 SpringBoot视频:http://t.cn/R3QepWG Spring Cloud视频:http:/ ...
- Spring AOP原理及拦截器
原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充. AOP将应用系统分为两部分,核心业务逻辑(Core bu ...
最新文章
- 我们常称自己“码农”,这次已得到官方认定:“新生代农民工!
- lvm扩张与收缩小结
- 微服务已过时!DDD领域建模与架构设计才是未来!
- linux用户管理类常用命令:
- 基于java mail实现简单的QQ邮箱发送邮件
- 首尾相接数组求子数组最大和
- wtforms Form实例化流程(源码解析)
- QA: 自闭合标签要不要手动闭合?
- 随机抽样方法正太分布 MC, MCMC, Gibbs采样 原理实现(in R)
- 企业微信最全17种获客+4种自动转化玩法
- 英语单词发音中/s/后的/p/,/t/,/k//tr/什么时候读作/b/,/d/,/g/,/dr/?
- win32.mak下载地址github
- 微信小程序 教你如何复制页面路径 (以及京东、虎牙、苏宁、拼多多、等大厂的加密路径详解)(多图!!!)
- Apache 301转向技巧
- 基于51单片机万年历
- 哪里东西更便宜?读《卧底经济学(珍藏版)》
- 题目:输入一个8bit数,输出其中1的个数,只能使用1bit全加器
- 水的黏度 Viscosity of Water
- (Vulnhub练习)-- fristileaks渗透实战
- 每日一问 --什么是信源、信宿?