程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 后端开发

    • Spring Boot多模块项目开发
    • Spring Boot图片资源返回
    • Spring Boot文件上传
    • Spring Boot文件下载
    • 对接第三方文件上传
    • Servlet 原生API
    • HttpServletResponse 和 ResponseEntity
    • 后端解决跨域问题
    • 后端拦截器
    • SpringBoot+Vue实现邮件发送与验证码验证
    • 谷歌验证码
    • 利用hutool工具类实现图片验证码
    • 统一返回格式
      • 统一返回格式与异常处理封装方案
        • 1. 状态码枚举类:ResultCode
        • 2. 统一返回对象:CommonResult<T>
        • 3. 自定义异常类:CustomException
        • 4. 全局异常处理:GlobalExceptionHandler
        • 4.1.异常信息分类与重要参数
        • 4.2 详细异常参数说明
        • 4.3 全局异常处理器中的定制打印
        • 4. 解读日志输出的结构
        • 5. 补充说明:如何优化堆栈信息的打印
        • 5. 工具类:ResultUtil
        • 6. Controller 层的使用
      • 统一返回格式示例说明
        • 1. 成功返回示例
        • 2. 失败返回示例
        • 3. 自定义状态码返回示例
        • 4. 自定义异常返回示例
        • 5. 全局异常处理返回示例
    • 通用 普通 登录模块
    • 通用 JWT 登录认证模块
    • 通用 普通 注册模块
    • 基于 MyBatis curd
    • 基于 MyBatis-Plus curd
    • Java 常见对象模型
    • 开发枚举的使用
    • MyBatis与MyBatis-Plus日期类型处理
    • 接口日志拦截基础版
    • 接口日志拦截进阶版
    • 文件操作工具类
    • Spring Boot 数据校验
    • 幂等性
  • 前端开发

  • 开发笔记
  • 后端开发
scholar
2024-12-27
目录

统一返回格式

# 统一返回格式与异常处理封装方案

在企业开发中,后端接口需要统一的返回格式,以保证前后端交互的一致性和易维护性。本文将详细总结如何在 Spring Boot 项目中实现企业级统一返回格式和异常处理的封装,包含以下部分:

  1. 状态码枚举类:ResultCode
  2. 统一返回对象:CommonResult<T>
  3. 自定义异常类:CustomException
  4. 全局异常处理:GlobalExceptionHandler
  5. 工具类:ResultUtil
  6. Controller 层的使用示例

# 1. 状态码枚举类:ResultCode

说明:状态码枚举类用于统一管理接口返回的状态码及其对应的描述信息。这样可以避免在项目中直接使用硬编码状态码,提高代码的可维护性和可读性。

/**
 * @description 状态码枚举类,用于统一管理所有接口的状态码和描述信息
 */
public enum ResultCode {
    // 成功请求
    SUCCESS(200, "操作成功"),

    // 通用错误
    FAILED(400, "请求失败"),
    VALIDATE_FAILED(404, "参数校验失败"),
    UNAUTHORIZED(401, "未登录或Token已过期"),
    FORBIDDEN(403, "没有相关权限"),

    // 客户端错误
    BAD_REQUEST(400, "请求参数错误"),
    NOT_FOUND(404, "资源未找到"),
    METHOD_NOT_ALLOWED(405, "请求方法不支持"),
    CONFLICT(409, "资源冲突"),

    // 服务端错误
    INTERNAL_SERVER_ERROR(500, "服务器内部错误"),
    NOT_IMPLEMENTED(501, "未实现的功能"),
    BAD_GATEWAY(502, "网关错误"),
    SERVICE_UNAVAILABLE(503, "服务不可用"),
    GATEWAY_TIMEOUT(504, "网关超时"),

    // 数据库错误
    DATABASE_ERROR(600, "数据库操作异常"),
    DATA_NOT_FOUND(601, "数据未找到"),
    DATA_CONFLICT(602, "数据冲突"),
    
    // 业务错误
    BUSINESS_ERROR(700, "业务逻辑错误"),
    OPERATION_FAILED(701, "操作失败"),
    DATA_PROCESSING_ERROR(702, "数据处理异常");

    // 状态码
    private final int code;

    // 状态码描述信息
    private final String message;

    // 构造函数私有化,防止外部直接调用
    ResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    /**
     * 获取状态码
     *
     * @return 状态码
     */
    public int getCode() {
        return code;
    }

    /**
     * 获取状态码描述信息
     *
     * @return 描述信息
     */
    public String getMessage() {
        return message;
    }

    /**
     * 根据状态码获取枚举
     *
     * @param code 状态码
     * @return 对应的枚举类型
     */
    public static ResultCode fromCode(int code) {
        for (ResultCode resultCode : values()) {
            if (resultCode.getCode() == code) {
                return resultCode;
            }
        }
        throw new IllegalArgumentException("未知的状态码: " + code);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

重要 API 和参数说明:

  • getCode():返回枚举中的状态码,类型为 int。
  • getMessage():返回状态码对应的描述信息,类型为 String。

# 2. 统一返回对象:CommonResult<T>

说明:CommonResult<T> 是一个通用的返回对象,用于封装接口的返回结果。它支持泛型,因此可以适用于不同类型的数据返回。通过统一返回结构,可以确保所有接口返回的数据格式一致,从而简化前后端交互的处理流程。

package com.scholar.springbootscaffolding.common;

import com.scholar.springbootscaffolding.enums.ResultCode;
import lombok.Data;

/**
 * @param <T> 返回数据的类型
 * @description 通用返回对象,用于统一接口的返回结构
 */
@Data
public class CommonResult<T> {

    // 状态码(如 200 成功,400 失败等)
    private Integer code;

    // 返回消息(如 "操作成功","请求失败" 等)
    private String message;

    // 返回数据,支持任意类型
    private T data;

    // 私有构造函数,防止外部直接实例化
    private CommonResult(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    /**
     * 成功返回结果(携带数据)
     *
     * @param data 返回的数据
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> success(T data) {
        return new CommonResult<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
    }

    /**
     * 成功返回结果(不携带数据)
     *
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> success() {
        return new CommonResult<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);
    }

    /**
     * 失败返回结果
     *
     * @param message 错误描述
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> failed(String message) {
        return new CommonResult<>(ResultCode.FAILED.getCode(), message, null);
    }

    /**
     * 失败返回结果(使用默认的失败信息)
     *
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> failed() {
        return new CommonResult<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMessage(), null);
    }

    /**
     * 自定义返回结果(支持自定义状态码和数据)
     *
     * @param resultCode 状态码枚举
     * @param data       返回的数据
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode, T data) {
        return new CommonResult<>(resultCode.getCode(), resultCode.getMessage(), data);
    }

    /**
     * 自定义返回结果(不携带数据)
     *
     * @param resultCode 状态码枚举
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode) {
        return new CommonResult<>(resultCode.getCode(), resultCode.getMessage(), null);
    }

    /**
     * 自定义返回结果,支持自定义消息和数据
     *
     * @param resultCode 状态码枚举
     * @param message    自定义的消息
     * @param data       返回的数据
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode, String message, T data) {
        return new CommonResult<>(resultCode.getCode(), message, data);
    }

    /**
     * 自定义返回结果,支持自定义消息,不携带数据
     *
     * @param resultCode 状态码枚举
     * @param message    自定义的消息
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode, String message) {
        return new CommonResult<>(resultCode.getCode(), message, null);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

重要 API 和参数说明:

  • success(T data):返回成功的结果并携带数据。
  • failed(String message):返回失败结果并附带错误消息。
  • custom(ResultCode resultCode, T data):支持自定义状态码和数据返回。

# 3. 自定义异常类:CustomException

说明:自定义异常类用于处理业务逻辑中可预见的异常情况,如参数校验失败、权限不足等。通过自定义异常,可以在业务层更好地控制错误处理。

import lombok.Getter;

/**
 * @description 自定义异常类,用于处理业务逻辑中的特定异常
 */
@Getter
public class CustomException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    // 状态码
    private final ResultCode resultCode;

    /**
     * 构造函数,直接传入状态码枚举
     *
     * @param resultCode 状态码枚举
     */
    public CustomException(ResultCode resultCode) {
        super(resultCode.getMessage());
        this.resultCode = resultCode;
    }

    /**
     * 构造函数,支持自定义错误信息
     *
     * @param resultCode 状态码枚举
     * @param message    自定义错误信息
     */
    public CustomException(ResultCode resultCode, String message) {
        super(message);
        this.resultCode = resultCode;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

重要 API 和参数说明:

  • getResultCode():返回异常对应的状态码,类型为 ResultCode。

# 4. 全局异常处理:GlobalExceptionHandler

在全局异常处理器中,处理异常信息的关键在于如何有效地提取和记录异常信息,使开发者能够快速定位问题。通常,我们希望在记录日志时不带过多的堆栈信息,而是聚焦在有助于排查的关键信息上。以下是全局异常处理中可以定制的异常参数及方法的详细说明。

# 4.1.异常信息分类与重要参数

在处理异常时,我们可以将异常信息分为以下几个重要部分:

  • 异常类型 (e.getClass().getSimpleName()):记录异常的类型,例如 NullPointerException、IllegalArgumentException 等。这有助于快速确定问题的性质。
  • 异常消息 (e.getMessage()):提取异常的简短描述或原因,这是异常抛出时的核心提示信息。
  • 异常堆栈跟踪 (e.getStackTrace()):记录异常的堆栈信息通常会产生大量输出,除非是深入调试,否则我们一般避免直接在日志中输出全部堆栈信息。可以只记录堆栈中的关键位置,例如抛出异常的类和方法。

# 4.2 详细异常参数说明

在全局异常处理中,以下是可以提取并定制打印的异常参数:

  1. getClass().getSimpleName():获取异常的简单类名,这是异常类型的标识。适合在日志中简单明了地描述异常类型。

    String exceptionType = e.getClass().getSimpleName();  // 输出:NullPointerException
    
    1
  2. getMessage():获取异常的消息内容,这是对错误的简要描述。通常是引发异常的主要原因或提示信息。

    String errorMessage = e.getMessage();  // 输出:空指针异常
    
    1
  3. getStackTrace()[0]:获取异常堆栈中的首个位置,一般表示异常抛出的具体类和方法。相较于打印完整堆栈信息,提取首个堆栈信息可以帮助定位代码中的问题位置。

    StackTraceElement firstStackTrace = e.getStackTrace()[0];
    String location = firstStackTrace.toString();  // 输出:com.example.demo.MyClass.myMethod(MyClass.java:25)
    
    1
    2
  4. getCause():获取引发当前异常的原因(如果有)。这在处理多级异常时尤为有用,可以追溯到最初的异常源头。

    Throwable rootCause = e.getCause();
    String causeMessage = (rootCause != null) ? rootCause.getMessage() : "无根本原因";
    
    1
    2
  5. getSuppressed():获取被抑制的异常信息(如果有)。在 Java 7 之后,异常处理机制支持抑制其他异常,例如在 try-with-resources 结构中,资源关闭时抛出的异常会被抑制。

    Throwable[] suppressedExceptions = e.getSuppressed();
    for (Throwable suppressed : suppressedExceptions) {
        logger.error("被抑制的异常:{}", suppressed.getMessage());
    }
    
    1
    2
    3
    4

# 4.3 全局异常处理器中的定制打印

以下是经过定制后的全局异常处理器,简化了异常日志输出,重点记录关键信息,便于快速排查问题:

import com.scholar.springbootscaffolding.common.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Arrays;

@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理所有未捕获的异常
     *
     * @param e 异常对象
     * @return 通用返回对象,包含错误信息
     */
    @ExceptionHandler(Exception.class)
    public CommonResult<Object> handleException(Exception e) {
        // 构建结构化的异常日志
        String formattedLog = formatExceptionLog(e);

        // 打印格式化的异常日志
        logger.error(formattedLog);

        // 返回通用的失败结果,避免直接暴露异常信息
        return CommonResult.failed("系统异常,请联系管理员");
    }

    // 格式化异常信息
    private String formatExceptionLog(Exception e) {
        StringBuilder errorLog = new StringBuilder();
        errorLog.append("\n\n==================== 异常捕获开始 ====================\n");

        // 异常类型
        errorLog.append("【异常类型】: ").append(e.getClass().getName()).append("\n");

        // 解析异常信息,避免重复 Cause 信息
        String filteredMessage = filterDuplicateCause(e.getMessage());
        errorLog.append("【异常信息】: ").append(filteredMessage).append("\n");

        // 异常发生的位置
        StackTraceElement firstElement = e.getStackTrace()[0];
        errorLog.append("【发生位置】: ")
                .append(firstElement.getClassName())
                .append(".")
                .append(firstElement.getMethodName())
                .append(" (")
                .append(firstElement.getFileName())
                .append(":")
                .append(firstElement.getLineNumber())
                .append(")\n");

        // 嵌套异常的处理
        Throwable cause = e.getCause();
        if (cause != null && !cause.getMessage().equals(e.getMessage())) {
            errorLog.append("【嵌套异常】: ").append(cause.getClass().getName())
                    .append(" - ").append(cause.getMessage()).append("\n");
        }

        // 堆栈信息
        errorLog.append("【堆栈信息】: \n");
        Arrays.stream(e.getStackTrace())
                .limit(5) // 控制输出堆栈信息的深度
                .forEach(stackTraceElement -> errorLog.append("\tat ").append(stackTraceElement).append("\n"));

        errorLog.append("==================== 异常捕获结束 ====================\n");

        return errorLog.toString();
    }

    // 过滤重复的 Cause 信息
    private String filterDuplicateCause(String message) {
        if (message == null) {
            return "";
        }
        // 检测并移除重复的 "Cause" 信息
        int firstCauseIndex = message.indexOf("Cause:");
        if (firstCauseIndex != -1) {
            int secondCauseIndex = message.indexOf("Cause:", firstCauseIndex + 6);
            if (secondCauseIndex != -1) {
                return message.substring(0, secondCauseIndex).trim();
            }
        }
        return message;
    }

    /**
     * 处理自定义业务异常
     *
     * @param e 自定义异常对象
     * @return 统一格式的错误结果
     */
    @ExceptionHandler(CustomException.class)
    public CommonResult<Object> handleCustomException(CustomException e) {
        // 记录自定义异常信息,包含业务相关提示
        logger.warn("业务异常 - 信息: {}", e.getMessage());

        // 根据自定义异常中的状态码返回特定的错误信息
        return CommonResult.custom(e.getResultCode(), e.getMessage());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

# 4. 解读日志输出的结构

假设系统发生了一个 NullPointerException,上面的异常处理器会生成如下日志输出:

系统异常 - 类型: NullPointerException | 信息: 空指针异常 | 位置: com.example.demo.MyClass.myMethod(MyClass.java:25)
1

日志包含以下关键信息:

  1. 异常类型:NullPointerException —— 明确问题的类型。
  2. 异常信息:空指针异常 —— 异常的简要描述,通常用于提示开发人员问题的本质。
  3. 异常位置:com.example.demo.MyClass.myMethod(MyClass.java:25) —— 异常发生的具体代码位置,有助于定位问题源头。

# 5. 补充说明:如何优化堆栈信息的打印

对于复杂的异常场景,如果需要更多细节,但又不想打印完整堆栈,可以使用以下策略:

  • 记录关键堆栈层级:除了首个堆栈信息,可能需要打印一些重要层级(如首层和最后一层)。

    logger.error("异常位置 - 首层: {} | 最底层: {}",
            e.getStackTrace()[0].toString(),
            e.getStackTrace()[e.getStackTrace().length - 1].toString()
    );
    
    1
    2
    3
    4
  • 记录异常链条:如果异常是由其他异常引发的,可以递归遍历并记录所有引发的原因。

    Throwable cause = e;
    while (cause != null) {
        logger.error("引发原因: {} - {}", cause.getClass().getSimpleName(), cause.getMessage());
        cause = cause.getCause();
    }
    
    1
    2
    3
    4
    5

通过以上定制策略,你可以更清晰、更简洁地记录异常信息,避免被冗长的堆栈信息干扰,从而专注于解决关键问题。


# 5. 工具类:ResultUtil

说明:工具类封装了常用的返回结果生成方法,简化了开发过程。它提供了快速生成成功、失败结果的方法,还支持抛出自定义异常。

/**
 * @description 结果工具类,简化返回结果的生成
 */
public class ResultUtil {

    /**
     * 返回成功结果(携带数据)
     *
     * @param data 返回的数据
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> success(T data) {
        return CommonResult.success(data);
    }

    /**
     * 返回成功结果(不携带数据)
     *
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> success() {
        return CommonResult.success();
    }

    /**
     * 返回失败结果(自定义错误信息)
     *
     * @param message 错误描述
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> failed(String message) {
        return CommonResult.failed(message);
    }

    /**
     * 返回失败结果(使用默认的错误信息)
     *
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> failed() {
        return CommonResult.failed();
    }

    /**
     * 返回自定义结果
     *
     * @param resultCode 状态码枚举
     * @param data       返回的数据
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode, T data) {
        return CommonResult.custom(resultCode, data);
    }

    /**
     * 返回自定义结果(不携带数据)
     *
     * @param resultCode 状态码枚举
     * @return 通用返回对象
     */
    public static <T> CommonResult<T> custom(ResultCode resultCode) {
        return CommonResult.custom(resultCode);
    }

    /**
     * 抛出自定义异常
     *
     * @param resultCode 状态码枚举
     * @param message    自定义错误信息
     */
    public static void throwCustomException(ResultCode resultCode, String message) {
        throw new CustomException(resultCode, message);
    }

    /**
     * 抛出自定义异常(使用默认信息)
     *
     * @param resultCode 状态码枚举
     */
    public static void throwCustomException(ResultCode resultCode) {
        throw new CustomException(resultCode);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

重要 API 和参数说明:

  • success(T data):快速生成成功结果。
  • failed(String message):快速生成失败结果。
  • throwCustomException(ResultCode resultCode, String message):抛出带有自定义错误信息的异常。

# 6. Controller 层的使用

说明:在实际使用中,Controller 层通过封装好的工具类和异常处理机制,可以快速开发接口,并确保返回数据格式统一。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @description 示例控制器,用于演示统一返回格式的使用
 */
@RestController
@RequestMapping("/api/example")
public class ExampleController {

    /**
     * 获取成功结果的示例
     *
     * @return 通用返回对象
     */
    @GetMapping("/success")
    public CommonResult<String> getSuccess() {
        // 使用工具类生成成功结果
        return ResultUtil.success("这是一个成功的响应");
    }

    /**
     * 获取失败结果的示例
     *
     * @return 通用返回对象
     */
    @GetMapping("/failed")
    public CommonResult<String> getFailed() {
        // 使用工具类生成失败结果
        return ResultUtil.failed("这是一个失败的响应");
    }

    /**
     * 触发自定义异常的示例
     *
     * @return 不返回数据,抛出异常
     */
    @GetMapping("/exception")
    public CommonResult<String> throwException() {
        // 直接抛出自定义异常
        ResultUtil.throwCustomException(ResultCode.VALIDATE_FAILED, "参数校验不通过");
        return null; // 代码不会执行到这里
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

重要 API 和参数说明:CommonResult<T> 中的泛型 T 决定了 data 字段的数据类型。

  • @GetMapping("/success"):演示成功结果的返回,返回的数据为 "这是一个成功的响应"。
  • @GetMapping("/failed"):演示失败结果的返回,返回的数据为 "这是一个失败的响应"。
  • @GetMapping("/exception"):演示自定义异常的抛出,触发参数校验失败的错误。

总结

通过以上封装和示例,您可以实现:

  1. 统一的返回格式:所有接口的返回数据都遵循相同的格式,包含状态码、消息和数据。
  2. 状态码的集中管理:通过枚举类确保状态码及其描述信息的一致性。
  3. 自定义异常处理:在业务逻辑中抛出自定义异常,并在全局异常处理器中进行统一捕获和处理。
  4. 简化开发流程:通过工具类 ResultUtil,快速生成返回结果或抛出异常。

# 统一返回格式示例说明

所有接口返回的数据格式为一个 JSON 对象,包含以下字段:

  • code:状态码,表示请求的处理结果。
  • message:返回的消息,通常用于描述当前操作的结果信息。
  • data:返回的数据,内容根据具体请求有所不同。

格式如下:

{
  "code": "状态码",
  "message": "描述信息",
  "data": "实际返回的数据"
}
1
2
3
4
5

# 1. 成功返回示例

当请求成功且有数据返回时,接口会返回以下格式:

代码:

@GetMapping("/success")
public CommonResult<String> getSuccess() {
    return ResultUtil.success("这是一个成功的响应");
}
1
2
3
4

返回给前端的格式:

{
  "code": 200,
  "message": "操作成功",
  "data": "这是一个成功的响应"
}
1
2
3
4
5
  • code: 200 表示操作成功。
  • message: 操作成功 是默认的成功描述信息。
  • data: 实际返回的业务数据,这里是 "这是一个成功的响应"。

如果请求成功但没有数据需要返回:

{
  "code": 200,
  "message": "操作成功",
  "data": null
}
1
2
3
4
5

# 2. 失败返回示例

当请求失败时,接口会返回以下格式:

代码:

@GetMapping("/failed")
public CommonResult<String> getFailed() {
    return ResultUtil.failed("这是一个失败的响应");
}
1
2
3
4

返回给前端的格式:

{
  "code": 400,
  "message": "这是一个失败的响应",
  "data": null
}
1
2
3
4
5
  • code: 400 表示请求失败。
  • message: 自定义的失败描述信息,这里是 "这是一个失败的响应"。
  • data: 在失败场景中通常为 null。

# 3. 自定义状态码返回示例

当需要返回自定义的状态码和描述信息时:

代码:

@GetMapping("/custom")
public CommonResult<String> getCustom() {
    return CommonResult.custom(ResultCode.FORBIDDEN, "您没有访问权限");
}
1
2
3
4

返回给前端的格式:

{
  "code": 403,
  "message": "您没有访问权限",
  "data": null
}
1
2
3
4
5
  • code: 403 表示没有权限。
  • message: 自定义的错误信息,这里是 "您没有访问权限"。
  • data: 这里没有返回数据,因此为 null。

# 4. 自定义异常返回示例

当在业务中抛出自定义异常时,返回格式如下:

代码:

@GetMapping("/exception")
public CommonResult<String> throwException() {
    ResultUtil.throwCustomException(ResultCode.VALIDATE_FAILED, "参数校验不通过");
    return null; // 代码不会执行到这里
}
1
2
3
4
5

返回给前端的格式:

{
  "code": 404,
  "message": "参数校验不通过",
  "data": null
}
1
2
3
4
5
  • code: 404 表示参数校验失败。
  • message: 这里是自定义的错误信息 "参数校验不通过"。
  • data: 同样在异常情况下,通常为 null。

# 5. 全局异常处理返回示例

当系统出现未捕获的异常时,返回的格式如下:

代码:(这里假设未捕获的异常发生在服务中)

返回给前端的格式:

{
  "code": 400,
  "message": "具体的异常信息",
  "data": null
}
1
2
3
4
5
  • code: 400 表示请求失败,这是默认的全局异常状态码。
  • message: 异常的具体信息,由 Exception 的消息内容决定。
  • data: 异常情况下,返回的数据通常为 null。

编辑此页 (opens new window)
上次更新: 2025/03/16, 22:19:39
利用hutool工具类实现图片验证码
通用 普通 登录模块

← 利用hutool工具类实现图片验证码 通用 普通 登录模块→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式