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;
}
|