【SpringBoot】Spring 一站式解决方案:融合统一返回结果、异常处理与适配器模式

news2025/5/16 23:34:14

前言

???本期讲解关于统一功能处理的详细介绍~~~

??感兴趣的小伙伴看一看小编主页:-CSDN博客

?? 你的点赞就是小编不断更新的最大动力

??那么废话不多说直接开整吧~~

目录

???1.适配器模式?

??1.1适配器模式定义

?编辑

??1.2适配器模式角色

??1.3适配器模式实现

???2.统一数据返回格式

??2.1快速入门

??2.2存在问题

1.作用路径

2.异常情况

??2.3统一返回格式优点

???3.统一异常处理

??3.1快速入门

??3.2多种异常

??3.3统一异常处理优点

???4.总结

**??**1.适配器模式

??1.1适配器模式定义

适配器模式, 也叫包装器模式. 将个类的接,转换成客期望的另个接, 适配器让原本接不兼容的类可以合作间.

简单来说就是标类不能直接使, 通过个新类进包装下, 适配调使. 把两个不兼容的接通过定的式使之兼容.

如下两个接, 本是不兼容的(参数类型不样, 参数个数不样等等)

但是此时我们可以通过适配器进行两者的兼容,具体的图示如下所示:

??1.2适配器模式角色

Target: 标接 (可以是抽象类或接), 客希望直接的接

Adaptee: 适配者, 但是与Target不兼容

Adapter: 适配器类, 此模式的核. 通过继承或者引适配者的对象, 把适配者转为标接

client: 需要使适配器的对象

大致就是:两个不相容的接口,通过适配器进行了连接,使得使用适配器的对象能够操作目标接口;

??1.3适配器模式实现

slf4j 就使了适配器模式,slf4j底层调用了这里的log4j,我们作为调用者,只需要调用slf4j的api就可以了

具体的代码如下所示:

第一步:创建slf4j的api接口

interface Slf4jApi{
 void log(String message);
}

第二步:创建一个log4j,实现打印的功能

class Log4j{
 void log4jLog(String message){
 System.out.println("Log4j打印:"+message);
 }
}

此时可以看到,这两个类并没有关联,那么此时我们就要进行两个接口的连接了

第三步:创建适配器,进行两个接口的连接

class Slf4jLog4JAdapter implements Slf4jApi{
   private Log4j log4j;
   public Slf4jLog4JAdapter(Log4j log4j) {
      this.log4j = log4j;
   }
   @Override
   public void log(String message) {
      log4j.log4jLog(message);
   }
}

此时就是进行方法的重写,这里重写的方法调用我们目标打印的类里的方法,此时就将两个不相关的接口进行连接;

第四步:调用api实现打印

public class Slf4jDemo {
   public static void main(String[] args) {
      Slf4jApi slf4jApi = new Slf4jLog4JAdapter(new Log4j());
         slf4jApi.log("使?slf4j打印?志");
      }
}

所以可以发现,作为调用者,真正使用的就是适配器帮我们进行操作,不需要改变log4j的api,只需要通过适配器转换下, 就可以更换志框架, 保障系统的平稳运

适配器使用场景:

般来说,适配器模式可以看作种"补偿模式",来补救设计上的缺陷. 应这种模式算是"奈之举", 如果在设计初期,我们就能协调规避接不兼容的问题, 就不需要使适配器模式了

**??**2.统一数据返回格式

??2.1快速入门

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

代码如下所示:

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {   
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        
         return null
    }
}

解释:

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

下面的方法就是表示同意返回的格式是什么,默认重写的就是null;

??2.2存在问题
1.作用路径

假如我们需要作用指定的类上,那么代码如下所示:

@Override
public boolean supports(MethodParameter returnType, Class converterType) {
    // 假设你想针对某个具体业务的返回值类型进行处理,这里以 com.example.demo.entity.User 为例
    return returnType.getParameterType().getName().equals("com.example.demo.entity.User");
}

解释:

过获取MethodParameter中的返回值类型的全限定名,并与指定的类全限定名(这里是com.example.demo.entity.User)进行比较,如果相等,就表明当前处理的方法返回值类型正是我们期望操作的那个类,supports方法就返回true

2.异常情况

这里在对于返回类型为string类型的数据会发生,数据不匹配的原因,这里涉及到原码的问题了,出现问题如下所示:

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("t1")
    public String t1(){
        return "t1";
    }
}

首先我们先创建一个string类,通过运行代码,然后进行同意结果的访问,那么出现的结果如下所示:

主要还是应为原码的问题:

所以此时,我们规定的返回格式不符合这里的string类型,所以发生类型不匹配的问题,那么此时我们就需要进行操作修改;

代码如下:

@Autowired
    private ObjectMapper mapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
         //如果返回的值本来就是result类型,那么就不必再次进行包装了
         if(body instanceof String){
              return mapper.writeValueAsString(Result.success(body));
         }
      
         return Result.success(body);
    }

解释:

这里就是判断类型是否是一个string类型,如果是string类型,在包装后我们要进行转化为string类,那么这里的objectmapping的使用是什么呢?

ObjectMapper是 Jackson 库(一个常用的 Java 处理 JSON 数据的库)中的一个核心类,主要用于在 Java 对象和 JSON 格式数据之间进行相互转换,在这里主要用于将对象转换为json格式的字符串;

??2.3统一返回格式优点

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

**??**3.统一异常处理

??3.1快速入门

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

代码如下所示:

@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
    @ExceptionHandler
    public Result handlerException(Exception e){
        log.error("发生不知名异常, e: {}", e);
        return Result.fail("内部错误");
    }

注意:小编这里使用统一返回类型来进行演示的,这里添加了@slf4j来进行错误日志的打印;此时我们自己手动构造一个错误;

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("t1")
    public String t1(){
        int a=10/0;
        return "t1";
    }
}

很明显这是一种算数异常的出现,那么此时我们进行运行后,在postman中可以看到此时的情况是如何的;

可以看到这里就是出现了内部错误;

??3.2多种异常

代码如下:

 @ExceptionHandler
    public Result handlerException(Exception e){
        log.error("发生不知名异常, e: {}", e);
        return Result.fail("内部错误");
    }
    @ExceptionHandler
    public Result handlerException(NullPointerException e){
        log.error("发生空指针异常, e: {}", e);
        return Result.fail("发生空指针异常");
    }
    @ExceptionHandler
    public Result handlerException(ArithmeticException e){
        log.error("发生算数异常, e: {}", e);
        return Result.fail("发生算数异常");
    }

那么此时可以看到,我们列举了不止一种异常,一个父类异常,两个子类异常,那么此时我们再次进行运行,并试一下controller中的算数异常;

可以看到此时得到的就是算数异常;

总结:

在出现一个父类异常时,和出现一个对应的子类异常时,优先就是使用子类异常处理,若没有对应的子类异常,那么就是使用父类的异常处理;这里涉及到原码小编就不再过多赘述了;

??3.3统一异常处理优点

1.保障代码质量:确保异常处理方式统一规范,避免因开发人员差异导致的不一致,使代码遵循相同规则,增强可读性与可维护性。
2.强化系统性能:全面捕获各类异常,采取诸如重试、降级等应对策略,有效防止系统因异常而崩溃,维持稳定运行,提升健壮性。
3.助力问题排查:详细记录异常信息,包括类型、发生位置及堆栈详情,方便开发人员依据日志迅速追溯根源,实现高效调试。
4.优化用户感受:向客户端反馈简洁友好的错误消息,屏蔽复杂技术细节,使用户能直观了解问题,提升交互体验。

**??**4.总结

本期接着上回,讲解了关于适配器模式,以及Spring统一功能处理的统一返回格式,以及统一异常处理,当然这里涉及原码,大家可以去看看,翻一翻;

???~~~~最后希望与诸君共勉,共同进步!!!


???以上就是本期内容了, 感兴趣的话,就关注小编吧。

???期待你的关注~~~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32基础篇(三)------滴答定时器

滴答定时器简介 SysTick定时器(STK) 处理器有一个24位系统定时器SysTick,它从重新加载值倒计时到零,在下一个时钟沿重新加载(换行)LOAD寄存器中的值,然后对后续时钟倒计时。当处理器暂停调试时&…

Sublime Text4安装、汉化

-------------2025-02-22可用---------------------- 官方网址下载:https://www.sublimetext.com 打开https://hexed.it 点击打开文件找到软件安装目录下的 ctrlf 查找 8079 0500 0f94 c2右边启用替换替换为:c641 0501 b200 90点击替换按钮 替换完成后 另存为本地…

CameraX学习1-关于预览、拍照、对焦

关于CameraX是否可以打开多种特殊摄像头,例如广角、长焦、景深等等 虽然CameraSelector只简单定义了前置后置,没具体指明摄像头,但是可以跟Camera2 API的CameraCharacteristics结合使用,获取对应的cameraid,再传入Came…

【愚公系列】《Python网络爬虫从入门到精通》033-DataFrame的数据排序

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…

RBF神经网络+NSGAII多目标优化算法,工艺参数优化、工程设计优化(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.RBF神经网络NSGAII多目标优化算法(Matlab完整源码和数据) 多目标优化是指在优化问题中同时考虑多个目标的优化过程。在多目标优化中,通常存在多个冲突的目标,即改善一…

执行yum -y install npt 报错解决

Cannot find a valid baseurl for repo: base/7/x86_64 解决办法 一、检查网络连接 确保你的服务器可以访问互联网。你可以使用 ping 命令来测试: ping www.baidu.com 若能访问外网,则网络没问题,否则检查网络 二、修改CentOS-Base.rep…

Android Studio 新版本Gradle通过JitPack发布Maven仓库示例

发布本地仓库示例:https://blog.csdn.net/loutengyuan/article/details/145938967 以下是基于 Android Studio 24.2.2(Gradle 8.10.2 AGP 8.8.0 JDK17) 的通过JitPack发布Maven仓库示例,包含aar和jar的不同配置: 1.…

【官方配图】win10/win11 安装cuda 和 cudnn

文章目录 参考资料1.安装cuda toolkit1. 下载安装包2.安装验证 2. 安装cudnn下载cudnn安装包安装cudnn安装后的配置 参考资料 官方nvidia安装cuda官方nvidia安装cudnn 1.安装cuda toolkit 1. 下载安装包 下载地址 https://developer.nvidia.com/cuda-downloads?target_osW…

水滴tabbar canvas实现思路

废话不多说之间看效果图,只要解决了这个效果水滴tabbar就能做出来了 源码地址 一、核心实现步骤分解 布局结构搭建 使用 作为绘制容器 设置 width=600, height=200 基础尺寸 通过 JS 动态计算实际尺寸(适配高清屏) function initCanvas() {// 获取设备像素比(解决 Re…

神经网络 - 激活函数(Sigmoid 型函数)

激活函数在神经元中非常重要的。为了增强网络的表示能力和学习能力,激活函数需要具备以下几点性质: (1) 连续并可导(允许少数点上不可导)的非线性函数。可导的激活函数可以直接利用数值优化的方法来学习网络参数. (2) 激活函数及其导函数要尽可能的简单&#xff0…

2.5 运算符2

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的 2.5.3 赋值运算符 赋值运算符将值存储在左操作数指定的对象中。有两种赋值操作: 1、简单赋值,使用。其中第二…

DeepSeek + 自由职业 发现新大陆,从 0 到 1 全流程跑通商业 IP

DeepSeek 自由职业 发现新大陆,从 0 到 1 全流程跑通商业 IP 商业定位1. 商业定位分析提示词2. 私域引流策略提示词3. 变现模型计算器提示词4. 对标账号分析提示词5. 商业IP人设打造提示词6. 内容选题策略提示词7. 用户人群链分析提示词8. 内容布局与转化路径设计提…

【Python】网络爬虫——词云wordcloud详细教程,爬取豆瓣最新评论并生成各式词云

目录 一、功能介绍 二、关键技术 1、安装WordCloud 2、利用WordCloud 1、WordCloud的基础用法 **相关参数介绍** **WordCloud 提供的方法如下** 2、WordCloud的应用举例 3、设置停用词 4、WordCloud使用词频 三、程序设计的步骤 1、抓取网页数据 2、数据清洗 3、…

第39天:安全开发-JavaEE应用SpringBoot框架Actuator监控泄漏Swagger自动化

时间轴: Java知识点: 功能:数据库操作,文件操作,序列化数据,身份验证,框架开发,第三方组件使用等. 框架库:MyBatis,SpringMVC,SpringBoot&#xf…

综合练习 —— 递归、搜索与回溯算法

目录 一、1863. 找出所有子集的异或总和再求和 - 力扣(LeetCode) 算法代码: 代码思路 问题分析 核心思想 实现细节 代码解析 初始化 DFS 函数 时间复杂度 空间复杂度 示例运行 输入 运行过程 总结 二、 47. 全排列 II - 力扣&a…

【Java SE】Java中String的内存原理

参考笔记: Java String 类深度解析:内存模型、常量池与核心机制_java stringx、-CSDN博客 解析java中String的内存原理_string s1 new string("ab");内存分析-CSDN博客 目录 1.String初识 2.字符串字面量 3.内存原理图 4. 示例验证 4.…

IDEA提示将方法形参更改为(什么什么类型),要检查对应的实体类中的字段类型是否正确

IDEA提示inviteCodeId应该是字符串,明显不对,后来检查发现是FakeRegistration类中把inviteCodeId定义为String类型了。

【芯片设计】NPU芯片前端设计工程师面试记录·20250227

应聘公司 某NPU/CPU方向芯片设计公司。 小声吐槽两句,前面我问了hr需不需要带简历,hr不用公司给打好了,然后我就没带空手去的。结果hr小姐姐去开会了,手机静音( Ĭ ^ Ĭ )面试官、我、另外的hr小姐姐都联系不上,结果就变成了两个面试官和我一共三个人在会议室里一人拿出…

初阶数据结构(C语言实现)——3顺序表和链表(3)

3.链表 3.1 链表的概念及结构 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 链表的物理结构 1.从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续…

使用 VSCode 代替 BeyondStudio for NXP 开发 JN 5169

使用 VSCode 代替 BeyondStudio for NXP 开发 JN 5169 一、安装 VSCode二、搭建 NXP JN5169 ZigBee 3.0 开发环境和下载示例工程三、配置 VSCode1、配置环境变量 MYSYS_HOME2、VSCode 安装以下插件3、VSCode 配置头文件路径 四、编译工程1、JN-AN-1219 有 6 个构建选项2、修改 …