【SpringBoot】统一功能处理详解

【SpringBoot】统一功能处理详解

🎬 那我掉的头发算什么个人主页
🔥 个人专栏: 《javaSE》《数据结构》《数据库》《javaEE》

⛺️待到苦尽甘来日


在这里插入图片描述

文章目录

统一数据返回格式

快速入门

统一的数据返回格式使用 @ControllerAdvice 和 ResponseBodyAdvice 的方式实现@ControllerAdvice 表示控制器通知类添加类 ResponseAdvice , 实现 ResponseBodyAdvice 接口,并在类上添加@ControllerAdvice 注解。

packagecom.hbu.book.responseAdvice;importorg.jspecify.annotations.Nullable;importorg.springframework.core.MethodParameter;importorg.springframework.http.MediaType;importorg.springframework.http.server.ServerHttpRequest;importorg.springframework.http.server.ServerHttpResponse;importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;publicclassResponseAdviceimplementsResponseBodyAdvice{@Overridepublicbooleansupports(MethodParameter returnType,Class converterType){returnfalse;}@Overridepublic@NullableObjectbeforeBodyWrite(@NullableObject body,MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response){returnnull;}}

supports 方法:判断是否要执行 beforeBodyWrite 方法. true 为执行,false 不执行。通过该方法可以选择哪些类或哪些方法的 response 要进行处理,其他的不进行处理。

在这里插入图片描述


beforeBodyWrite方法: 对response方法进行具体操作处理。

此时还没启动统一处理,这时访问接口返回结果是这样的:

在这里插入图片描述
packagecom.hbu.book.model;importcom.hbu.book.enums.ResultCodeEnum;importlombok.Data;@DatapublicclassResult<T>{privateResultCodeEnum code;//-1 未登录 200 正常 -2 出错privateString errMsg;privateT data;publicstatic<T>Resultsuccess(T data){Result result =newResult(); result.setCode(ResultCodeEnum.SUCCESS); result.setErrMsg(""); result.setData(data);return result;}publicstatic<T>Resultfail(String errMsg){Result result =newResult(); result.setCode(ResultCodeEnum.FAIL); result.setErrMsg(errMsg); result.setData(null);return result;}publicstatic<T>Resultfail(String errMsg,T data){Result result =newResult(); result.setCode(ResultCodeEnum.FAIL); result.setErrMsg(errMsg); result.setData(data);return result;}publicstatic<T>Resultunlogin(){Result result =newResult(); result.setCode(ResultCodeEnum.UNLOGIN); result.setErrMsg("用户未登录");return result;}}
packagecom.hbu.book.responseAdvice;importcom.hbu.book.model.Result;importorg.jspecify.annotations.Nullable;importorg.springframework.core.MethodParameter;importorg.springframework.http.MediaType;importorg.springframework.http.server.ServerHttpRequest;importorg.springframework.http.server.ServerHttpResponse;importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;publicclassResponseAdviceimplementsResponseBodyAdvice{@Overridepublicbooleansupports(MethodParameter returnType,Class converterType){returntrue;}@Overridepublic@NullableObjectbeforeBodyWrite(@NullableObject body,MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response){returnResult.success(body);}}

启动了之后再次访问接口:

在这里插入图片描述

存在问题


在这里插入图片描述


在这里插入图片描述


但是数据库中确实是插入了这个数据。

其他的操作都是正常的。

packagecom.hbu.book.controller;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/test")@RestControllerpublicclassTestController{@RequestMapping("/t1")publicStringt1(){return"t1";}@RequestMapping("/t2")publicbooleant2(){returntrue;}@RequestMapping("/t3")publicIntegert3(){return200;}}

多方测试下,只有返回类型是String的接口才会发生这种错误。并且报错方式都是一样的。

核心原因是 Spring 处理 String 类型返回值的消息转换器优先级问题:当控制器方法返回 String 时,Spring 会优先使用 StringHttpMessageConverter 处理响应,但这个转换器只能处理 String 类型,而 ResponseAdvice 把 String 包装成了 Result 对象,导致转换器尝试将 Result 强制转为 String 时抛出类型转换异常。

代码优化

packagecom.hbu.book.config;importcom.hbu.book.model.Result;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.core.MethodParameter;importorg.springframework.http.MediaType;importorg.springframework.http.server.ServerHttpRequest;importorg.springframework.http.server.ServerHttpResponse;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;importtools.jackson.databind.ObjectMapper;@ControllerAdvicepublicclassResponseAdviceimplementsResponseBodyAdvice{@AutowiredprivateObjectMapper objectMapper;@Overridepublicbooleansupports(MethodParameter returnType,Class converterType){returntrue;}@OverridepublicObjectbeforeBodyWrite(Object body,MethodParameter returnType,MediaType selectedContentType,Class selectedConverterType,ServerHttpRequest request,ServerHttpResponse response){if(body instanceofResult){return body;}if(body instanceofString){return objectMapper.writeValueAsString(Result.success(body));}returnResult.success(body);}}

优点

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

统一异常处理

统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类, @ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。

packagecom.hbu.book.config;importcom.hbu.book.model.Result;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice@ResponseBody@Slf4jpublicclassExceptionAdvice{@ExceptionHandlerpublicObjecthandler(Exception e){ log.error("出现异常:",e);returnResult.fail(e.getMessage());}}

测试一下:

packagecom.hbu.book.controller;importorg.apache.ibatis.jdbc.Null;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/test")@RestControllerpublicclassTestController{@RequestMapping("/t1")publicStringt1(){Integer x =7/0;return"t1";}@RequestMapping("/t2")publicbooleant2(){String a =null; a.contains("a");returntrue;}@RequestMapping("/t3")publicIntegert3(){int[] arr =newint[10];System.out.println(arr[100]);return200;}}
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


对于不同的异常,我们其实可以设置不同的方法:

packagecom.hbu.book.config;importcom.hbu.book.model.Result;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice@ResponseBody@Slf4jpublicclassExceptionAdvice{@ExceptionHandlerpublicObjecthandler(Exception e){ log.error("出现异常:",e);returnResult.fail(e.getMessage());}@ExceptionHandlerpublicObjecthandler(NullPointerException e){ log.error("出现空指针异常:",e);returnResult.fail(e.getMessage());}@ExceptionHandlerpublicObjecthandler(ArithmeticException e){ log.error("出现除0异常:",e);returnResult.fail(e.getMessage());}@ExceptionHandlerpublicObjecthandler(ArrayIndexOutOfBoundsException e){ log.error("出现数组越界异常:",e);returnResult.fail(e.getMessage());}}

或者也可以:

packagecom.hbu.book.config;importcom.hbu.book.model.Result;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.ControllerAdvice;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice@ResponseBody@Slf4jpublicclassExceptionAdvice{@ExceptionHandlerpublicObjecthandler(Exception e){ log.error("出现异常:",e);returnResult.fail(e.getMessage());}// @ExceptionHandler// public Object handler(NullPointerException e){// log.error("出现空指针异常:",e);// return Result.fail(e.getMessage());// }// @ExceptionHandler// public Object handler(ArithmeticException e){// log.error("出现除0异常:",e);// return Result.fail(e.getMessage());// }// @ExceptionHandler// public Object handler(ArrayIndexOutOfBoundsException e){// log.error("出现数组越界异常:",e);// return Result.fail(e.getMessage());// }@ExceptionHandler(NullPointerException.class)publicObjecthandler1(Exception e){ log.error("出现异常:",e);returnResult.fail(e.getMessage());}@ExceptionHandler(ArrayIndexOutOfBoundsException.class)publicObjecthandler2(Exception e){ log.error("出现异常:",e);returnResult.fail(e.getMessage());}}

我们一般不把异常的具体内容返回给前端,因此可以这样处理:

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


这里我们没有针对t1做特别的异常处理,最后打印出来的是内部异常。
所以说,当没有匹配的异常时,会自动去寻找有没有报的异常的父类的处理方法,然后执行处理方法。

Read more

【Spring Cloud】初识Spring Cloud

【Spring Cloud】初识Spring Cloud

系列文章目录 在学习Spring Cloud 之前, 我们先来了解下什么是微服务, 以及微服务的发展史. 在架构发展的过程中,项目开发遇到了哪些问题, 以及Spring Cloud是用来解决什么问题的. 这将对咱们后面的相关内容有很大帮助! 一、认识微服务 下图表示了服务架构从单体应用逐渐转变为微服务应用的过程: 1.1 单体架构 很多创业公司早期或者传统企业会把业务的所有功能实现都打包在⼀个项⽬, 这就是单体架构.业务的所有功能实现都打包在⼀个war包或者Jar包中, 这种方式就称为单体架构 如果一个项目前端+后端+数据库实现,都在⼀个项⽬中, 这种架构就称为单体架构. 以大家都很熟悉的电商系统为例, 电商系统包括: 用户管理, 商品管理, 订单管理, 支付管理, 库存管理, 物流管理等等, 项目早期我们会把这些模块都写在⼀个web项目中, 然后统一部署到⼀个Web服务器中。 这种架构开发简单, 部署简单, ⼀个项⽬就包含了所有的功能, 省去了多个项目之间的交互和调用消耗.直接部署在⼀个服务器即可. 1.

By Ne0inhk
NanoClaw 深度剖析:一个“AI 原生“架构的个人助手是如何运转的?

NanoClaw 深度剖析:一个“AI 原生“架构的个人助手是如何运转的?

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 1. 了解大厂经验 2. 拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 * 一、它到底是什么?—— 三句话说清楚 * 二、整体架构:一张图看懂数据流 * 三、数据层:SQLite 才是"真相的唯一来源" * 3.1 为什么选 SQLite? * 3.2 游标机制:如何做到"断点续传" * 四、消息循环:一颗永不停跳的心脏 * 五、容器化执行:安全隔离的艺术 * 5.1 为什么要用容器? * 5.

By Ne0inhk
构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

前言 随着大语言模型(LLM)能力的飞速提升,将 AI 能力集成到终端命令行工具(CLI)中已成为提升开发效率的重要手段。Rust 语言凭借其内存安全、零成本抽象以及极其高效的异步运行时,成为构建此类高性能网络 IO 密集型应用的首选。本文将深度剖析如何使用 Rust 语言,结合智谱 AI 的 GLM-5 模型,从零构建一个支持流式输出、多语言切换及文件批处理的 AI 翻译引擎。 本文将涵盖环境配置、依赖管理、异步网络编程、流式数据处理(SSE)、命令行参数解析以及最终的二进制发布优化。 第一部分:Rust 开发环境的系统级构建 在涉足 Rust 编程之前,必须确保底层操作系统具备必要的构建工具链。Rust 虽然拥有独立的包管理器,但在链接阶段依赖于系统的 C 语言编译器和链接器,尤其是在涉及网络库(如 reqwest 依赖的 OpenSSL)

By Ne0inhk
从千毫秒到亚毫秒:连接条件下推如何让复杂 SQL 飞起来

从千毫秒到亚毫秒:连接条件下推如何让复杂 SQL 飞起来

文章目录 * 前言 * 一、问题背景 * 1.1 客户场景中的典型痛点 * 1.2 业界普遍面临的两大难点 * 1.2.1 语义安全性(Equivalence) * 1.2.2 代价评估(Cost) * 二、传统方案的局限 * 三、金仓数据库基于代价的连接条件下推设计 * 3.1 能不能推:等价性判定(Equivalence) * 3.2 值不值推:代价模型(Cost) * 四、效果验证 * 4.1 最小化用例 * 4.2 复杂场景验证 * 五、总结 前言 在真实的业务系统中,SQL 往往远比教科书示例复杂。随着业务逻辑的不断演进,CTE、

By Ne0inhk