SpringBoot统一返回结果封装 + 全局异常处理 学习笔记

SpringBoot统一返回结果封装 + 全局异常处理 学习笔记

一、前言

在前后端分离项目开发中,存在两个高频痛点:

  1. 返回格式不统一:不同接口返回数据结构杂乱,前端需要写多套解析逻辑,维护成本极高;
  2. 异常分散难管理:代码中到处写try-catch,重复代码多,异常返回格式不规范。

本节课通过统一Result返回封装类 + 全局异常处理器@RestControllerAdvice 一次性解决以上问题,是企业级后端项目标准基础配置。

二、核心知识点梳理

1. 统一返回格式规范

约定全局返回JSON结构,包含3个固定字段,前端可统一解析:

{
  "code": 200,    // 状态码:200成功,500服务异常
  "message": "提示信息", // 接口说明/异常文案
  "data": null    // 业务数据,成功时携带,异常时为null
}

2. 核心注解说明

注解 作用
@RestControllerAdvice 全局REST接口增强,统一拦截所有Controller抛出的异常
@ExceptionHandler 绑定指定异常类型,捕获后自定义返回信息
@Data(Lombok) 自动生成get/set、toString,简化实体类代码

三、完整代码实现步骤

步骤1:创建通用返回类 Result<T>

存放路径:com.weitoutiao.common.Result
泛型<T>支持任意类型业务数据返回,内置静态方法快速构建成功/失败响应。

package com.weitoutiao.common;

import lombok.Data;

@Data
public class Result<T> {
    // 状态码
    private Integer code;
    // 提示信息
    private String message;
    // 业务数据
    private T data;

    // 私有构造,禁止外部new,统一使用静态方法创建对象
    private Result(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    // 成功:携带数据
    public static <T> Result<T> success(T data) {
        return new Result<>(200, "success", data);
    }

    // 成功:仅返回提示文案,无数据
    public static <T> Result<T> success(String message) {
        return new Result<>(200, message, null);
    }

    // 失败:统一服务异常,code固定500
    public static <T> Result<T> error(String message) {
        return new Result<>(500, message, null);
    }
}

步骤2:创建全局异常处理器 GlobalExceptionHandler

存放路径:com.weitoutiao.common.GlobalExceptionHandler
拦截所有Controller抛出的运行时异常,打印堆栈日志并封装成统一Result返回。

package com.weitoutiao.common;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 捕获所有运行时异常
    @ExceptionHandler(RuntimeException.class)
    public Result<?> handleRuntimeException(RuntimeException e) {
        // 打印异常堆栈,方便后端定位bug
        e.printStackTrace();
        // 异常信息封装统一返回格式
        return Result.error(e.getMessage());
    }
}

步骤3:改造Controller,使用统一返回体

存放路径:com.weitoutiao.controller.HelloController
所有接口返回值统一改为Result<T>,调用Result.success()快速构建响应。

package com.weitoutiao.controller;

import com.weitoutiao.common.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public Result<String> hello() {
        // 调用静态方法,统一封装返回
        return Result.success("微头条后端启动成功!");
    }
}

步骤4:项目完整目录结构

src/main/java/com/weitoutiao
├── common                // 通用工具类包
│   ├── GlobalExceptionHandler  // 全局异常处理器
│   └── Result                 // 统一返回封装类
├── config                // 配置类
├── controller            // 控制器
│   └── HelloController
├── entity                // 实体类
├── mapper                // Mybatis Mapper
├── service               // 业务层
└── WeiTouTiaoSpringBootApplication // 启动类

四、Postman接口测试验证

操作流程

  1. 运行主启动类WeiTouTiaoSpringBootApplication,启动SpringBoot项目;
  2. 打开Postman,新建集合微头条测试;
  3. 在集合内新增GET请求,命名hello;
  4. 请求地址填写:http://localhost:8080/hello;
  5. 点击Send发送请求,查看返回JSON:
{
  "code": 200,
  "message": "微头条后端启动成功!",
  "data": null
}

异常场景测试拓展(可选)

在接口内手动抛出运行时异常,验证全局异常捕获效果:

@GetMapping("/hello")
public Result<String> hello() {
    throw new RuntimeException("服务器内部业务异常");
}

请求后会自动返回统一错误格式:

{
  "code": 500,
  "message": "服务器内部业务异常",
  "data": null
}

五、学习总结

1. 统一返回Result类优势

  • 接口输出标准化,前端仅需一套通用解析逻辑;
  • 静态工厂方法简化代码,不用每次new对象;
  • 泛型兼容字符串、实体、集合等全部业务数据类型。

2. 全局异常处理器优势

  • 消除项目中大量冗余try-catch代码,业务代码更纯粹;
  • 异常统一拦截、统一返回格式,前后端协作更规范;
  • 集中打印异常堆栈,便于线上/线下排查问题。

3. 企业拓展优化方向(后续可完善)

  1. 自定义业务异常类,区分参数错误、权限不足、数据不存在等不同code;
  2. 新增参数校验异常MethodArgumentNotValidException捕获;
  3. 引入日志框架(SLF4J)替换e.printStackTrace(),持久化异常日志;
  4. 封装分页专用返回对象,拓展Result分页字段。

六、踩坑记录

  1. 忘记引入Lombok依赖,@Data注解失效,实体无get/set方法,接口返回空对象;
  2. 异常处理器未加@RestControllerAdvice,无法拦截Controller异常;
  3. 启动类未扫描到common包:正常启动类默认扫描自身及子包,无需额外配置;若分包过深可通过@SpringBootApplication(scanBasePackages = "com.weitoutiao")指定扫描路径。
posted @ 2026-06-18 14:49  05春  阅读(54)  评论(0)    收藏  举报