SpringBoot实现接口:统一返回值、全局异常处理、Swagger接口文档


在 Spring Boot 应用中实现统一返回值和全局异常处理可以带来多方面的好处,这些好处不仅提升了代码的可读性和可维护性,还增强了应用的健壮性和用户体验。以下是一些具体的好处:

代码一致性:

  • 通过定义统一的返回值格式,可以确保整个应用中的API响应结构保持一致。
  • 统一的异常处理机制使得错误信息的返回方式也保持一致,便于前端开发者理解和处理。

可维护性:

  • 集中管理返回值和异常处理逻辑,减少了代码重复,降低了维护成本。
  • 当需要修改返回格式或异常处理逻辑时,只需在统一的地方进行修改,无需逐个API进行更改。

可读性和易用性:

  • 统一的返回值格式使得API文档更加清晰明了,前端开发者可以更容易地理解和使用API。
  • 全局异常处理可以提供详细的错误信息,帮助开发者快速定位问题。

健壮性:

  • 全局异常处理能够捕获和处理应用中的各种异常,避免应用崩溃或返回不友好的错误信息。
  • 通过自定义异常类型,可以更精确地控制异常的处理方式,提高应用的稳定性和安全性。

1、创建项目

(1)创建 SpringBoot 项目,项目结构如下图:

(2)添加 Maven 依赖

在 pom.xml 配置文件中添加 Swagger2、 Slf4j、Lombok 插件依赖。

<!-- Lombok 依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.34</version>
    <scope>provided</scope>
</dependency>

<!-- Slf4j的依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
</dependency>

<!-- Swagger依赖-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!-- Swagger-UI依赖 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

(3)配置相关信息

将默认的 application.properties 文件的后缀修改为“.yml”,即配置文件名称为:application.yml,并配置以下信息:

#主配置文件
server:
  port: 8085

2、实现统一返回值

通过定义统一的返回值格式,可以确保整个应用中的API响应结构保持一致。统一的返回值格式使得API文档更加清晰明了,前端开发者可以更容易地理解和使用API。

(1)在 model.ApiModel 包中,创建 ApiResponseCode 枚举(响应结果编码枚举)。

package com.pjb.business.model.ApiModel;

/**
 * 响应结果编码枚举
 * @author pan_junbiao
 **/
public enum ApiResponseCode
{
    SUCCESS(200000, "操作成功"),
    FAILURE(300000, "操作失败"),
    PARAMETER_ERROR(300001, "参数有误"),
    UNKNOWN_ERROR(300002, "未知错误"),
    EXIST_ACCOUNT_CODE(300003, "账户已存在"),
    UNAUTHORIZED(40001, "认证失败"),
    FORBIDDEN(400002, "无权操作"),
    NOT_FOUND(400004, "资源不存在"),
    INTERNAL_SERVER_ERROR(500001, "服务器内部错误"),
    SERVICE_UNAVAILABLE(500002, "服务暂不可用");

    private final int code;
    private final String message;

    ApiResponseCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

(2)在 model.ApiModel 包中,创建 ApiResponseResult 类(响应结果类)。

package com.pjb.business.model.ApiModel;

import lombok.Data;

/**
 * 响应结果类
 * @author pan_junbiao
 **/
@Data
public class ApiResponseResult<T> {
    private int code;
    private String message;
    private T data;

    public ApiResponseResult(ApiResponseCode apiResponseCode) {
        this.code = apiResponseCode.getCode();
        this.message = apiResponseCode.getMessage();
    }

    public ApiResponseResult(ApiResponseCode apiResponseCode, T data) {
        this.code = apiResponseCode.getCode();
        this.message = apiResponseCode.getMessage();
        this.data = data;
    }
}

3、全局异常处理

全局异常处理可以提供详细的错误信息,帮助开发者快速定位问题。统一的异常处理机制使得错误信息的返回方式也保持一致,便于前端开发者理解和处理。

详细的全局异常处理,请点击浏览文章:《SpringBoot使用@ControllerAdvice和@ExceptionHandler注解实现全局异常处理》

(1)在 exception 包中,创建 ApiResponseException 类(Api操作异常类)。

package com.pjb.business.exception;

import com.pjb.business.model.ApiModel.ApiResponseCode;
import lombok.Data;

/**
 * Api操作异常类
 * 注意:如果继承的是Exception类,那么Spring的事务管理将会失效,
 * 只有继承RuntimeException类才使Spring的事务管理不会失效
 * @author pan_junbiao
 **/
@Data
public class ApiResponseException extends RuntimeException
{
    private ApiResponseCode apiResponseCode; //错误编码信息

    public ApiResponseException(ApiResponseCode apiResponseCode)
    {
        super(apiResponseCode.getMessage());
        this.apiResponseCode = apiResponseCode;
    }
}

(2)在 exception 包中,创建 GlobalExceptionHandler 类(全局异常处理器)。

package com.pjb.business.exception;

import com.pjb.business.model.ApiModel.ApiResponseCode;
import com.pjb.business.model.ApiModel.ApiResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 全局异常处理器
 * 基于@ControllerAdvice和@ExceptionHandler注解
 * @author pan_junbiao
 **/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler
{
    /**
     * 自定义业务异常处理:Api操作异常类
     */
    @ExceptionHandler(ApiResponseException.class)
    @ResponseBody
    public ApiResponseResult businessExceptionHandler(ApiResponseException ex)
    {
        //错误信息
        ApiResponseCode apiResponseCode = ex.getApiResponseCode();

        //记录异常日志
        log.error("[API操作异常] 错误编码:{} 错误信息:{}",apiResponseCode.getCode(),apiResponseCode.getMessage());

        //返回错误信息
        return new ApiResponseResult(apiResponseCode);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public ApiResponseResult exceptionHandler(Exception ex)
    {
        //记录异常日志
        log.error("[系统异常]" + ex.toString());

        //返回错误页面
        return new ApiResponseResult(ApiResponseCode.UNKNOWN_ERROR);
    }

}

4、整合 Swagger 实现接口文档

在项目开发中,一般都是前后端分离开发的,需要由前后端工程师共同定义接口,编写接口文档,之后大家都根据这个接口文档进行开发、维护。为了便于编写和维护稳定,可以使用Swagger来编写API接口文档,以提升团队的沟通效率。

详细Swagger的使用方法,请点击浏览文章:《SpringBoot整合Swagger实现接口文档》

(1)在 config 包中,创建 SwaggerConfig 类(Swagger 配置类)。

package com.pjb.business.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * Swagger 配置类
 * @author pan_junbiao
 **/
@Configuration
@EnableSwagger2
public class SwaggerConfig
{
    /**
     * 创建API应用
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.pjb.business.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 创建该API的基本信息(这些基本信息会展现在文档页面中)
     * 访问地址:http://项目实际地址/swagger-ui.html
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("用户信息管理系统API")
                .description("RESTful APIs")
                .termsOfServiceUrl("http://localhost:8085/")
                .contact("long")
                .version("1.0")
                .build();
    }
}

5、综合实例

【实例】使用 Spring Boot 实现用户信息的查询、新增、修改、删除接口。

(1)在 entity 包中,创建 UserInfo 类(用户信息实体类)。

package com.pjb.business.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * 用户信息实体类
 * @author pan_junbiao
 **/
@Data
@ApiModel(value="用户信息实体类")
public class UserInfo
{
    @ApiModelProperty("用户编号")
    private Long userId;

    @ApiModelProperty("用户名称")
    private String userName;

    @ApiModelProperty("博客信息")
    private String blogName;

    @ApiModelProperty("博客地址")
    private String blogUrl;
}

(2)在 controller 包中,创建 UserController 类(用户信息控制器)。

package com.pjb.business.controller;

import com.pjb.business.entity.UserInfo;
import com.pjb.business.exception.ApiResponseException;
import com.pjb.business.model.ApiModel.ApiResponseCode;
import com.pjb.business.model.ApiModel.ApiResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

/**
 * 用户信息控制器类
 * @author pan_junbiao
 **/
@RestController
@RequestMapping("/user")
@Api(description = "用户信息控制器")
public class UserController
{
    /**
     * 查询用户信息
     */
    @ApiOperation(value = "查询用户信息")
    @RequestMapping(value = "/getUserInfo/{id}", method = RequestMethod.GET)
    public ApiResponseResult<UserInfo> getUserInfo(@PathVariable("id") Long userId)
    {
        if (userId <= 0)
        {
            //使用:全局异常处理
            throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);
        }

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(userId);
        userInfo.setUserName("pan_junbiao的博客");
        userInfo.setBlogName("您好,欢迎访问 pan_junbiao的博客");
        userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");

        //使用:统一返回值
        return new ApiResponseResult(ApiResponseCode.SUCCESS, userInfo);
    }

    /**
     * 新增用户信息
     */
    @ApiOperation(value = "新增用户信息")
    @RequestMapping(value = "/addUserInfo", method = RequestMethod.POST)
    public ApiResponseResult<Boolean> addUserInfo(@RequestBody UserInfo userInfo)
    {
        if (userInfo == null)
        {
            //使用:全局异常处理
            throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);
        }

        //使用:统一返回值
        return new ApiResponseResult(ApiResponseCode.SUCCESS, true);
    }

    /**
     * 修改用户信息
     */
    @ApiOperation(value = "修改用户信息")
    @RequestMapping(value = "/updateUserInfo", method = RequestMethod.POST)
    public ApiResponseResult<Boolean> updateUserInfo(@RequestBody UserInfo userInfo)
    {
        if (userInfo == null && userInfo.getUserId() <= 0)
        {
            //使用:全局异常处理
            throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);
        }

        //使用:统一返回值
        return new ApiResponseResult(ApiResponseCode.SUCCESS, true);
    }

    /**
     * 删除用户信息
     */
    @ApiOperation(value = "删除用户信息")
    @RequestMapping(value = "/deleteUserInfo/{id}", method = RequestMethod.POST)
    public ApiResponseResult<Boolean> deleteUserInfo(@PathVariable("id") Long userId)
    {
        if (userId <= 0)
        {
            //使用:全局异常处理
            throw new ApiResponseException(ApiResponseCode.PARAMETER_ERROR);
        }

        //使用:统一返回值
        return new ApiResponseResult(ApiResponseCode.SUCCESS, true);
    }
}

查看 Swagger 接口文档:

启动项目,访问 http://127.0.0.1:8085/swagger-ui.html 就能看到所展示的RESTful API的页面,可以通过单击具体的API测试请求,来查看代码中配置的信息,以及参数的描述信息。

查询用户信息:

查看全局异常:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【从零开始的LeetCode-算法】3194. 最小元素和最大元素的最小平均值

你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums&#xff0c;其中 n 为偶数。 你需要重复以下步骤 n / 2 次&#xff1a; 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement。将 (minElement maxElement) / 2 加入到 averages …

Apache Linkis + OceanBase:如何提升数据分析效率

计算中间件 Apache Linkis 构建了一个计算中间件层&#xff0c;以实现上层应用程序和底层数据引擎之间的连接、治理和编排。目前&#xff0c;已经支持通过数据源的功能&#xff0c;实现用户通过Linkis 对接并使用 OceanBase数据库。 本文详细阐述了在 Apache Linkis v1.3.2中&a…

零基础学习网络安全,注意这几个高效学习方法,零基础入门到精通,收藏这篇就够了

零基础学习网络安全&#xff0c;注意查收这些有效学习方法 ‍零基础怎么学网络安全?网络安全学习办法有很多&#xff0c;又高效得&#xff0c;也有低效得&#xff0c;还有无效得。今天和我一起来看看网络安全的有效学习秘籍。 ‍ 零基础从什么开始学网络安全&#xff0c;大…

七大经典排序算法优化:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序、归并排序代码详解

目录 排序算法 1.插入排序 2.希尔排序 3.选择排序 4.冒泡排序 5.堆排序 6.快速排序 7.归并排序 排序算法 排序算法是一类用于将数据按照特定顺序&#xff08;如升序或降序&#xff09;排列的算法&#xff0c;常用于优化数据检索和处理。常见的排序算法包括冒泡排序、选…

【Deepin】钉钉下载文件图片闪退问题解决(临时方式)

环境 故障 下载文件、图片等闪退 解决 cd /opt/apps/com.alibabainc.dingtalk/files/7.6.0-Release.4091801/sudo rm -rf ./libstdc.so.6*注&#xff1a; 7.6.0-Release.4091801可能会略有不同&#xff0c;根据实际情况调整保险起见&#xff0c;操作第二行删除命令时&#…

第二十七篇:传输层讲解,TCP系列一

一、传输层的功能 ① 分割与重组数据 传输层也要做数据分割&#xff0c;所以必然也需要做数据重组。 ② 按端口号寻址 IP只能定位数据哪台主机&#xff0c;无法判断数据报文应该交给哪个应用&#xff0c;传输层给每个应用都设置了一个编号&#xff0c;这个编号就是端口&…

Wails 学习笔记:Wails核心思想理解

文章目录 1. Wails 的核心思想2. 工作流程2.1 前端渲染2.2 后端逻辑2.3 前后端通信2.4 应用打包与分发 3. Wails 主要组件3.1 WebView3.2 事件与数据绑定3.3 窗口管理 4. Wails 的优点5. Wails 的使用场景6. 启动函数Runwails.Run() 的主要功能wails.Run() 的参数&#xff1a;w…

【C++】STL篇 string类(使用)

string的学习会分为两个大步骤&#xff0c;第一步就是会使用string&#xff0c;第二部是模拟实现string。这篇文章我们介绍一下string类以及它的使用。string大概有一百多个接口&#xff0c;我们需要重点掌握的就十几二十个。string其实就是字符串&#xff0c;严格来说string类…

STM32传感器模块编程实践(八) HX711压力传感器称重模块简介及驱动源码

文章目录 一.概要二.HX711主要技术指标三.HX711模块参考原理图四.模块接线说明五.模块工作原理介绍六.模块通讯协议介绍七.STM32单片机与HX711模块实现重量测量实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 八.小结 一.概要 电子秤是将检测与转换技术、计算机技术、信息…

一文通透OpenAI o1:从CoT、Quiet-STaR、Self-Correct、Self-play RL、MCST等技术细节到工程复现

前言 注意&#xff0c;本文自10.12日起&#xff0c;正在每天更新的过程中&#xff0c;包括已写的部分也在不断修改(以增加更多技术细节、更加通俗易懂) 预计10.20完成第一版&#xff0c;10月底修订到第二版——具体修订记录详见本文文末.. 可能是去年写或讲的关于ChatGPT原理的…

植物大战僵尸杂交版之后要出联机版植物大战僵尸?(内测中,可在安卓手机上玩,文末附下载链接)

继植物大战僵尸杂交版之后给大家介绍一个杂交版作者正在酝酿的“植物大战僵尸射击版” 植物大战僵尸射击版介绍 《植物大战僵尸杂交版》的创作者“潜艇伟伟迷”即将推出PVZ改版新作——《植物大战僵尸射击版》。游戏将支持PC、手游和web端&#xff0c;提供单人、双人、三人、…

【java Web如何开发?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

华为eNSP实验:交换机流量控制之风暴控制

一、交换机流量控制之风暴控制 风暴控制是交换机流量控制中的一种重要机制&#xff0c;用于防止网络中的广播、多播或单播风暴对网络性能造成破坏。具体如下&#xff1a; 基本原理&#xff1a;风暴控制通过监控端口的入站流量&#xff0c;并与预设的风暴抑制级别进行对比来管…

java数组讲解

前言&#xff1a; 由上两章&#xff0c;我们已经了解关于java的基础语法&#xff0c;这章我们将讲解数组的相关语法&#xff0c;坐好了没&#xff0c;我们准备要发车啦&#xff01;&#xff01;&#xff01; 我们将从五部分给大家讲解&#xff1a; 1数组的基本概念 2.数组是…

使用Windows创建一个MFC应用【带界面】

MFC使用教程【对初学者保姆型友好&#xff01;】 目录 前提条件 1&#xff1a;创建MFC应用程序 2. 项目结构解读 引用 外部依赖项 头文件 源文件 资源文件 文件功能详解 项目的主要流程 步骤2&#xff1a;配置OpenCV 安装OpenCV 包含目录与库文件 步骤3&#xff1…

Milvus×Dify半小时轻松构建RAG系统

最近&#xff0c;检索增强生成&#xff08;RAG&#xff09;技术在AI界引起了广泛关注。作为一种将知识库与生成模型结合的新型架构&#xff0c;RAG大大提升了AI应用的实际表现。而在构建RAG系统时&#xff0c;Milvus作为业界领先的开源向量数据库&#xff0c;扮演着关键角色。本…

视频格式在线转换,五种超实用的视频格式转换工具!

视频内容无处不在&#xff0c;从教育课程到娱乐电影&#xff0c;从社交媒体分享到在线会议&#xff0c;视频已成为我们日常生活中不可或缺的一部分。然而&#xff0c;不同的设备和平台支持的视频格式各异&#xff0c;会导致视频文件在某些设备上无法播放。因此&#xff0c;掌握…

计算机毕业设计python+spark知识图谱课程推荐系统 课程预测系统 课程大数据 课程数据分析 课程大屏 mooc慕课推荐系统 大数据毕业设计

指导教师意见&#xff1a; 1&#xff0e;对“文献综述”的评语&#xff1a; 对教育领域数据可视化的相关背景和现状做了综述&#xff0c;明确了课题的研究目标和研究重点&#xff0c;并对研究手段进行了概述。为后面的毕业设计做好了准备。 对本课题的深度、广度及工作量的…

【开源】第三期:数字货币程序化交易终端开源

关于初衷&#xff1a; 这篇文章&#xff0c;其实应该在六年前发出来&#xff0c;但是受制于各种杂事和生活琐事&#xff0c;一直拖到现在&#xff0c;想必有朋友看到在"终端"那期里&#xff0c;聊到的数字货币交易的实践&#xff0c;那个时候遍地都是数字货币交易所&…

git gui基本使用

一、图形化界面 二、创建新项目 创建文件&#xff0c;加入暂存区&#xff0c;提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突&#xff0c;加入暂存区&#xff0c;提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…