SpringBoot—统一功能处理

SpringBoot—统一功能处理

  • 🔎小插曲(通过一级路由调用多种方法)
  • 🔎使用拦截器实现用户登录权限的统一校验
    • 自定义拦截器
    • 将自定义拦截器添加至配置文件中
    • 拦截器的实现原理
    • 统⼀访问前缀添加
  • 🔎统一异常的处理
  • 🔎统一数据格式的返回
    • 统一数据格式返回的优点
    • 统一数据格式返回的实现
  • 🔎总结

利用 AOP 的思想对一些特定的功能进行统一的处理, 包括

  • 使用拦截器实现用户登录权限的统一校验
  • 统一异常的处理
  • 统一数据格式的返回

🔎小插曲(通过一级路由调用多种方法)


通过一级路由调用多种方法, 需要保证这些方法的请求类型各不相同(GET, POST, PUT…)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

🔎使用拦截器实现用户登录权限的统一校验


使用 Spring AOP 可以实现统一拦截, 但 Spring AOP 的使用较为复杂, 包括

  1. 定义拦截的规则(切点表达式)较为复杂
  2. 在切面类中拿到 HttpSession 较为复杂

于是 Pivotal 公司针对上述情况开发出 Spring 拦截器

Spring 拦截器的使用🍂

  1. 自定义拦截器
    • 实现 HandlerInterceptor 接口
    • 重写 preHandler 方法, 在方法中编写业务代码
  2. 将自定义拦截器添加至配置文件中, 并设置拦截的规则

自定义拦截器


在这里插入图片描述

将自定义拦截器添加至配置文件中


  • addPathPatterns, 表示需要拦截的 URL
    (/*表示一级路由, /**表示所有的请求)
  • excludePathPatterns, 表示不需要拦截的 URL
    在这里插入图片描述

拦截器的实现原理


调用方法时, 发现 DispatcherServlet

Dispatcher → 调度器

在这里插入图片描述

所有方法都会执行 DispatcherServlet 中的 doDispatch—调度方法

拦截器(doDispatch)的实现源码🌰

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv = null;Object dispatchException = null;try {processedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;mappedHandler = this.getHandler(processedRequest);if (mappedHandler == null) {this.noHandlerFound(processedRequest, response);return;}HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}this.applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception var20) {dispatchException = var20;} catch (Throwable var21) {dispatchException = new NestedServletException("Handler dispatch failed", var21);}this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);} catch (Exception var22) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);} catch (Throwable var23) {this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));}} finally {if (asyncManager.isConcurrentHandlingStarted()) {if (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}} else if (multipartRequestParsed) {this.cleanupMultipart(processedRequest);}}
}

在这里插入图片描述

当返回结果为 false 时, 拦截器将不会进行后续操作

在这里插入图片描述

applyPreHandle 的源码🌰

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}return true;
}

分析源码🍂

在 applyPreHandle 中会获取所有的拦截器 HandlerInterceptor, 并执行 HandlerInterceptor 中的 preHandle 方法

即自定义拦截器中重写的 preHandle 方法

在这里插入图片描述

统⼀访问前缀添加


统⼀访问前缀的添加有 2 种方式

  1. 重写 configurePathMatch( )
  2. 在配置文件中添加

重写 configurePathMatch( ) 🍂

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/bibubibu", c -> true);
}
  • /bibubibu, 要添加的统一前缀
  • c -> true, 所有请求均添加统一前缀

在这里插入图片描述

在配置文件中添加🍂

server:servlet:context-path: /bibubibu

在这里插入图片描述

🔎统一异常的处理


统一异常的处理, 利用 2 个注解

  1. @ControllerAdvice → 感知异常
  2. @ExceptionHandler → 处理异常

未设置异常处理🍂

在这里插入图片描述

NullPointerException

在这里插入图片描述

ArithmeticException

在这里插入图片描述

设置异常处理🍂

@ControllerAdvice
@ResponseBody
public class MyExceptionHandler {/*** 拦截所有空指针异常, 进行统一数据格式的返回* @author bibubibu* @date 2023/7/9*/@ExceptionHandler(NullPointerException.class)public HashMap<String, Object> nullPointerException(NullPointerException e) {HashMap<String, Object> map = new HashMap<>();map.put("status", -1);map.put("data", null);map.put("msg", "NullPointerException" + e.getMessage()); // 错误码的描述信息return map;}/*** 拦截所有算数异常, 进行统一数据格式的返回* @author bibubibu* @date 2023/7/9*/@ExceptionHandler(ArithmeticException.class)public HashMap<String, Object> arithmeticException(ArithmeticException e) {HashMap<String, Object> map = new HashMap<>();map.put("status", -1);map.put("data", null);map.put("msg", "ArithmeticException" + e.getMessage()); // 错误码的描述信息return map;}/*** 拦截所有异常, 进行统一数据格式的返回* @author bibubibu* @date 2023/7/9*/@ExceptionHandler(Exception.class)public HashMap<String, Object> exception(Exception e) {HashMap<String, Object> map = new HashMap<>();map.put("status", -1);map.put("data", null);map.put("msg", "Exception" + e.getMessage());return map;}
}

在这里插入图片描述

NullPointerException

在这里插入图片描述

ArithmeticException

在这里插入图片描述

🔎统一数据格式的返回


统一数据格式返回的优点


  1. 方便前端程序员更好的接收和解析后端数据接口返回的数据
  2. 降低前端程序员和后端程序员的沟通成本, 按照某个格式实现即可, 因为所有接口都是这样返回的
  3. 有利于项目统一数据的维护和修改
  4. 有利于后端技术部门统一规范的标准制定, 不会出现奇怪的返回内容

统一数据格式返回的实现


统一数据格式的返回, 利用注解 @ControllerAdvice + ResponseBodyAdvice(接口) 实现

未设置统一数据格式的返回🍂

@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("get-num")public Integer getNumber() {return (int) (Math.random() * 10 + 1);}}

在这里插入图片描述

设置统一数据格式的返回🍂

  1. 自定义类(ResponseAdvice), 添加 @ControllerAdvice 注解
  2. 实现 ResponseBodyAdvice 接口, 重写 supports() 与 beforeBodyWrite()

supports() 类似于一个开关
当返回值为 true 时, 开启 beforeBodyWrite() 中编写的相关功能
当返回值为 false 时, 关闭 beforeBodyWrite() 中编写的相关功能

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String, Object> map = new HashMap<>();map.put("status", 200);map.put("data", body); // 此处的 Body 是 String 类型会出错map.put("msg", "");return map;}
}

在这里插入图片描述

当方法的返回值类型为 String 时

@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/get-user")public String getUser() {System.out.println("执行 getUser()");return "getUser~~";}}

当调用方法的返回值类型为 String 时, 设置统一数据格式的返回🍂

在这里插入图片描述

类型转换异常

在这里插入图片描述

解决方法

当调用方法的返回值类型为 String 时, 利用 jackson 完成类型转换

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {// 利用 jackson 转换 String@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap<String, Object> map = new HashMap<>();map.put("status", 200);map.put("data", body); // 此处的 Body 是 String 类型会出错map.put("msg", "");// 判断 Body 是否为 String 类型if(body instanceof String) {// 是 String 类型, 将 map 转换为 Json 格式try {return objectMapper.writeValueAsString(map);} catch (JsonProcessingException e) {e.printStackTrace();}}return map;}
}

在这里插入图片描述

在这里插入图片描述

🔎总结


  1. 用户登录权限的统一校验 → 实现 HandlerInterceptor 接口 + 重写 preHandler 方法 + 将自定义拦截器添加至配置文件中(实现 WebMvcConfigurer 接口)
  2. 统一访问前缀的添加 → 重写 configurePathMatch( ) / 在配置文件中添加
  3. 统一异常的处理 → 利用注解 @ControllerAdvice + @ExceptionHandler
  4. 统一数据格式的返回 → 利用注解 @ControllerAdvice + 实现接口 ResponseBodyAdvice

🌸🌸🌸完结撒花🌸🌸🌸

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/14900.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

天天刷题-->LeetCode(两数相加)

个人名片&#xff1a; &#x1f405;作者简介&#xff1a;一名大二在校生&#xff0c;热爱生活&#xff0c;爱好敲码&#xff01; \ &#x1f485;个人主页 &#x1f947;&#xff1a;holy-wangle ➡系列内容&#xff1a; &#x1f5bc;️ tkinter前端窗口界面创建与优化 &…

oracle启动/关闭/查看监听+启动/关闭/查看数据库实例命令

启动oracle第一步启动监听&#xff0c;第二步启动数据库实例 &#xff08;1&#xff09;输入su oracle进入oracle用户状态 &#xff08;2&#xff09;这里的密码是你的root密码 1 启动/关闭/查看监听命令 &#xff08;1&#xff09;启动监听—— lsnrctl start &am…

Permission denied (publickey,password)问题的解决办法

[15:29:00.146] Terminal shell path: C:\WINDOWS\System32\cmd.exe [15:29:01.703] > root59.110.21.45: Permission denied (publickey,password). 解决&#xff1a; RSA key 登录方法/home/user/ 目录下建立 .ssh/ 文件夹 cd ~/ mkdir .ssh # 注意.ssh文件夹的权限 ch…

GIT版本控制常规性操作演示汇总

文章目录 GIT基本操作GIT配置个人信息配置&#xff1a;GIT查看个人信息配置&#xff1a;GIT的三大区域GIT回滚&#xff1a;git resetGIT恢复日志&#xff1a;git reflogGIT三大区域转换GIT新建分支GIT合并分支GIT删除分支码云上创建项目GIT变基&#xff1a;git rebase合并提交记…

随机产生50个100以内的不重复的整数,设计位图排序算法进行排序。

1.问题 随机产生50个100以内的不重复的整数&#xff0c;设计位图排序算法进行排序。 2.设计思路 阶段1&#xff1a; 初始化一个空集合    for i[0,n)    bit[i]0 阶段2&#xff1a; 读入数据i&#xff0c;并设置bit[i]1    for each i in the input file    bit[i]1…

3.6.共享内存的学习

目录 前言1. 共享内存2. shared memory案例3. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-共享…

基于C++、GDAL、OpenCV的矢量数据骨架线提取算法

基于C、GDAL、OpenCV的矢量数据骨架线提取算法 CGAL已经实现了该功能&#xff0c;但由于CGAL依赖于Boost库&#xff0c;编译后过大&#xff0c;因此本文所采用的这套方式实现骨架线提取功能。 效果&#xff1a; 思路&#xff1a; 1、将导入shp按照要素逐一拆分成新的shp 2、…

类Twitter风格的RSS阅读器

本文完成于 2 月中旬&#xff0c;其中的反代还是 frp npm 方案&#xff1b; 什么是 RSS ? RSS 是用 PHP、Laravel、Inertia.js、Tailwind 和 Vue.js 编写的简单的类Twitter 风格的 RSS阅读器&#xff0c;支持 RSS和ATOM 格式。 命令行安装 在群晖上以 Docker 方式安装。 官…

Nacos2.3.0源码启动报错找不到符号com.alibaba.nacos.consistency.entity

一. 源码下载编译&#xff1a;找不到符号com.alibaba.nacos.consistency.entity 如果报错找不到符号com.alibaba.nacos.consistency.entity Nacos\consistency\src\main\java\com\alibaba\nacos\consistency\entity 这个包下没有相关的java文件&#xff0c;其实是我们没有编译…

hadoop --- MapReduce

MapReduce定义&#xff1a; MapReduce可以分解为Map (映射) Reduce (规约) &#xff0c; 具体过程&#xff1a; Map : 输入数据集被切分成多个小块&#xff0c;并分配给不同的计算节点进行处理Shuffle and Sort&#xff1a;洗牌和排序&#xff0c;在 Map 阶段结束后&#xf…

15.1 BP神经网络实现图像压缩——了解神经网络在图像处理方面的应用(matlab程序)

1.简述 BP神经网络现在来说是一种比较成熟的网络模型了,因为神经网络对于数字图像处理的先天优势,特别是在图像压缩方面更具有先天的优势,因此,我这一段时间在研究神经网络的时候同时研究了一下关于BP网络实现图像压缩的原理和过程,并且是在MATLAB上进行了仿真的实验,结果发现设…

TinyStories: How Small Can Language Models Be and Still Speak Coherent English?

本文是LLM系列的文章之一&#xff0c;针对《TinyStories: How Small Can Language Models Be and Still Speak Coherent English?》的翻译。 TinyStories&#xff1a;语言模型能有多小&#xff0c;还能说连贯的英语&#xff1f; 摘要1 引言2 TinyStories数据集的描述2.1 Tiny…