在我们的Java项目中经常会报各种各样的异常,这些异常的信息虽然很详细,会将报错的位置、报错类型和原因都打印在控制台中。
但是如果BS项目用户做交互的时候,由于他们的误操作产生了某些异常,这些异常没有经过包装,是很难被没有编程经验的用户所读懂的,所以我们需要自定义异常并且包装异常信息返回给用户。不过抛出异常也仅仅是我们中断项目执行的一类方法,选择抛出自定义异常返回到前端,能够给予更好的用户体验。
由于是自定义的异常类,那么其实我们的自定义异常类肯定是需要继承于Exception类的,由于是返回给前端的,那么其实自定义抛出异常的各种ErrMsg和错误码就行了。
那么首先是创建一个公用的异常接口,该接口应该包含下列方法(我这里只是简单的定义了两个方法:获取错误码和错误信息)。
public interface CommonError {
public int getErrorCode();
public String getErrorMsg();
public CommonError setErrorMsg(String ErrorMsg);
}
而后创造自定义异常类实现接口中的方法。
public class TransactionException extends Exception implements CommonError{
/*** 序列化*/
private static final long serialVersionUID = -4586789845574329434L;
private CommonError commonError;
//直接接受EmBusinessError的传参用于构造业务异常public TransactionException(CommonError CommonError)
{
super();
this.commonError = CommonError;
}
//接收自定义errMsg的方法构造业务异常public TransactionException(CommonError CommonError,String ErrMsg)
{
super();
this.commonError = CommonError;
this.commonError.setErrorMsg(ErrMsg);
}
@Override
public int getErrorCode() {
return this.commonError.getErrorCode();
}
@Override
public String getErrorMsg() {
return this.commonError.getErrorMsg();
}
@Override
public CommonError setErrorMsg(String ErrorMsg) {
this.commonError.setErrorMsg(ErrorMsg);
return this;
}
}
使用枚举去限制抛出异常的内容和错误代码,在枚举中我们定义一下异常的错误码和错误信息。
public enum EmBusinessError implements CommonError {
RCONNECTION_ERROR(10001,"获取R服务器链接失败,请通知管理员"),
USER_NOT_INUSE(20000,"该用户还未得到管理员许可"),
USER_NOT_MATCH(20001,"用户名和密码不匹配"),
USER_NOT_LOGIN(20002,"用户还未登录"),
USER_REGESITERDUPLICATEKEY(20003,"注册使用账号重复"),
USER_REGESITERFAIL(20004,"注册失败,未知原因"),
FILE_NOT_EXIST(30001,"文件不存在"),
MYSQL_NOT_EXIST(30002,"数据库错误!"),
UNKNOWN_ERROR(40004,"未知错误!"),
RSERVERERROR(50001,"选择上传的文件错误!")
;
private int errCode;
private String errMsg;
private EmBusinessError(int errCode,String errMsg ) {
this.errCode = errCode;
this.errMsg = errMsg;
}
/* (non-Javadoc)* @see com.example.demo.error.CommonError#getErrorCode()*/
@Override
public int getErrorCode() {
return this.errCode;
}
/* (non-Javadoc)* @see com.example.demo.error.CommonError#getErrorMsg()*/
@Override
public String getErrorMsg() {
return this.errMsg;
}
/* (non-Javadoc)* @see com.example.demo.error.CommonError#setErrorMsg(java.lang.String)* 这个接口就可以用来改动通用错误类型中的ErrorMsg*/
@Override
public CommonError setErrorMsg(String ErrorMsg) {
this.errMsg = ErrorMsg;
return this;
}
}
这样我们就创建好了自定义的异常类。
之后在Controller层加入异常捕捉头即可。
在这里可以看到在捕捉头里判断捕获的异常是否是这些异常类的实例,如果是自定义异常的实例则直接对公共返回类属性赋值。而如果捕获到的不是自定义异常则需要进行进行其他判断给返回数据赋值。
这里需要注意的是:当我们程序中抛出的是我预先定义的TransactionException时才可以对捕获到的异常进行强转。而程序中往往还会抛出很多一些你无法定义或者捕获到的运行时异常,比如NullPointerException这类异常,它也是无法强转为我们的自定义异常的。那么此时就需要使用到instanceof关键字来判断异常的类型了,对异常类型判断后就可以对访问的数据进行处理了。
@ExceptionHandler(Exception.class)
@ResponseBody
public Object handlerException(HttpServletRequest request,Exception e) {
Map responseData = new HashMap<>();
if (e instanceof TransactionException) {
TransactionException businessException = (TransactionException)e;
responseData.put("errCode", businessException.getErrorCode());
responseData.put("errMsg", businessException.getErrorMsg());
}
else if (e instanceof RserveException) {
responseData.put("errCode", EmBusinessError.RSERVER_ERROR.getErrorCode());
responseData.put("errMsg", EmBusinessError.RSERVER_ERROR.getErrorMsg());
}
else{
responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrorCode());
responseData.put("errMsg", EmBusinessError.UNKNOWN_ERROR.getErrorMsg());
}
return CommonReturnType.create(responseData,"fail");
}
而CommonReturnType是我创建的统一的返回包装类,包装类是用来返回数据到前端进行交互的。
public class CommonReturnType {
//表明对应请求的返回处理结果:success failprivate String status;
//当status为success时,则返回前端所需要的数据private Object data;
//定义一个通用的创建方法public static CommonReturnType create(Object result) {
return CommonReturnType.create(result,"success");
}
public static CommonReturnType create(Object result, String status) {
CommonReturnType type = new CommonReturnType();
type.setData(result);
type.setStatus(status);
return type;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
通过该包装类,当我们在前端使用Ajax获取到后端数据后,就可以处理它携带的Data去更好的获取信息了。
至此,我们就能够使用自定义异常类更好的处理后端的各类异常,返回给前端用户更直观的异常类型和错误信息。