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方法后,开始业务处理;得到业务处理结果后,响应结果也会经过请求进来时的所有过滤器、 * 的处理,不同的是顺序与请求进来时完全相反,即先进后出;

Springboot项目快速实现 * 功能

实现方式

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是抽象类,实际上并没有具体实现,所以在实现 * 功能功能的两种方式本质上是一种;

Springboot项目快速实现 * 功能

代码实现

定义两个 * :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()方法触发执行;

Springboot项目快速实现 * 功能

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,即先进后出;

Springboot项目快速实现 * 功能

来源:https://blog.csdn.net/fox9916/article/details/129691345

标签:Java,Springboot,Interceptor, ,
0
投稿

猜你喜欢

  • C#使用foreach语句遍历堆栈(Stack)的方法

    2021-11-03 08:03:38
  • Java发送邮箱验证码、session校验功能

    2023-09-11 02:44:21
  • 浅谈C#中的值类型和引用类型

    2023-10-30 21:41:41
  • 如何将Mybatis连接到ClickHouse

    2023-11-06 02:35:51
  • Java实现淘宝秒杀聚划算抢购自动提醒源码

    2022-09-11 10:11:53
  • Groovy编程入门攻略

    2022-12-05 13:35:47
  • C#中WinForm控件的拖动和缩放的实现代码

    2023-09-27 23:54:08
  • java9迁移注意问题总结

    2022-07-19 11:26:30
  • springboot如何静态加载@configurationProperties

    2021-12-13 16:20:13
  • JAVA导出EXCEL表格的实例教学

    2021-11-21 01:47:28
  • Android使用Intent传递组件大数据

    2023-09-30 12:21:46
  • idea中Maven镜像源详细配置步骤记录(对所有项目)

    2022-12-17 14:27:56
  • Springboot项目出现java.lang.ArrayStoreException的异常分析

    2022-05-13 05:48:20
  • Android 之BottomsheetDialogFragment仿抖音评论底部弹出对话框效果(实例代码)

    2023-08-06 01:01:56
  • 详解Android运行时权限及APP适配方法

    2021-06-15 11:06:17
  • Java SpringBoot拦截器详解

    2021-11-01 15:29:37
  • Spring MVC 前端控制器 (DispatcherServlet)处理流程解析

    2023-02-03 03:56:50
  • Kotlin协程的线程调度示例详解

    2023-12-26 20:19:56
  • 解决try-catch捕获异常信息后Spring事务失效的问题

    2022-11-15 03:17:33
  • JavaFX之TableView的使用详解

    2022-07-16 06:32:24
  • asp之家 软件编程 m.aspxhome.com