SpringMVC Controllrt 层的异常处理 (@ExceptionHandler)
SpringMVC Controllrt 层的异常处理 :
一、统一的返回格式
当我向前端返回数据时,无论是否成功,我都希望能提供一个统一的返回格式,和一个友善的错误提示。所以在完成异常处理前,先提供一个统一的返回格式CommonReturnType,它暂时含有两个字段
status 表示上传数据成功或者失败,data 则是要 上传的数据。当成功上传数据时,status 为 “success ”,data 为 数据;当失败时 status 为 “fail”, data 为 错误的详细。
private String status; private Object data;
代码:
package com.snapshot2.demo.response; /** * 通用的返回体,用于向前端返回一个通用的数据结构体 */ public class CommonReturnType { //表明返回的类型是"success " 或者 "fail" private String status; //若status = success data内放回前端需要的数据 //若status = fail data内返回相应的错误信息 private Object data; /* 两种创建方法 */ /** * 当只传入数据data 时,默认成功 * @param result * @return */ public static CommonReturnType creat(Object result){ return creat(result,"success"); } /** * 当传入status 和 object 时使用这个创建方法 * @param result * @param status * @return */ public static CommonReturnType creat(Object result, String status){ CommonReturnType commonReturnType = new CommonReturnType(); commonReturnType.setData(result); commonReturnType.setStatus(status); return commonReturnType; } /* 省略 Getter and Setter */
二、使用装饰器模式来自定义一个Controller 层的异常
我们使用一个枚举来定义自己的一些异常类型,然后使用装饰器模式来实现对应的功能:
UML 类设计图:
代码实现:
CommonErr:
package com.snapshot2.demo.error; /** * 通用的异常接口,整合后端异常反馈给前端,使用装饰器模式 * 这是装饰器的统一接口 */ public interface CommonError { public int getErrCode(); public String getErrMsg(); public CommonError setErrMsg(String errMsg); }
CommonErrEnum:
package com.snapshot2.demo.error; public enum CommonErrEnum implements CommonError { //00001 通用的参数不合法错误码 PARAMTER_VALIDATION_ERROR(00001,"参数不合法"), UNKOWN_ERROR(00002,"未知错误"), //10000开头的错误码代表用户信息相关的错误 USER_NOT_EXIST(100001,"用户不存在"); private int errCode; private String errMsg; /* Constructor */ CommonErrEnum(int errCode, String errMsg) { this.errCode = errCode; this.errMsg = errMsg; } @Override public int getErrCode() { return this.errCode; } @Override public String getErrMsg() { return this.errMsg; } @Override public CommonError setErrMsg(String errMsg) { this.errMsg = errMsg; return this; } }
UserExceprion
package com.snapshot2.demo.error; /** * 使用到了包装器模式 */ public class UserException extends Exception implements CommonError { //强关联一个CommonError(CommonErrorEnum) private CommonError commonError; //直接接受一个CommonEnum,用于构造一个业务异常 public UserException(CommonError commonError){ //调用Exception的初始化机制 super(); this.commonError = commonError; } /* Constructor */ public UserException(CommonError commonError,String errMsg){ super(); this.commonError = commonError; this.commonError.setErrMsg(errMsg); } public void setCommonError(CommonError commonError) { this.commonError = commonError; } @Override public int getErrCode() { return this.commonError.getErrCode(); } @Override public String getErrMsg() { return this.commonError.getErrMsg(); } @Override public CommonError setErrMsg(String errMsg) { this.commonError.setErrMsg(errMsg); return this.commonError; } }
我们可以看到,UserException 继承与Exception类,又实现了CommonErr接口。它关联了一个实现CommonErr接口的类(这里就是我们定义的Enum类),并且可以使用并增强它的方法。
之后我们就可以在Controller层使用@ExceptionHandler(Exception.class) 注解来捕获在Controler层出现的Exception异常,并且消化它,向前端返回友善的错误提示:
//定义ExceptionHandler解决Controller层未被处理掉的异常 @ExceptionHandler(Exception.class) //Controller 层返回的异常应该属于后端的异常 @ResponseStatus(HttpStatus.OK) @ResponseBody public Object handlerException(HttpServletRequest request, Exception e){ Map<String,Object> responseData = new HashMap<>(); CommonReturnType commonReturnType = new CommonReturnType(); if(e instanceof UserException){ //强制转化捕获的错误为UserException UserException userException = (UserException)e; //将错误信息转化为通用的上传格式 commonReturnType.setStatus("fail"); //将自定义的Exception 信息提取出来放在返回体中 responseData.put("errCode",userException.getErrCode()); responseData.put("errMsg",userException.getErrMsg()); commonReturnType.setData(responseData); } else{ responseData.put("errCode",CommonErrEnum.UNKOWN_ERROR.getErrCode()); responseData.put("errMsg",CommonErrEnum.UNKOWN_ERROR.getErrMsg()); commonReturnType.setStatus("fail"); commonReturnType.setData(responseData); } return commonReturnType; }