5.4 KiB
5.4 KiB
统一异常处理
后端异常处理
在开发过程中,不可避免的是需要处理各种异常,异常处理方法随处可见,所以代码中就会出现大量的try {...} catch {...} finally {...}
代码块,不仅会造成大量的冗余代码,而且还影响代码的可读性,所以对异常统一处理非常有必要。为此,我们定义了一个统一的异常类LuckException
与异常管理类 DefaultExceptionHandlerConfig
。
我们先来看下 LuckException
的代码
public class LuckException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Object object;
/**
* 响应状态码枚举
*/
private ResponseEnum responseEnum;
public LuckException(String msg) {
super(msg);
}
public LuckException(String msg, Object object) {
super(msg);
this.object = object;
}
public LuckException(String msg, Throwable cause) {
super(msg, cause);
}
public LuckException(ResponseEnum responseEnum) {
super(responseEnum.getMsg());
this.responseEnum = responseEnum;
}
public LuckException(ResponseEnum responseEnum,Object object) {
super(responseEnum.getMsg());
this.responseEnum = responseEnum;
this.object = object;
}
public Object getObject() {
return object;
}
public ResponseEnum getResponseEnum() {
return responseEnum;
}
}
ResponseEnum
为我们自定义的返回状态码的枚举类,定义为一个枚举类,更直观处理异常返回的状态码及异常内容,以后每增加一种异常情况,只需增加一个枚举实例即可,不用每一种异常都定义一个异常类。
public enum ResponseEnum {
/**
* ok
*/
OK("00000", "ok"),
/**
* 用于直接显示提示用户的错误,内容由输入内容决定
*/
SHOW_FAIL("A00001", ""),
/**
* 方法参数没有校验,内容由输入内容决定
*/
METHOD_ARGUMENT_NOT_VALID("A00002", ""),
/**
* 无法读取获取请求参数
*/
HTTP_MESSAGE_NOT_READABLE("A00003", "请求参数格式有误"),
/**
* 未授权
*/
UNAUTHORIZED("A00004", "Unauthorized"),
/**
* 服务器出了点小差
*/
EXCEPTION("A00005", "服务器出了点小差");
private final String code;
private final String msg;
public String value() {
return code;
}
public String getMsg() {
return msg;
}
ResponseEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String toString() {
return "ResponseEnum{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + "} " + super.toString();
}
}
再来看看 DefaultExceptionHandlerConfig
类
@RestController
@RestControllerAdvice
public class DefaultExceptionHandlerConfig {
private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionHandlerConfig.class);
@ExceptionHandler(LuckException.class)
public ResponseEntity<ServerResponseEntity<Object>> luckExceptionHandler(LuckException e) {
logger.error("tmerclubExceptionHandler", e);
ResponseEnum responseEnum = e.getResponseEnum();
// 失败返回失败消息 + 状态码
if (responseEnum != null) {
return ResponseEntity.status(HttpStatus.OK).body(ServerResponseEntity.fail(responseEnum, e.getObject()));
}
// 失败返回消息 状态码固定为直接显示消息的状态码
return ResponseEntity.status(HttpStatus.OK).body(ServerResponseEntity.showFailMsg(e.getMessage()));
}
}
前端异常处理
前端请求与相应做了封装,请求响应的内容会被拦截器所拦截,当后台返回给前台特定的状态码,前台将显示不同报错信息。请求响应非常常见,我们查看在src\utils\request.js
里面的其中一段代码
service.interceptors.response.use(
response => {
const res = response.data
if (res.code === '00000') {
return res.data
}
// A00001 用于直接显示提示用户的错误,内容由输入内容决定
// A00003 无法读取获取请求参数
if (res.code === 'A00001' || res.code === 'A00003' || res.code === 'A00005') {
Message({
message: res.msg || 'Error',
type: 'error',
duration: 1.5 * 1000
})
return Promise.reject(res)
}
// A00002 方法参数没有校验,内容由输入内容决定
if (res.code === 'A00002') {
if (res.data && res.data.length) {
res.data.forEach(errorMsg => {
Message({
message: errorMsg || 'Error',
type: 'error',
duration: 1.5 * 1000
})
})
} else {
Message({
message: res.msg || 'Error',
type: 'error',
duration: 1.5 * 1000
})
}
return Promise.reject()
}
// A00004 未授权
if (res.code === 'A00004') {
// to re-login
MessageBox.confirm('您已注销,您可以取消停留在该页上,或重新登录', '确认注销', {
confirmButtonText: '重新登陆',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
return Promise.reject()
}
return Promise.reject(res)
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 1.5 * 1000
})
return Promise.reject(error)
}
)
这里将会统一拦截返回的状态码如A00001
,进行错误提示。