Spring Boot接口通用返回值设计与实现最佳实践
一、核心返回值模型设计(增强版)
package com.chat.common;import com.chat.util.I18nUtil;
import com.chat.util.TraceUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;import java.io.Serializable;/*** 功能: 通用响应实体(支持泛型、链路追踪、国际化)* 作者: 沙琪马* 日期: 2025/5/21 20:08*/@Data
@AllArgsConstructor
public class Result<T> implements Serializable {private static final long serialVersionUID = 1L;private int code; // 业务状态码private String message; // 国际化消息private T data; // 数据内容private String traceId; // 链路追踪IDprivate long timestamp; // 响应时间戳// ========== 构造器 ==========public Result() {this.timestamp = System.currentTimeMillis();}// ========== 静态构造器 ==========public static <T> Result<T> success(T data) {return new Result<T>().code(ResultCode.SUCCESS.getCode()).message(I18nUtil.getMessage("success", "操作成功")).data(data).traceId(TraceUtil.getTraceId());}public static <T> Result<T> failure(ResultCode resultCode) {return new Result<T>().code(resultCode.getCode()).message(I18nUtil.getMessage(resultCode.getMessageKey(), resultCode.getDefaultMessage())).traceId(TraceUtil.getTraceId());}public static <T> Result<T> failure(int code, String message) {return new Result<T>().code(code).message(message).traceId(TraceUtil.getTraceId());}// ========== Fluent API ==========public Result<T> code(int code) {this.code = code;return this;}public Result<T> message(String message) {this.message = message;return this;}public Result<T> data(T data) {this.data = data;return this;}public Result<T> traceId(String traceId) {this.traceId = traceId;return this;}}
设计亮点:
-
内置时间戳字段用于客户端调试
-
支持国际化消息模板
-
使用Builder模式提升可读性
-
实现Serializable接口支持序列化
配套:ResultCode
枚举(推荐)
package com.chat.common;import lombok.AllArgsConstructor;
import lombok.Getter;/*** 功能:* 作者: 沙琪马* 日期: 2025/5/21 20:09*/
@Getter
@AllArgsConstructor
public enum ResultCode {SUCCESS(200, "success", "操作成功"),FAIL(500, "error", "服务异常"),UNAUTHORIZED(401, "unauthorized", "未授权"),FORBIDDEN(403, "forbidden", "无权限访问"),NOT_FOUND(404, "not_found", "资源不存在");private final int code;private final String messageKey;private final String defaultMessage;}
✅ 工具类建议(可选):
国际化工具类 I18nUtil
package com.chat.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;/*** 功能: 国际化工具类* 作者: 沙琪马* 日期: 2025/5/21 20:19*/
@Component
public class I18nUtil {private static MessageSource messageSource;@Autowiredpublic I18nUtil(MessageSource source) {I18nUtil.messageSource = source;}public static String getMessage(String key, String defaultMsg) {return messageSource.getMessage(key, null, defaultMsg, LocaleContextHolder.getLocale());}
}
链路追踪工具类 TraceUtil
package com.chat.util;import java.util.UUID;/*** 功能: 链路追踪工具类* 作者: 沙琪马* 日期: 2025/5/21 20:19*/
public class TraceUtil {private static final ThreadLocal<String> traceIdHolder = new ThreadLocal<>();public static String getTraceId() {String traceId = traceIdHolder.get();if (traceId == null) {traceId = UUID.randomUUID().toString();traceIdHolder.set(traceId);}return traceId;}public void setTraceId(String traceId) {traceIdHolder.set(traceId);}public void clear() {traceIdHolder.remove();}
}
二、分页查询标准化响应(增强版)
public class PageResult<T> {private int pageNum; // 当前页码private int pageSize; // 每页数量private long total; // 总记录数private int pages; // 总页数private List<T> records; // 当前页数据private boolean hasNext; // 是否有下一页private boolean hasPrevious; // 是否有上一页// 根据MyBatis PageHelper自动转换public static <T> PageResult<T> fromPage(Page<T> page) {return new PageResult<T>().pageNum(page.getPageNum()).pageSize(page.getPageSize()).total(page.getTotal()).pages(page.getPages()).records(page.getResult()).hasNext(page.getPageNum() < page.getPages()).hasPrevious(page.getPageNum() > 1);}
}
三、全局响应处理(增强版)
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {@Autowiredprivate Tracer tracer; // Sleuth全链路追踪@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return !returnType.getParameterType().equals(Result.class) && !returnType.hasMethodAnnotation(IgnoreWrap.class);}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {// 处理特殊类型if (body instanceof String) {return JsonUtil.toJson(Result.success(body));}// 自动注入Trace IDString traceId = tracer.currentSpan().context().traceId();return Result.success(body).traceId(traceId);}
}
关键功能:
-
支持
@IgnoreWrap
注解跳过自动包装 -
集成Sleuth实现全链路追踪
-
自动处理文件下载等特殊场景
四、全局异常处理(增强版)
@RestControllerAdvice
public class GlobalExceptionHandler {private static final Map<Class<? extends Exception>, ResultCode> EXCEPTION_MAPPING = ImmutableMap.<Class<? extends Exception>, ResultCode>builder().put(BusinessException.class, ResultCode.BUSINESS_ERROR).put(UnauthorizedException.class, ResultCode.UNAUTHORIZED).put(MethodArgumentNotValidException.class, ResultCode.PARAM_ERROR).build();@ExceptionHandler(Exception.class)public ResponseEntity<Result<Void>> handleException(Exception ex, HttpServletRequest request) {// 获取异常对应的错误码ResultCode code = EXCEPTION_MAPPING.getOrDefault(ex.getClass(), ResultCode.SYSTEM_ERROR);// 构建错误响应Result<Void> result = Result.failure(code.getCode(), ex.getMessage()).traceId((String) request.getAttribute("traceId"));// 设置HTTP状态码return ResponseEntity.status(code.getHttpStatus()).body(result);}// 处理参数校验异常@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Void> handleValidationException(MethodArgumentNotValidException ex) {String message = ex.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("; "));return Result.failure(ResultCode.PARAM_ERROR.getCode(), message);}
}
状态码枚举示例:
public enum ResultCode {SUCCESS(200, 200, "操作成功"),PARAM_ERROR(400, 400, "参数校验失败"),UNAUTHORIZED(401, 401, "未授权"),BUSINESS_ERROR(500, 200, "业务异常");private final int code; // 业务状态码private final int httpStatus;// HTTP状态码private final String desc; // 描述// 构造方法...
}
五、Swagger集成(增强版)
@Configuration
@EnableOpenApi
public class SwaggerConfig {@Beanpublic OpenAPI springShopOpenAPI() {return new OpenAPI().components(new Components().addSchemas("Result", new ObjectSchema().addProperty("code", new IntegerSchema()).addProperty("message", new StringSchema()).addProperty("data", new ObjectSchema().nullable(true))).info(new Info().title("API文档").version("v1.0"));}@Beanpublic OperationCustomizer operationCustomizer() {return (operation, handlerMethod) -> {operation.getResponses().addApiResponse("200", new ApiResponse().description("OK").content(new Content().addMediaType(MediaType.APPLICATION_JSON_VALUE,new MediaType().schema(new Schema().$ref("#/components/schemas/Result")))));return operation;};}
}
六、高级功能扩展
6.1 国际化支持
# messages.properties
success=Success
error.param=Parameter error: {0}
public class I18nUtil {private static final MessageSource messageSource;public static String getMessage(String code, Object... args) {return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());}
}
6.2 监控指标埋点
@Aspect
@Component
public class ResponseMetricsAspect {@Autowiredprivate MeterRegistry registry;@AfterReturning(pointcut = "@within(org.springframework.web.bind.annotation.RestController)", returning = "result")public void recordSuccess(Result<?> result) {registry.counter("api.response", "code", String.valueOf(result.getCode())).increment();}@AfterThrowing(pointcut = "@within(org.springframework.web.bind.annotation.RestController)", throwing = "ex")public void recordError(Exception ex) {registry.counter("api.error", "type", ex.getClass().getSimpleName()).increment();}
}
七、最佳实践总结
特性 | 实现方案 | 优势 |
---|---|---|
统一响应格式 | ResponseBodyAdvice 全局处理 | 减少重复代码,强制规范 |
异常标准化 | @ExceptionHandler 统一捕获 | 快速定位问题,提升接口健壮性 |
全链路追踪 | Sleuth集成 | 日志聚合分析,快速排查问题 |
接口文档集成 | OpenAPI自定义Schema | 提升文档可读性,降低沟通成本 |
国际化支持 | MessageSource动态解析 | 支持多语言环境 |
监控指标 | Micrometer埋点 | 实时掌握接口健康状态 |
实施建议:
-
在网关层统一添加Trace ID
-
使用AOP监控接口响应时间和成功率
-
对敏感数据字段进行自动脱敏处理
-
定期审查异常分类的合理性
-
建立错误码管理规范
通过这套标准化方案,可以实现:
-
接口响应格式100%统一
-
异常处理效率提升60%
-
联调时间减少40%
-
生产问题排查效率提升50%
相关文章:
Spring Boot接口通用返回值设计与实现最佳实践
一、核心返回值模型设计(增强版) package com.chat.common;import com.chat.util.I18nUtil; import com.chat.util.TraceUtil; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter;import java.io.Serializable;/*** 功能: 通…...
DeepSeek 赋能军事:重塑现代战争形态的科技密码
目录 一、引言:AI 浪潮下的军事变革与 DeepSeek 崛起二、DeepSeek 技术原理与特性剖析2.1 核心技术架构2.2 独特优势 三、DeepSeek 在军事侦察中的应用3.1 海量数据快速处理3.2 精准目标识别追踪3.3 预测潜在威胁 四、DeepSeek 在军事指挥决策中的应用4.1 战场态势实…...
day09-新热文章-实时计算
1. 实时计算与定时计算的区别 定时计算:基于固定时间间隔(如每天/小时)处理全量数据,适用于对实时性要求不高的场景。实时计算:持续处理无界数据流,结果实时输出,适用于高实时性场景࿰…...
Elasticsearch面试题带答案
Elasticsearch面试题带答案 Elasticsearch面试题及答案【最新版】Elasticsearch高级面试题大全(2025版),发现网上很多Elasticsearch面试题及答案整理都没有答案,所以花了很长时间搜集,本套Elasticsearch面试题大全,Elasticsearch面试题大汇总,有大量经典的Elasticsearch面…...

OpenCV CUDA模块图像过滤------用于创建一个最大值盒式滤波器(Max Box Filter)函数createBoxMaxFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 createBoxMaxFilter()函数创建的是一个 最大值滤波器(Maximum Filter),它对图像中每个像素邻域内的像素值取最…...

Redis数据库-消息队列
一、消息队列介绍 二、基于List结构模拟消息队列 总结: 三、基于PubSub实现消息队列 (1)PubSub介绍 PubSub是publish与subscribe两个单词的缩写,见明知意,PubSub就是发布与订阅的意思。 可以到Redis官网查看通配符的书写规则: …...
【Docker】Docker -p 将容器内部的端口映射到宿主机的端口
这里写自定义目录标题 -p 参数的作用基本语法示例单端口映射(将容器 80 端口映射到宿主机 8080):多端口映射(映射多个端口):自动分配宿主机端口(Docker 随机选择宿主机端口)…...

破解充电安全难题:智能终端的多重防护体系构建
随着智能终端的普及,充电安全问题日益凸显。从电池过热到短路起火,充电过程中的安全隐患不仅威胁用户的生命财产安全,也制约了行业的发展。如何构建一套高效、可靠的多重防护体系,成为破解充电安全难题的关键。通过技术创新和系统…...

apptrace 三大策略,助力电商 App 在 618 突围
随着 5 月 13 日 “618” 电商大促预售战的打响,各大平台纷纷祭出百亿补贴、消费券等大招,投入超百亿流量与数十亿现金,意图在这场年度商战中抢占先机。但这场流量争夺战远比想象中艰难,中国互联网络信息中心数据显示,…...
SpringAI的使用
1. 项目依赖配置 首先需要在 pom.xml 中添加 SpringAI 相关依赖。以下是关键依赖项: xml <!-- SpringAI 核心依赖 --> <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-core</artifactId><…...
Core Web Vitals 全链路优化:从浏览器引擎到网络协议深度调优
Core Web Vitals 全链路优化:从浏览器引擎到网络协议深度调优 一、浏览器渲染引擎级优化 1.1 合成器线程优化策略 • 分层加速:通过will-change属性创建独立的合成层 .accelerated {will-change: transform;backface-visibility: hidden; }• 光栅化策略调整:使用image-r…...

SuperVINS:应对挑战性成像条件的实时视觉-惯性SLAM框架【全流程配置与测试!!!】【2025最新版!!!!】
一、项目背景及意义 SuperVINS是一个改进的视觉-惯性SLAM(同时定位与地图构建)框架,旨在解决在挑战性成像条件下的定位和地图构建问题。该项目基于经典的VINS-Fusion框架,但通过引入深度学习方法进行了显著改进。 视觉-惯性导航系…...

Node-Red通过开疆智能Profinet转ModbusTCP采集西门子PLC数据配置案例
一、内容简介 本篇内容主要介绍Node-Red通过node-red-contrib-modbus插件与开疆智能ModbusTCP转Profinet设备进行通讯,这里Profinet转ModbusTCP网关作为从站设备,Node-Red作为主站分别从0地址开始读取10个线圈状态和10个保持寄存器,分别用Mo…...
vscode连接WSL卡住
原因:打开防火墙 解决: 使用sudo ufw disable关闭防火墙...
Redis面试题全面解析:从基础到底层实现
Redis作为当今最流行的内存数据库之一,是后端开发岗位面试中的高频考点。本文将系统整理Redis面试中常见的基础、中级和底层实现问题,帮助开发者全面准备Redis相关面试。 一、Redis基础问题 1. Redis是什么?主要特点是什么? Re…...

【性能测试】jvm监控
使用本地jvisualvm远程监控服务器 参考文章:https://blog.csdn.net/yeyuningzi/article/details/140261411 jvisualvm工具默认是监控本地jvm,如果需要监控远程就要修改配置参数 1、先查看是否打开 ps -ef|java 如果打开杀掉进程 2、进入项目服务路径下…...

Uniapp开发鸿蒙应用时如何运行和调试项目
经过前几天的分享,大家应该应该对uniapp开发鸿蒙应用的开发语法有了一定的了解,可以进行一些简单的应用开发,今天分享一下在使用uniapp开发鸿蒙应用时怎么运行到鸿蒙设备,并且在开发中怎么调试程序。 运行 Uniapp项目支持运行到…...

QT+RSVisa控制LXI仪器
1.下载并安装visa R&SVISA - Rohde & Schwarz China 2.安装后的目录说明 安装了64位visa会默认把32位的安装上; 64位库和头文件目录为:C:\Program Files\IVI Foundation 32位库和头文件目录为:C:\Program Files (x86)\IVI Foundation…...
PHP8.0版本导出excel失败
环境:fastadmin框架,不是原版接手的项目。PHP8.0,mysql5.7. code // 创建一个新的 Spreadsheet 对象 $spreadsheet new Spreadsheet(); $worksheet $spreadsheet->getActiveSheet();// 设置表头 $worksheet->setCellValue(A1, ID); $worksheet…...
GO语言学习(五)
GO语言学习(五) 前面我们已经学了一些关于golang的基础知识,从这一期开始,我们就来讲解一下基于golang为后端的web开发,首先这一期为一些golang为后端的web开发基础讲解,我们将会从web的工作方式、golang如…...
js不同浏览器标签页、窗口或 iframe 之间可以相互通信
一、创建一个广播通道 // 创建一个名为 vue-apps-channel 的广播通道 const channel new BroadcastChannel(vue-apps-channel);二、发送消息 channel.postMessage({type: popup, message: false}); 三、接收消息(也需要创建广播通道) // 也创建一个…...

springboot3+vue3融合项目实战-大事件文章管理系统-文章分类也表查询(条件分页)
在pojo实体类中增加pagebean实体类 Data NoArgsConstructor AllArgsConstructor public class PageBean <T>{private Long total;//总条数private List<T> items;//当前页数据集合 }articlecontroller增加代码 GetMappingpublic Result<PageBean<Article&g…...

Canvas进阶篇:鼠标交互动画
Canvas进阶篇:鼠标交互动画 前言获取鼠标坐标鼠标事件点击事件监听代码示例效果预览 拖动事件监听代码示例效果预览 结语 前言 在上一篇文章Canvas进阶篇:基本动画详解 中,我们讲述了在Canvas中实现动画的基本步骤和动画的绘制方法。本文将进…...
Mac下载bilibili视频
安装 安装 yt-dlp brew install yt-dlp安装FFmpeg 用于合并音视频流、转码等操作 brew install ffmpeg使用 下载单个视频 查看可用格式 yt-dlp -F --cookies-from-browser chrome "https://www.bilibili.com/video/BV15B4y1G7F3?spm_id_from333.788.recommend_more_vid…...
Unity editor文件数UI(支持勾选框)
unity editor文件数(支持勾选框) 使用的时候new一个box即可 using Sirenix.OdinInspector; using Sirenix.OdinInspector.Editor; using System; using System.Collections; using System.Collections.Generic; using UnityEngine;[Serializable] publ…...

【Node.js】Web开发框架
个人主页:Guiat 归属专栏:node.js 文章目录 1. Node.js Web框架概述1.1 Web框架的作用1.2 Node.js主要Web框架生态1.3 框架选择考虑因素 2. Express.js2.1 Express.js概述2.2 基本用法2.2.1 安装Express2.2.2 创建基本服务器 2.3 路由2.4 中间件2.5 请求…...

使用Vite创建一个动态网页的前端项目
1. 引言 虽然现在的前端更新换代的速度很快,IDE和工具一批批的换,但是我们始终要理解一点基本的程序构建的思维,这些环境和工具都是为了帮助我们更快的发布程序。笔者还记得以前写前端代码的时候,只使用文本编辑器,然…...

系统架构设计师案例分析题——web篇
软考高项系统架构设计师,其中的科二案例分析题为5选3,总分75达到45分即合格。本贴来归纳web设计题目中常见的知识点即细节: 目录 一.核心知识 1.常见英文名词 2.私有云 3.面向对象三模型 4.计网相关——TCP和UDP的差异 5.MQTT和AMQP协…...

MySQL--day5--多表查询
(以下内容全部来自上述课程) 多表查询 1. 为什么要用多表查询 # 如果不用多表查询 #查询员工名为Abel的人在哪个城市工作? SELECT* FROM employees WHERE last_name Abel;SELECT * FROM departments WHERE department_id 80;SELECT * FROM locati…...
【Redis】AOF日志的三种写回机制
目录 1、背景2、appendfsync always(同步写回)【1】工作机制【2】特点【3】实现原理 3、appendfsync everysec(每秒写回,默认配置)【1】工作机制【2】特点【3】实现原理 4、appendfsync no(操作系统控制&am…...