通用返回对象
1.通用返回对象
目的:给对象补充一些信息,告诉前端这个请求在业务层面上是成功还是失败
200、404、500、502
//通常我们的返回结果
{
"name": taoha
}
//使用统一对象后正常的返回
{
"code": 0 //业务状态码
"data": {
"name": "taoha"
},
"message": "ok"
}
//使用统一对象后异常的返回
{
"code": 50001 //业务状态码
"data": null
"message": "用户操作异常..."
}
/**
* 通用返回类
*
* @param <T>
* @author taoha
*/
@Data
public class BaseResponse<T> implements Serializable {
private int code;
private T data;
private String message;
private String description;
public BaseResponse(int code, T data, String message, String description) {
this.code = code;
this.data = data;
this.message = message;
this.description = description;
}
public BaseResponse(int code, T data, String message) {
this(code, data, message, "");
}
public BaseResponse(int code, T data) {
this(code, data, "", "");
}
public BaseResponse(ErrorCode errorCode) {
this(errorCode.getCode(), null, errorCode.getMessage(), errorCode.getDescription());
}
}
返回成功对象效果:
需要将原本控制器中的方法的类型和返回对象进行包装
优点: 返回了统一的对象
缺点:每个返回对象中的属性都需要亲自手敲,可能出现错误,例如(message:ok message:okk)
改进:写一个工具类,让工具类帮助我们返回一个成功或失败的BaseResponse对象
2.定义一个工具类
/**
* 返回工具类
*
* @author taoha
*/
public class ResultUtils {
/**
* 成功
*
* @param data
* @param <T>
* @return
*/
public static <T> BaseResponse<T> success(T data) {
return new BaseResponse<>(0, data, "ok");
}
/**
* 失败
*
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode) {
return new BaseResponse<>(errorCode);
}
/**
* 失败
*
* @param code
* @param message
* @param description
* @return
*/
public static BaseResponse error(int code, String message, String description) {
return new BaseResponse(code, null, message, description);
}
/**
* 失败
*
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode, String message, String description) {
return new BaseResponse(errorCode.getCode(), null, message, description);
}
/**
* 失败
*
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode, String description) {
return new BaseResponse(errorCode.getCode(), errorCode.getMessage(), description);
}
}
效果:
接着针对失败返回
-1 或 null 的指向性不是特别好,前端或者后端并不知道这个-1所代表的错误具体是什么
解决:定义一个通用的错误码或定义一套错误码规范: 可以定义一个枚举值对象
3.定义一个枚举值对象
/**
*
* 错误码
* @Author taoha
*/
public enum ErrorCode {
SUCCESS(0, "ok", ""),
PARAMS_ERROR(40000, "请求参数错误", ""),
NULL_ERROR(40001, "请求数据为空", ""),
NOT_LOGIN(40100, "未登录", ""),
NO_AUTH(40101, "无权限", ""),
SYSTEM_ERROR(50000, "系统内部异常", "");
private final int code;
/**
* 状态码信息
*/
private final String message;
/**
* 状态码描述(详情)
*/
private final String description;
ErrorCode(int code, String message, String description) {
this.code = code;
this.message = message;
this.description = description;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
}
返回失败对象效果:
优点:通过定义错误码规范,返回的错误更具有指向性
全局异常处理器
使用统一返回对象时,还有一种情况,就是程序的报错是由于运行时异常导致的结果,有些异常是我们在业务中抛出的,有些是无法提前预知。
因此,我们需要定义一个统一的全局异常,在全局捕获所有异常,并且做适当处理,并作为同一对象返回
设计思路:
1.自定一个异常类,捕获针对项目或业务的异常;
2.使用@ExceptionHandler注解捕获自定义异常和通用异常;
3.使用@ControllerAdvice集成@ExceptionHandler的方法到一个类中;
4.异常的对象信息补充到统一结果枚举中;
4.自定义业务异常类
/**
* 自定义异常类
*
* @author taoha
*/
public class BusinessException extends RuntimeException {
private final int code;
private final String description;
public BusinessException(String message, int code, String description) {
super(message);
this.code = code;
this.description = description;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = errorCode.getDescription();
}
public BusinessException(ErrorCode errorCode, String description) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
效果:
区别:第一个框是直接返回,现在是抛出异常
同理service中:
上面是我们可提前预知的业务异常,而对于一些不可预知的系统异常,我们是不能直接返回给前端的
因此我们还需要一个全局异常处理器:
1.捕获代码中所有(业务异常和系统异常)的异常,内部消化,让前端感知到更详细的业务报错/信息,
2.同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
3.集中处理,eg:记录日志
5.封装全局异常处理器
实现:
1.SpringAOP:在调用方法前后进行额外的处理
package com.th.usercenter.exception;
import com.th.usercenter.common.BaseResponse;
import com.th.usercenter.common.ErrorCode;
import com.th.usercenter.common.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全集异常处理器
* @author taoha
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
//业务异常
@ExceptionHandler(BusinessException.class)
public BaseResponse businessExceptionHandle(BusinessException e){
log.error("businessException: "+ e.getMessage(),e);
return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription());
}
//系统异常
@ExceptionHandler(RuntimeException.class)
public BaseResponse runtimeExceptionHandle(BusinessException e){
log.error("businessException",e);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR,e.getMessage(),"");
}
}
项目结构:
总结:
1. 通用返回对象
目的:给对象补充一些信息,告诉前端这个请求在业务层面上是成功还是失败
自定义错误码
返回类支持返回正常和错误
2. 封装全局异常处理
a. 定义业务异常类
ⅰ. 相对于 java 的异常类,支持更多字段
ⅱ. 自定义构造函数,更灵活 / 快捷的设置字段
b. 编写全局异常处理器
作用:
ⅰ. 捕获代码中所有的异常,内部消化,让前端得到更详细的业务报错 / 信息
ⅱ. 同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
ⅲ. 集中处理,比如记录日志
实现:
ⅰ. Spring AOP:在调用方法前后进行额外的处理