我之前做过一个项目,采用的是前端和后端分离,某些时候后台出现了异常,直接给前端抛了一个500错误,这种错误会被用户看到非常不友好,于是就有了以下统一异常处理,就是把所有的异常都经过处理,按照前端可读的格式返回。
一、对比返回结果如下
1.没有做统一异常处理前,后台出现异常返回结果如下图
2.做了统一异常处理,后台出现异常返回的结果如下图
总结:1.没有对出现的异常做处理,让默认抛出500错误,前端处理麻烦、且对用户不友好
2.对出现的异常做了统一的格式处理,并封装成固定格式、前端处理简单、提示消息友好
二、具体实现步骤
1.之前处理工程异常,代码中最常见的就是try-catch-finally,有时一个try,多个catch,覆盖了核心业务逻辑,现在使用
Spring能够较好的处理这种问题,核心如下,文章主要关注前两个:
- @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
- @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开
demo代码如下
/**
* @Auther: mzl
* @Date: 2019/4/11 10:24
* @Description:
*/
@ControllerAdvice
@RestController
public class CommonExceptionHandler {
/**
* Java一般异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public String exceptionHandler(Exception e){
e.printStackTrace();
if(e instanceof BindException){
int index = e.getMessage().lastIndexOf("[");
return Result.defeatedResultByCodeAndMsg(2, index!= -1?e.getMessage().substring(index + 1,e.getMessage().length()-1).trim():e.getMessage());
}
return Result.defeatedResultByMsg(e.toString());
}
/**
* 拦截自定义异常
* @param ex
* @return
*/
@ExceptionHandler(BaseException.class)
@ResponseBody
public String exceptionHandler(BaseException ex){
ex.printStackTrace();
if(ex.getCode()==null){
ex.setCode(4);
}
return Result.defeatedResultByCodeAndMsg(ex.getCode(),ex.getMsg());
}
}
2.自定义一个异常
/**
* @Auther: mzl
* @Date: 2019/4/10 18:02
* @Description: 异常处理
*/
public class BaseException extends RuntimeException{
private Integer code;
private String msg;
/**
* 默认异常,状态码为2
* @param msg
*/
public BaseException(String msg){
super();
this.msg=msg;
this.code=2;
}
/**
* 自定义异常
* @param code
* @param massge
*/
public BaseException(Integer code,String massge){
super(massge);
this.msg=msg;
this.code=code;
}
public BaseException(){
super("系统错误,请联系管理员");
this.code=4;
this.msg="系统错误,请联系管理员";
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
3.返回结果封装
public class Result {
private static volatile Consequence consequence=new Consequence();
/**
* code结果状态码 0:操作成功;
*/
public static int code0=0;
public static int code1=1;//1:未登录;
public static int code2=2;//2:参数错误;
public static int code3=3;//3:没有权限;
public static int code4=4;//4:系统异常
//时间格式
public static String dateFormat="yyyy-MM-dd HH:mm:ss";
public static String succeedResultByMsgAndDate( String msg, Object date){
consequence.clear();
consequence.setCode(code0);
consequence.setMsg(msg);
consequence.setDate(date);
return getResult(consequence); }
public static String succeedResultByMsg( String msg){
consequence.clear();
consequence.setCode(code0);
consequence.setMsg(msg);
consequence.setDate("");
return getResult(consequence); }
public static String succeedResult(){
consequence.clear();
consequence.setCode(code0);
consequence.setMsg("操作成功");
consequence.setDate("");
return getResult(consequence); }
public static String defeatedResultByMsg(String msg){
consequence.clear();
consequence.setCode(code4);
consequence.setDate("");
consequence.setMsg("系统异常,请联系管理员");
consequence.setDevMsg(msg);
return getResult(consequence); }
public static String defeatedResult(){
consequence.clear();
consequence.setCode(code4);
consequence.setDate("");
consequence.setMsg("系统异常,请联系管理员");
return getResult(consequence); }
public static String noLoginResult(){
consequence.clear();
consequence.setCode(code1);
consequence.setDate("");
consequence.setMsg("没有登录,请登录");
return getResult(consequence); }
public static String noAuthorityResult(){
consequence.clear();
consequence.setCode(code3);
consequence.setDate("");
consequence.setMsg("没有权限,请联系管理员分配权限");
return getResult(consequence); }
public static String noAuthorityResultByMsg(String msg){
consequence.clear();
consequence.setCode(code3);
consequence.setDate("");
consequence.setMsg(msg);
return getResult(consequence); }
public static String errorParameterResult(String 参数错误){
consequence.clear();
consequence.setCode(code2);
consequence.setDate("");
consequence.setMsg("参数错误,或参数不能为空");
return getResult(consequence); }
public static String errorParameterResultByMsg(String msg){
consequence.clear();
consequence.setCode(code2);
consequence.setDate("");
consequence.setMsg(msg);
return getResult(consequence); }
public static String defeatedResultByCodeAndMsg(Integer code,String msg){
consequence.clear();
consequence.setCode(code);
consequence.setDate("");
consequence.setMsg(msg);
return getResult(consequence); }
public static String setResultByCodeAndMsgAndDate(Integer code,String msg, Object date){
consequence.clear();
consequence.setCode(code);
consequence.setDate(date);
consequence.setMsg(msg);
return getResult(consequence);
}
public static String getResult(Consequence consequence){
return JSON.toJSONStringWithDateFormat(consequence,dateFormat,SerializerFeature.DisableCircularReferenceDetect);
}
}
/**
* @Auther: mzl
* @Date: 2019/4/11 13:56
* @Description:结果返回封装工具
*/
public class Consequence {
private Integer code;
private String msg;
private Object date;
private String devMsg;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getDate() {
return date;
}
public void setDate(Object date) {
this.date = date;
}
public String getDevMsg() {
return devMsg;
}
public void setDevMsg(String devMsg) {
this.devMsg = devMsg;
}
public void clear(){
this.code=null;
this.date=null;
this.msg=null;
this.devMsg=null;
}
}
到此关键代码基本完成,DEMO比较简陋,仅供参考