在应用中,我们力求做到优雅的捕获异常,并返回统一的格式给前端。下面是一种解决方案,步骤如下:
1.创建公共返回体
/**
* @author hesh
* @date 2019/1/23
* @des 公共返回类
*/
@Data
public class CommHttpResult {
private String status;//success,fail
private Object data;//返回的json数据,或通用错误码格式
public static CommHttpResult create(Object data) {
return create("success",data);
}
public static CommHttpResult create(String status, Object data) {
CommHttpResult commHttpResult = new CommHttpResult();
commHttpResult.setStatus(status);
commHttpResult.setData(data);
return commHttpResult;
}
}
2.创建公共异常操作接口
/**
* @author hesh
* @date 2019/1/23
* @des 公共错误接口
*/
public interface CommError {
/**
* 获取错误码
* @return
*/
int getErrCode();
/**
* 获取错误信息
* @return
*/
String getErrMsg();
/**
* 动态设置错误信息,并返回错误实体类
* @param errMsg
* @return
*/
CommError setErrMsg(String errMsg);
}
3.创建自定义业务异常
/**
* @author hesh
* @date 2019/1/24
* @des 通用业务异常类
* 设计模式-->包装器业务异常类实现,使得异常或者错误枚举都可以设置错误信息
*/
public class BusinessException extends Exception implements CommError{
private CommError commError;
/**
* 直接接收BusinessErrorEnum的传参用于构造业务异常
* @param commError
*/
public BusinessException(CommError commError){
super();//继承父类的异常初始化方法
this.commError = commError;
}
/**
* 接收自定义errMsg的方式构造业务异常
* @param commError
* @param errMsg
*/
public BusinessException(CommError commError,String errMsg){
super();
this.commError = commError;
this.commError.setErrMsg(errMsg);
}
@Override
public int getErrCode() {
return this.commError.getErrCode();
}
@Override
public String getErrMsg() {
return this.commError.getErrMsg();
}
@Override
public CommError setErrMsg(String errMsg) {
this.commError.setErrMsg(errMsg);
return this;
}
}
4.创建错误枚举类
/**
* @author hesh
* @date 2019/1/23
* @des 通用业务错误枚举类
*/
public enum BusinessErrorEnum implements CommError{
//通用错误类型100000开头
PARAM_INVALID(100001,"参数不合法"),//可动态更改msg的内容
UNKNOWN(100002,"未知错误"),
//20000开头为用户信息相关错误定义
USER_NOT_EXIST(20001,"用户不存在"),
USER_LOGIN_FAIL(20002,"用户账号或密码不正确"),
USER_NOT_LOGIN(20003,"用户未登录"),
//30000开头为交易信息相关错误定义
STOCK_NOT_ENOUGH(30001,"库存不足"),
;
private int errCode;
private String errMsg;
BusinessErrorEnum(int errCode, String errMsg) {
this.errCode = errCode;
this.errMsg = errMsg;
}
@Override
public int getErrCode() {
return this.errCode;
}
@Override
public String getErrMsg() {
return this.errMsg;
}
@Override
public CommError setErrMsg(String errMsg) {
this.errMsg = errMsg;
return this;
}
}
5.使用@ExceptionHandler捕获controller抛出的异常
/**
* @author hesh
* @date 2019/1/24
* @des Controller的基类,用于处理公共逻辑
*/
@Slf4j
//@ControllerAdvice //对所有的controller类进行拦截处理
public class BaseController {
@ExceptionHandler//异常捕获与处理
@ResponseStatus(HttpStatus.OK)//使http返回的状态码是200
@ResponseBody//使之返回json格式数据
public Object handleException(HttpServletRequest request,Exception ex){
log.error("统一异常捕获,莫紧张--{}" ,ExceptionUtils.getStackTrace(ex));
//定义一个map,在json解析时,会自动按key-value把值读出来
Map<String,Object> responseData = new HashMap<>();
if (ex instanceof BusinessException){
BusinessException businessException = (BusinessException) ex;
responseData.put("errCode",businessException.getErrCode());
responseData.put("errMsg",businessException.getErrMsg());
}else {
responseData.put("errCode", BusinessErrorEnum.UNKNOWN.getErrCode());
responseData.put("errMsg", BusinessErrorEnum.UNKNOWN.getErrMsg());
}
return CommHttpResult.create("fail",responseData);
}
}
6.具体应用例子
1.用户不存在异常
if (userModel==null){
throw new BusinessException(BusinessErrorEnum.USER_NOT_EXIST);
}
2.验证码有误异常--修改返回的枚举的msg内容
if (!StringUtils.equals(otpcode,inSessionOtpCode)){
throw new BusinessException(BusinessErrorEnum.PARAM_INVALID,"验证码有误");
}
throw new BusinessException(BusinessErrorEnum.PARAM_INVALID,"该账号已被注册!");
等等