SpringBoot统一响应格式及统一异常处理
作者:JK凯 时间:2022-08-30 08:03:08
在我们开发SpringBoot后端服务时,一般需要给前端统一响应格式,方便前端调试及配置错误提示等等。这篇文章讲讲实际工作中统一响应格式及统一异常处理是如何做的。
一、统一响应基础类
在项目中对应工具类或Vo层来创建我们的统一响应类
ResponseResult
:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.zhang.enums.AppHttpCodeEnum;
import java.io.Serializable;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> implements Serializable {
private Integer code;
private String msg;
private T data;
public ResponseResult() {
this.code = AppHttpCodeEnum.SUCCESS.getCode();
this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
}
public ResponseResult(Integer code, T data) {
this.code = code;
this.data = data;
}
public ResponseResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResponseResult(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static ResponseResult errorResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.error(code, msg);
}
public static ResponseResult okResult() {
ResponseResult result = new ResponseResult();
return result;
}
public static ResponseResult okResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.ok(code, null, msg);
}
public static ResponseResult okResult(Object data) {
ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
if (data != null) {
result.setData(data);
}
return result;
}
public static ResponseResult errorResult(AppHttpCodeEnum enums) {
return setAppHttpCodeEnum(enums, enums.getMsg());
}
public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg) {
return setAppHttpCodeEnum(enums, msg);
}
public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) {
return okResult(enums.getCode(), enums.getMsg());
}
private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg) {
return okResult(enums.getCode(), msg);
}
public ResponseResult<?> error(Integer code, String msg) {
this.code = code;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(Integer code, T data) {
this.code = code;
this.data = data;
return this;
}
public ResponseResult<?> ok(Integer code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(T data) {
this.data = data;
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
里面还有用到一个响应的枚举类AppHttpCodeEnum
,接下来我们创建这个枚举类
二、响应枚举类
AppHttpCodeEnum
:
public enum AppHttpCodeEnum {
// 成功
SUCCESS(200, "操作成功"),
// 登录
NEED_LOGIN(401, "需要登录后操作"),
NO_OPERATOR_AUTH(403, "无权限操作"),
SYSTEM_ERROR(500, "出现错误"),
USERNAME_EXIST(501, "用户名已存在"),
PHONENUMBER_EXIST(502, "手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"),
REQUIRE_USERNAME(504, "必需填写用户名"),
CONTENT_NOT_NULL(506, "评论内容不能为空"),
FILE_TYPE_ERROR(507, "文件类型错误"),
USERNAME_NOT_NULL(508, "用户名不能为空"),
NICKNAME_NOT_NULL(509, "昵称不能为空"),
PASSWORD_NOT_NULL(510, "密码不能为空"),
EMAIL_NOT_NULL(511, "邮箱不能为空"),
NICKNAME_EXIST(512, "昵称已存在"),
LOGIN_ERROR(505, "用户名或密码错误");
int code;
String msg;
AppHttpCodeEnum(int code, String errorMessage) {
this.code = code;
this.msg = errorMessage;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
一般我们在这个枚举类中管理需要响应的错误code
及msg
三、统一响应格式使用
在对应的controller或者service里面使用统一响应类
成功:
ResponseResult.okResult()
失败:
ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR)
, 参数传入我们定义的响应枚举类
四、统一异常处理
1. 自定义异常
为什么我们需要自定义异常?因为在某些情况下,我们需要返回我们自定义的响应格式非常不方便,如在处理用户鉴权或token校验的时候,因为像这些部分我们一般都是在单独的工具类中去处理,这时候如果报错其实就可以抛出我们自定义的异常,交由我们全局的异常处理去统一返回响应。
在
exception
包下新建SystemException
类SystemException
继承RuntimeException
具体实现代码如下
exception.SystemException:
import com.jk.enums.AppHttpCodeEnum;
public class SystemException extends RuntimeException{
private int code;
private String msg;
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
public SystemException(AppHttpCodeEnum appHttpCodeEnum) {
super(appHttpCodeEnum.getMsg());
this.code = appHttpCodeEnum.getCode();
this.msg = appHttpCodeEnum.getMsg();
}
}
目前只是自定义了异常,我们还需要对自定义的异常进行处理,返回统一的响应格式。
2.异常处理
在
handler.exception
包下新建GlobalExceptionHandler
处理类@RestControllerAdvice
是组合注解,由@ControllerAdvice
、@ResponseBody
组成,标明是一个统一异常处理的类,并把返回结果封装在ResponseBody
中@Slf4j
是Lombok
实现日志输出的注解@ExceptionHandler
标明该方法处理哪些异常
具体代码实现如下:
handler.exception.GlobalExceptionHandler:
import com.jk.enums.AppHttpCodeEnum;
import com.jk.exception.SystemException;
import com.jk.vo.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(SystemException.class)
public ResponseResult systemExceptionHandler(SystemException e) {
log.error("出现了异常! {}", e);
return ResponseResult.errorResult(e.getCode(), e.getMsg());
}
@ExceptionHandler(Exception.class)
public ResponseResult exceptionHandler(Exception e) {
log.error("出现了异常! {}", e);
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
}
}
可以看到我们除了处理自定义异常SystemException
外,还对Exception
就是其他我们无法预料到的异常做了一个兜底。
3.自定义异常使用
在需要抛出异常的地方:
throw new SystemException(AppHttpCodeEnum.LOGIN_ERROR);
前端接收到的响应是:
{
"code": 505,
"msg": "用户名或密码错误"
}
这样就比接收到500错误也不知道错误原因好多了。
来源:https://juejin.cn/post/7226994337123549242