在 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测试请求,来查看代码中配置的信息,以及参数的描述信息。
查询用户信息:
查看全局异常: