动手写个java快速开发框架-(4)统一异常处理
作为一个开发框架当然稍不了异常的统一处理,今天我们就在MkFramework中加入统一异常处理模块。大家在日常开发过程中,对于一些初级开发经常喜欢将代码框在try代码块中,然后在catch中进行异常捕获,但很多都只是在捕获了之后只是进行简单的print错误堆栈信息,这样就会导致系统报错了,但是我们在日志中看不到抛出的异常信息,或者是有些自认为可以进行处理的错误,其实没有处理成功,所以很多框架都加入了统一异常处理机制,这样就可以让所有的错误处理集中在一个地方进行处理,在业务代码开发过程中,遇到错误只需要进行throw就可以了,由上层统一进行拦截处理,返回给调用方。
对于一个框架中,当然也要有错误码的统一管理,这里我们使用了自定义错误码,并将错误码定义在了错误码枚举类中,当然如果你的系统比较庞大,错误码非常多,并且要实现错误码的动态调整,那么也可以将错误码存在数据库中,启动后放到内存缓存,这里为了方便大家理解只是提前将错误码定义在了枚举类中。
所有的错误码定义和错误异常处理都放在了common.exception包中。
我们定义的错误类为MkException,对于我们业务中的错误都可以使用自定义异常类,对于java runtime异常或者Error还是建议不做过多的封装,这样便于查询问题。
public class MkException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String returnMsg;
/**
* returnCode 表示HOP内部错误码
*/
private String returnCode = "999999";
private String errorMsg;
/**
* errorCode 表示后台系统返回错误码
*/
private String errorCode = "999999";
//...省略N个重载的构造函数
public MkException(String returnMsg, String returnCode, String errorMsg, String errorCode) {
super(returnMsg);
this.returnMsg = returnMsg;
this.returnCode = returnCode;
this.errorMsg = errorMsg;
this.errorCode = errorCode;
}
public MkException(String returnMsg, String returnCode, String errorMsg, String errorCode, Throwable e) {
super(returnMsg, e);
this.returnMsg = returnMsg;
this.returnCode = returnCode;
this.errorMsg = errorMsg;
this.errorCode = errorCode;
}
public MkException(ResultCode resultCode, Throwable e) {
super(resultCode.getMessage(), e);
this.errorMsg = resultCode.getMessage();
this.errorCode = resultCode.getCode();
}
public MkException(ResultCode resultCode) {
this.errorMsg = resultCode.getMessage();
this.errorCode = resultCode.getCode();
}
//...省略setter、getter
}
public enum ResultCode {
//检查输入项不能为空错误码
IS_NOT_BLANK_ERROR("999001", "请检查输入项,不能为空"),
SUCCESS("000000", "success"),
UNKNOW_ERROR("999999","系统未知异常"),
//省略其他错误码定义
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
private String code;
private String message;
private ResultCode(String code, String message) {
this.code = code;
this.message = message;
}
}
因为我们使用的是Spring框架,所以我们可以通过RestControllerAdvice对所有在最上层controller中进行统一拦截,在spring中实现这样的拦截需要自定义类继承自RestControllerAdvice,当然在spring4.0以后的版本可以通过@RestControllerAdvice注解来实现定义类,然后在类中实现异常处理,对于异常处理的方法需要添加@ExceptionHandler(xxxException.class)
注解来表示该方法处理哪一类异常。
@RestControllerAdvice
public class MkExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
private final static String NO_URL_FOUND = "404";
/**
* 处理自定义异常
*/
@ExceptionHandler(MkException.class)
public MkResponse handleHOPException(MkException e){
MkResponse r = new MkResponse();
r.put("returnCode", e.getReturnCode());
r.put("returnMsg", e.getReturnMsg());
r.put("errorCode", e.getErrorCode());
r.put("errorMsg", e.getErrorMsg());
logger.error(new Date() + ": " + e.getMessage(), e);
return r;
}
@ExceptionHandler(NoHandlerFoundException.class)
public MkResponse handlerNoFoundException(Exception e) {
logger.error(new Date() + ": " + e.getMessage(), e);
return MkResponse.error(NO_URL_FOUND, "路径不存在,请检查路径是否正确");
}
//大家可以自己定义其他的异常处理
@ExceptionHandler(Exception.class)
public MkResponse handleException(Exception e){
logger.error(new Date() + ": " + e.getMessage(), e);
return MkResponse.error(e.getMessage());
}
}
统一的异常处理是不是挺简单,并且也将正常的业务逻辑处理和异常处理的代码分离开了,并且返回的错误报文格式都是统一的,是不是整个工程更加清晰了。在TestController中有个exception方法,大家可以调用试试效果。
本文对应的github tag为v0.4,可以通过连接下载https://github.com/feiweiwei/MkFramework4java/releases/tag/v0.4,也可以通过git clone -b v0.4 https://github.com/feiweiwei/MkFramework4java.git