Springboot项目快速实现 * 功能
作者:凡夫贩夫 发布时间:2022-10-05 12:34:50
前言
上一篇文章分享了Springboot项目快速实现过滤器功能,本篇文章接着来盘一盘 * ,仔细研究后会发现,其实 * 和过滤器的功能非常类似,可以理解为面向切面编程的一种具体实现。下面就其功能特性、工作原理、涉及到的核心类以及具体的实现方式几个方面进行梳理,以便在实际业务开发过程中,可以根据实际需要选择合适的实现访求。
环境配置
jdk版本:1.8
开发工具:Intellij iDEA 2020.1
springboot:2.3.9.RELEASE
HandleInterceptor介绍
* ,在java中只是一种概念,并没有一个具体的实现或标准,通常所说的java web的 * 实际是指HandleInterceptor接口,这是Spring MVC提供的一套拦截机制,可以在controller处理请求之后和响应处理结果之后,对请求信息和响应结果进行拦截;但不能修改具体的请求信息和响应结果;Spring MVC的 * 的概念和servlet的Filter非常类似,但是在执行顺序上是有所不同的,下面会重点介绍;从本质上来说,SpringMVC的 * 机制,是AOP(面向切面编程)的一种具体实现,可以很方面用户对实际业务中公共的一些业务进行横向抽取,但是和servlet的Filter一样,有一定的局限性,如能对请求信息和响应结果进行拦截,但不能修改具体的请求信息和响应结果;能拦截controller层的方法,但是不能拦截service层的方法;
工作原理
如果把过滤器和 * 放在一起来分析其工作原理,就需要再次明确一件事:Filter接口的全限定类名是javax.servlet.Filter,HandleInterceptor接口的全限定类名是org.springframework.web.servlet.HandlerInterceptor,从这里就可以看得出来,Filter是servlet里就有的接口,HandleInterceptor是Spring中新增的接口,两个是来源完全不同的东西,但功能却很类似,那么放在一起又会发生什么奇妙的事呢?
1、过滤器1、过滤器2、拦截1、拦截2对象,会在Spring容器启动的过程中,完成bean的注册;
2、当客户端向服务端发起http请求时,在请求到达具体的controller方法之前,会先经过过滤器、 * 的处理,其中过滤器的执行时机要早于 * ;和过滤器一样,如果当前请求匹配到了多个 * ,会形成一个 * 链,按照默认或指定的优先级,依次经过各个 * 对象的处理之后,才会到达具体的controller方法;
3、到达具体的controller方法后,开始业务处理;得到业务处理结果后,响应结果也会经过请求进来时的所有过滤器、 * 的处理,不同的是顺序与请求进来时完全相反,即先进后出;
实现方式
1、实现org.springframework.web.servlet.HandlerInterceptor接口;
2、继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter类;
核心类
HandlerInterceptor
HandlerInterceptor是SpringMVC提供的实现 * 功能的一个标准接口,接口内有三个方法:
1、preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) ,方法在请求处理之前会被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回值是 Boolean 类型;当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时,会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法;
2、postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作;
3、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行;该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行,主要用来进行资源清理或释放。
HandlerInterceptorAdapter
HandlerInterceptorAdapter是一个抽象类,该抽象类实现了AsyncHandlerInterceptor接口,而AsyncHandlerInterceptor接口又继承于HandlerInterceptor,因此可以认为HandlerInterceptorAdapter是实现了HandlerInterceptor接口,但是HandlerInterceptorAdapter是抽象类,实际上并没有具体实现,所以在实现 * 功能功能的两种方式本质上是一种;
代码实现
定义两个 * :MyInterceptor1和MyInterceptor2,通过一次完成的请求,来分析一下HandlerInterceptor接口的preHandle()、postHandle()、afterCompletion()是如何工作的?
1、定义和注册两个 * :MyInterceptor1和MyInterceptor2,设置 * 的拦截路径为/person/get*,myInterceptor2的优先级高于myInterceptor1;
2、发起http请求(URL:/person/get);
3、/person/get请求在执行PersonController#getPerson()之前,会先执行到MyInterceptor1和MyInterceptor2的preHandler()方法;
4、如果MyInterceptor1和MyInterceptor2的preHandler()方法返回都为true,则会执行到PersonController#getPerson();
5、PersonController#getPerson()执行完成后,还没有返回视图渲染对象之前MyInterceptor1和MyInterceptor2的postHandle()方法触发执行;
6、再然后就是整个请求处理完之后,MyInterceptor1和MyInterceptor2的afterCompletion()方法触发执行;
PersonController.java
@Controller
@RequestMapping("/person")
@Slf4j
public class PersonController {
@Autowired
private IPersonService personService;
@GetMapping("/get")
@ResponseBody
public Person getPerson(Integer id) {
Person person = this.personService.get(id);
log.info("//查询person详情执行完成");
return person;
}
}
定义WebConfig类实现WebMvcConfigurer接口,实现addInterceptors(),完成 * 的注册以及设置好拦截路径和优先级顺序;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor2())
.addPathPatterns("/person/get*")
.order(1);
registry.addInterceptor(new MyInterceptor1())
.addPathPatterns("/person/get*")//设置拦截请求路径;*是通配符;
.order(2)//设置 * 对象的优先级,如果有多个 * 对象,设置数字越小,优先级越高;
.excludePathPatterns("/test");//设置排除拦截的请求路径;
}
}
定义MyInterceptor1类实现HandlerInterceptor接口
@Slf4j
public class MyInterceptor1 implements HandlerInterceptor {
//preHandle方法在请求处理之前被调用;当返回true,则表示可以继续后续请求处理;当返回false,则表示请求结束;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("//myInterceptor1的preHandle方法开始执行");
log.info("//请求路径:{}",request.getRequestURI());
HandlerMethod handlerMethod = (HandlerMethod) handler;
log.info("//拦截类:{},方法:{}",handlerMethod.getBean().getClass().getName(),handlerMethod.getMethod().getName());
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String parameterValue = request.getParameter(parameterName);
log.info("//请求参数>{}:{}",parameterName,parameterValue);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("//myInterceptor1的postHandle方法开始执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("//myInterceptor1的afterCompletion方法开始执行");
}
}
定义MyInterceptor2,继承HandlerInterceptorAdapter抽象类,重写HandlerInterceptorAdapter类的方法;
@Slf4j
public class MyInterceptor2 extends HandlerInterceptorAdapter {
//preHandle方法在请求处理之前被调用;当返回true,则表示可以继续后续请求处理;当返回false,则表示请求结束;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("//myInterceptor1的preHandle方法开始执行");
log.info("//请求路径:{}",request.getRequestURI());
HandlerMethod handlerMethod = (HandlerMethod) handler;
log.info("//拦截类:{},方法:{}",handlerMethod.getBean().getClass().getName(),handlerMethod.getMethod().getName());
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
String parameterValue = request.getParameter(parameterName);
log.info("//请求参数>{}:{}",parameterName,parameterValue);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("//myInterceptor1的postHandle方法开始执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("//myInterceptor1的afterCompletion方法开始执行");
}
结果验证
Filter与HandleInterceptor的执行顺序:在请求处理阶段,先经过Filter然后再经过HandleInterceptor,在响应处理阶段,先经过HandleInterceptor,再经过Filter,即先进后出;
来源:https://blog.csdn.net/fox9916/article/details/129691345


猜你喜欢
- 后端应用经常接收各种信息参数,例如评论,回复等文本内容。除了一些场景下面,可以特定接受的富文本标签和属性之外(如:b,ul,li,h1, h
- 在使用ListView组件来显示列表数据时,有的时候我们需要改变列表中的数据,有以下方法:1、重新给ListView组件设置适配器这种方法重
- 硬件环境:小米4Android版本:6.0咱们先看效果图:我把代码贴出来:AndroidMainfest.xml文件(需要新增camera权
- Unity中,我们怎么制作UI物体发光的渐隐渐现的效果呢?比如说我们有一张月亮光晕的精灵图片我们可以给它添加一个CanvasGroup组件我
- 基于 springboot+vue 的测试平台(练手项目)开发继续更新。在接口编辑页中点击发送接口请求,除了显示响应体外,还可以显示响应头等
- Spring核心Spring核心是 IOC 和 AOP 。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和
- 这篇文章主要介绍了简单了解java标识符的作用和命名规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&
- 本文研究的主要是利用spring的 * 自定义缓存的实现,具体实现代码如下所示。Memcached 是一个高性能的分布式内存对象缓存系统,用
- Android RadioButton 图片位置与大小Java:rgGroup = (RadioGroup) findViewById(R.
- 最近项目中需要根据模板生成word文档,模板文件也是word文档。当时思考一下想用POI API来做,但是觉得用起来相对复杂。后来又找了一种
- 枚举的基本用法回顾以下是一个常见的 C# 枚举(enum)的示例:enum Weekday{
- TabLayout+ViewPager实现tab和页面联动效果xml中:<?xml version="1.0" e
- 前言前段时间因为工作的需要用到Spring事件,翻翻文档将功能实现了,但是存在少许理解不畅的地方,今天有空来梳理梳理。需求背景叶子同学在新入
- 实例如下:/** * 弹出一个带确认和取消的dialog * @param context * @param title * @param
- 题目:求100之内的素数方法一:package airthmatic;public class demo8 { /** * 素数是指因数只有
- Java String对象使用方法详解先来看一个例子,代码如下: public class Test { public sta
- 对开场白没兴趣?好吧,我们直接切入正题,下面介绍10个C#编程和Visual Studio IDE使用技巧。1、Environment.Ne
- 前言本文主要给大家介绍了关于Android中GridView布局整体居中的相关内容,是对于自己在项目中遇到问题的一个记录,分享出来供大家参考
- 一、问题描述在使用idea Jrebel续期的时候,修改idea激活服务器地址时,遇到报错:Cannot reactivate, offli