对于前后端分离的Restful架构的服务端应用而言,需要保证在任何情况下都要正常响应前端的请求信息,包括处理过程中发生异常时。这就得针对异常进行统一的封装处理,保证前台能正常解析应答信息。
1.统一异常对象
自定义统一的异常对象有助于我们对异常的处理,这是我们返回给前台错误信息的统一接口。
public class SrvException extends RuntimeException {
private static final long serialVersionUID = 3162989605548935100L;
private String code;
private String msg;
private Object data;
public SrvException() {
}
public SrvException(CodeMsg cm) {
this(cm.getCode(), cm.getMsg(), null);
}
public SrvException(String code, String msg) {
this(code, msg, null);
}
public SrvException(String code, String msg, Exception e) {
this(code, msg, null, e);
}
public SrvException(String code, String msg, Object data) {
this(code, msg, data, null);
}
public SrvException(String code, String msg, Object data, Exception e) {
super(msg, e);
this.code = code;
this.msg = msg;
this.data = data;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
@Override
public String toString() {
return "Code:" + code + " Msg:" + msg + " Data:" + JsonHelper.toJson(data);
}
}
2.统一异常定义
这个类中定义了所有当前系统中抛出的异常信息。
public class CodeMsgDef {
public static CodeMsg SUCCESS = new CodeMsg(ErrorCodeDef.SUCCESS, "SUCCESS");
public static CodeMsg ERROR = new CodeMsg(ErrorCodeDef.ERROR, "ERROR");
public static CodeMsg 系统错误 = new CodeMsg(ErrorCodeDef.RUNTIME_ERROR, "未知系统错误!");
public static CodeMsg 参数错误 = new CodeMsg(ErrorCodeDef.PARAMETER_ERROR, "参数错误!");
public static CodeMsg 必填参数为空 = new CodeMsg(ErrorCodeDef.PARAMETER_ERROR, "必填参数不能为空!");
public static CodeMsg 无权限查看 = new CodeMsg(ErrorCodeDef.PURVIEW_ERROR, "无权限查看!");
public static CodeMsg 不可修改状态 = new CodeMsg(ErrorCodeDef.NOT_UPDATE, "不可修改状态!");
}
public class ErrorCodeDef {
protected static final String SUCCESS = "0";
protected static final String ERROR = "1";
protected static final String RUNTIME_ERROR = "2";
protected static final String PARAMETER_ERROR = "3";
protected static final String PURVIEW_ERROR = "4";
protected static final String NOT_UPDATE = "5";
}
tips: 异常定义类可以放在基础包中被各个微服务依赖,用于判断异常来源。
3.可检测异常的处理
对于非运行时异常,我们可以直接 try/catch 之后转换成SrvException:
try {
//文件上传
} catch (Exception e) {
log.error("文件处理失败!", e);
throw new SrvException(CodeMsgDef.FILE_UPLOAD_ERROR);
}
4.业务异常处理
业务异常需要手动抛出,在最外层统一处理。
if (id <= 0) {
throw new SrvException(CodeMsgDef.参数错误);
}
5.运行时异常处理
运行时异常虽然也可捕获,但是处理过于麻烦,所以也放在最外层统一处理。
6.异常的统一处理
经过上面的处理之后,异常就被区分成 SrvException 和 RuntimeException;
这里再使用 @ControllerAdvice 和 @ExceptionHandler 在系统抛出异常时,针对指定异常做处理。
@ControllerAdvice
public class ExceptionController {
private static final Logger log = LoggerFactory.getLogger(ExceptionController.class);
@ExceptionHandler({RuntimeException.class, Exception.class})
@ResponseBody
public Object runtimeExceptionHandler(Exception e, HttpServletRequest request, HttpServletResponse response) {
if (log.isDebugEnabled()) {
log.debug(e.getMessage(), e);
} else {
log.error(e.getMessage(), e);
}
return ResponseUtil.instance(CodeMsgDef.系统错误);
}
@ExceptionHandler({SrvException.class})
@ResponseBody
public Object srvExceptionHandler(SrvException e) {
if (log.isDebugEnabled()) {
log.debug("SrvException: msg: " + e.getMsg() + ", code: " + e.getCode(), e);
} else {
log.error("SrvException: msg: " + e.getMsg() + ", code: " + e.getCode());
}
return ResponseUtil.instance(e);
}
}
7.工具类
public class ResponseUtil {
public static Response success(Object obj) {
if (obj instanceof String) {
return new Response(CodeMsgDef.SUCCESS, (String) obj);
} else {
return new Response(CodeMsgDef.SUCCESS, obj);
}
}
public static Response instance(SrvException e) {
return new Response(new CodeMsg(e.getCode(),e.getMsg()));
}
public static Response instance(CodeMsg codeMsg) {
return new Response(codeMsg);
}
public static Response instance(CodeMsg codeMsg, String msg) {
return new Response(new CodeMsg(codeMsg.getCode(), msg));
}
public static Response instance(CodeMsg codeMsg, Object obj) {
if (obj instanceof String) {
return new Response(codeMsg, (String) obj);
} else {
return new Response(codeMsg,obj != null ? JsonHelper.toJson(obj) : null);
}
}
public static Response instance(CodeMsg codeMsg, String msg, Object obj) {
if (obj instanceof String) {
return new Response(new CodeMsg(codeMsg.getCode(), msg), (String) obj);
} else {
return new Response(new CodeMsg(codeMsg.getCode(), msg),obj != null ? JsonHelper.toJson(obj) : null);
}
}
}
个人博客:http://www.kesina.cn