Spring Boot 统一功能处理

✏️作者:银河罐头
📋系列专栏:JavaEE

🌲“种一棵树最好的时间是十年前,其次是现在”

目录

  • ⽤户登录权限效验
    • Spring Boot 拦截器
      • 自定义拦截器
      • 将自定义拦截器加入到系统配置
    • 拦截器实现原理
  • 统一异常处理
    • 创建一个异常处理类
    • 创建异常监测的类和处理的方法
  • 统一数据返回格式
    • StringHttpMessageConverter

Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节。

⽤户登录权限效验

Spring Boot 拦截器

Spring 中提供了具体的实现拦截器:HandlerInterceptor,拦截器的实现分为以下两个步 骤:

  1. 创建⾃定义拦截器,实现 HandlerInterceptor 接⼝的 preHandle(执⾏具体⽅法之前的预处理)方 法。
  2. 将⾃定义拦截器加⼊ WebMvcConfigurer 的 addInterceptors ⽅法中。

自定义拦截器

image-20230604164520468

public class LoginInterceptor implements HandlerInterceptor {// 调用目标方法之前执行的方法// 此方法会返回一个 boolean 类型的值,// 返回 true 表示拦截器验证成功,继续走后续流程,执行目标方法;// 返回 false 表示拦截器验证失败,后续流程和目标方法不用执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//用户登录校验HttpSession session = request.getSession(false);if(session != null && session.getAttribute("session_userinfo") != null){return true;}//        response.setStatus(401);response.setContentType("application/json;charset=utf8");
//        response.setCharacterEncoding("utf8");response.getWriter().println("{\"code\": -1, \"msg\": \"登录失败\", \"data\": \"\"}");return false;}
}

将自定义拦截器加入到系统配置

@Configuration
public class MyConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**")// 拦截所有 url.excludePathPatterns("/user/login") // 排除 登录 不拦截.excludePathPatterns("/user/reg") // 排除 注册 不拦截.excludePathPatterns("/image/**");}
}

验证下拦截功能:

@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public String login(){return "login";}@RequestMapping("/index")public String index(){return "index";}@RequestMapping("/reg")public String reg(){return "reg";}
}

image-20230604194230354

image-20230604194243430

image-20230604194257433

login() 和 reg() 没有被拦截,index() 被拦截。

拦截器实现原理

正常情况下的调⽤顺序:

image-20230604203530059

然⽽有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图所示:

image-20230604203643320

Spring Boot 拦截器的实现原理是基于 Spring MVC 框架的拦截器机制,当客户端发送请求时,请求会经过一系列的组件处理,其中就包括拦截器。

统一异常处理

如果不做统一的异常处理,后端抛异常,返回前端的状态码就是 500。

如果不想返回的是这个 500 状态码,可以对异常做统一处理,降低前端程序员和后端程序员的沟通成本。

创建一个异常处理类

@ControllerAdvice// 随着 spring Boot 项目的启动而启动 + 检测 controller 的异常
public class MyExceptionAdvice {}

创建异常监测的类和处理的方法

@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {@ExceptionHandler(NullPointerException.class)public HashMap<String, Object> doNullPointerException(NullPointerException e){HashMap<String, Object> result = new HashMap<>();result.put("code",-1);result.put("msg","空指针: " + e.getMessage());result.put("data",null);return result;}
}
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public int login(){Object obj = null;System.out.println(obj.hashCode());return 1;}
}

image-20230604213539804

但是这里只是处理了"空指针"异常,如果有其他的异常呢?比如"算数异常"

@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public int login(){int num = 10/0;return 1;}
}

image-20230604214219365

有一个办法,是再去写一个处理"算数异常"的类,但是异常类型太多,这样很麻烦。

可以写一个类,处理所有异常的父类-“Exception”.

@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {@ExceptionHandler(Exception.class)public HashMap<String, Object> doException(Exception e){HashMap<String, Object> result = new HashMap<>();result.put("code",-1);result.put("msg","Exception: " + e.getMessage());result.put("data",null);return result;}
}

image-20230604214702174

  • 如果子类异常(空指针)和父类异常都存在的情况下,出现"空指针"的情况会触发子类还是父类异常处理?
@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {@ExceptionHandler(NullPointerException.class)public HashMap<String, Object> doNullPointerException(NullPointerException e){HashMap<String, Object> result = new HashMap<>();result.put("code",-1);result.put("msg","空指针: " + e.getMessage());result.put("data",null);return result;}@ExceptionHandler(Exception.class)public HashMap<String, Object> doException(Exception e){HashMap<String, Object> result = new HashMap<>();result.put("code",-1);result.put("msg","Exception: " + e.getMessage());result.put("data",null);return result;}
}
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public int login(){Object obj = null;System.out.println(obj.hashCode());return 1;}@RequestMapping("/login2")public int login2(){int num = 10/0;return 1;}
}

image-20230605194818607

优先触发子类异常。

统一数据返回格式

强制性统一数据返回。(在返回数据之前进行数据重写)

统⼀数据返回格式的优点:⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回 的。有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。

//统一数据格式处理
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;// true => 调用 beforeBodyWrite() 方法}//返回数据之前进行重写@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 假定标准格式是 HashMap<String, Object> -> {code, msg, data}if(body instanceof HashMap) {return body;}HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg","");result.put("data",body);return result;}
}
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public int login(){return 1;}@RequestMapping("/login2")public int login2(){return 1;}@RequestMapping("/reg")public HashMap<String, Object> reg(){HashMap<String, Object> result = new HashMap<>();result.put("code",200);result.put("msg","");result.put("data",1);return result;}
}

image-20230605203257302

image-20230605203309463

保证始终返回的都是标准的格式。

StringHttpMessageConverter

  • 再来看一个例子:
@RequestMapping("/sayHi")
public String sayHi(){return "say hi";
}

image-20230605203828969

//默认异常处理(当具体的异常匹配不到时,会走这个方法)
@ExceptionHandler(Exception.class)
public HashMap<String, Object> doException(Exception e){HashMap<String, Object> result = new HashMap<>();result.put("code",-1);result.put("msg","Exception: " + e.getMessage());result.put("data",null);return result;
}

返回流程:

1.返回 String

2.统一数据格式处理:String -> HashMap

3.HashMap -> application/json 给前端

报错就是 第 3 步出错了。

image-20230605205752518

到 第 3 步之后就会对原 body 的类型进行判断:

1.是 String -> StringHttpMessageConverter 进行类型转换

就这个例子而言,它就会用第 2 步得到的 HashMap -> String, 就出现类型转换异常。

2.非 String -> HttpMessageConverter 进行类型转换

解决方案:

1.将 StringHttpMessageConverter 转化器去掉。

package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;@Configuration
public class MyConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.removeIf(converter->converter instanceof StringHttpMessageConverter);}
}

2.在统一数据重写时,单独处理 String 类型,让其返回一个 String 类型而不是 HashMap.

//返回数据之前进行重写@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 假定标准格式是 HashMap<String, Object> -> {code, msg, data}if(body instanceof HashMap) {return body;}HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg","");result.put("data",body);if(body instanceof String){
//            return "{\"code\": 200, \"msg\": \"\", \"data\": \"" + body + "\"}";//将对象转换成 json 字符串return objectMapper.writeValueAsString(result);}return result;}

image-20230605213253457

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

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

相关文章

LLM - 搭建 ProteinGPT 结合蛋白质结构 PDB 知识的行业 ChatGPT 系统

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/131403263 论文&#xff1a;ProteinChat: Towards Enabling ChatGPT-Like Capabilities on Protein 3D Structures 工程&#xff1a;ht…

数据库监控与调优【十七】—— 表结构设计优化

表结构设计优化 第一范式&#xff08;1NF&#xff09; 字段具有原子性&#xff0c;即数据库的每一个字段都是不可分割的原子数据项&#xff0c;不能是集合、数组、记录等非原子数据项 当实体中的某个属性有多个值时&#xff0c;必须拆分为不同的属性 例子&#xff1a; 如图…

【广州华锐互动】机械设备事故VR模拟体验系统

随着虚拟现实技术的不断发展&#xff0c;越来越多的行业开始尝试将VR技术应用到实际场景中&#xff0c;以提供更加真实的体验。其中&#xff0c;机械伤害事故VR警示教育系统的出现&#xff0c;为机械工程师、安全培训人员等行业提供了一种全新的培训方式。在实现上&#xff0c;…

Linux基础

Linux root用户&#xff0c;cd ~ 相当于 cd /root 普通用户&#xff0c;cd ~ 相当于cd /home/当前用户名 注&#xff1a;cd - 返回进入此目录之前所在目录 rm --> remove mv --> move cp --> copy !! 执行最近的一次命令 echo $USER 展现当前用户名字 echo $PATH 展…

Linux:安装tomcat

注意&#xff1a;1.安装tomcat时最好用非root用户安装 2.可以选择新建一个用户&#xff0c;用户安装部署tomcat&#xff0c;本文将继续用fovace账户进行tomcat安装 一、前置条件 安装tomcat需要先安装jdk&#xff0c;所以先确定系统中是否已经有jdk&#xff0c;如下&#xff1a…

Docker的run流程

底层原理 Docker怎么工作&#xff1f; Docker为什么比VM虚拟机块&#xff1f; 1.Docker有比虚拟机更少的抽象层 2.docker利用的是宿主机的内核&#xff0c;vm需要是Guest OS 所以说&#xff0c;新建一个容器的时候&#xff0c;docker不需要像虚拟机一样加载一个系统内核&am…

消息中间件中常见问题

如何保证消息不丢失 MQ的用途 异步发送&#xff08;验证码&#xff0c;短信&#xff0c;邮件&#xff09;MySQL&#xff0c;ES&#xff0c;Redis之间的数据同步分布式事务削峰填谷 消息可能丢失的环境 消息在产生端时候生产端挂掉&#xff0c;消息未到达交换机&#xff0c…

VS里拉取时候,变成变基中,变成分离分支状态,git 头指针分离于 baf67ff

分离头指针&#xff08;detached HEAD&#xff09; 通常&#xff0c;我们工作在某一个分支上&#xff0c;比如 master 分支。这个时候 master 指针和 HEAD 指针是一起前进的&#xff0c;每做一次提交&#xff0c;这两个指针就会一起向前挪一步。但是在某种情况下&#xff08;例…

Revit中怎么画阶梯式旋转楼梯及生成桩

一、Revit中如何绘制阶梯式旋转楼梯 在楼梯的绘制过程中&#xff0c;如果采用(草图)楼梯的绘制方式&#xff0c;是没有办法将绘制的楼梯设置为阶梯式楼梯的&#xff0c;那么接下来我将采用构件的方式绘制阶梯式楼梯。 我们首先来看看阶梯式旋转楼梯和普通的旋转楼梯的区别&…

【C++】一些关于visual stdio,vscode,Mingw的思考 |bug

文章目录 今天在做YOLOV8的C部署时遇到的一些问题&#xff1a; 在进行一系列的操作之后会生成解决方案文件sln: 当然按道理到这一步之后&#xff0c;应该使用make命令进行下一步操作&#xff08;但是我确实不会make命令&#xff0c;所以准备进sln来生成解决方案&#xff09;&…

(0018) H5-VS Code保存后自动格式化Vue代码

安装插件Vetur 配置自动格式化&#xff0c;具体路径【文件】-【首选项】-【设置】&#xff0c;打开设置&#xff08;json&#xff09; 将以下内容复制到settings.json {// vscode默认启用了根据文件类型自动设置tabsize的选项"editor.detectIndentation": fals…

最新导则下生态环评报告编制技术暨报告篇、制图篇、指数篇、综合应用篇教程

详情点击链接&#xff1a;最新导则下生态环评报告编制技术暨报告篇、制图篇、指数篇、综合应用篇 一&#xff0c;生态环评报告编制规范 结合生态环境影响评价最新导则&#xff0c;详述不同类型项目生态环评报告编制要求与规范 二&#xff0c;土地利用图 1、土地利用分类体系…