统一异常的封装,主要是为了减少前后端人员沟通时间,来提高工作效率,http状态码,返回是否请求成功
pom导入Lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
统一异常的分装
/**
* 统一请求分装
* @Data Lombok 是一個 Java library,可以透過簡單的注解省略 Java 的 code,像是 setter、getter、logger…等,目的在消除冗長的 code 和提高開發效率
*/
@Data
public class AjaxResponse {
private boolean isok; //请求是否处理成功 true或者false
private int code; //请求响应状态码 使用http状态码 比如:200请求成功,400用户输入错误导致的异常,500系统内部异常
private String message; //请求结果描述信息
private Object data; //请求结果数据(通常用于查询操作)
private AjaxResponse() {
}
//请求出现异常时的响应数据封装
public static AjaxResponse error(CustomException e) {
AjaxResponse resultBean = new AjaxResponse();
resultBean.setIsok(false);
resultBean.setCode(e.getCode());
if (e.getCode() == CustomExceptionType.USER_INPUT_ERROR.getCode()) {
resultBean.setMessage(e.getMessage());
} else if (e.getCode() == CustomExceptionType.SYSTEM_ERROR.getCode()) {
resultBean.setMessage(e.getMessage() + ",请将该异常信息发送给管理员!");
} else {
resultBean.setMessage("系统出现未知异常,请联系管理员!");
}
//TODO 这里最好将异常信息持久化
return resultBean;
}
//请求出现异常时的响应数据封装
public static AjaxResponse error(CustomExceptionType customExceptionType,
String errorMessage) {
AjaxResponse resultBean = new AjaxResponse();
resultBean.setIsok(false);
resultBean.setCode(customExceptionType.getCode());
resultBean.setMessage(errorMessage);
return resultBean;
}
//请求处理成功时的数据响应
public static AjaxResponse success() {
AjaxResponse resultBean = new AjaxResponse();
resultBean.setIsok(true);
resultBean.setCode(200);
resultBean.setMessage("success");
return resultBean;
}
//请求处理成功,并响应结果数据
public static AjaxResponse success(Object data) {
AjaxResponse ajaxResponse = AjaxResponse.success();
ajaxResponse.setData(data);
return ajaxResponse;
}
}
枚举异常
/**
* ExceptionTypeEnum 枚举异常分类,将异常分类固化下来,防止开发人员思维发散。
*/
public enum CustomExceptionType {
USER_INPUT_ERROR(400, "您输入的数据错误或您没有权限访问资源!"),
SYSTEM_ERROR(500, "系统出现异常,请您稍后再试或联系管理员!"),
OTHER_ERROR(999, "系统出现未知异常,请联系管理员!");
private String desc;//异常类型中文描述
private int code; //code
//构造方法
CustomExceptionType(int code, String desc) {
this.code = code;
this.desc = desc;
}
//get set方法
public String getDesc() {
return desc;
}
public int getCode() {
return code;
}
}
自定义异常
/**
* 自定义异常有两个核心内容,一个是code。使用CustomExceptionType 来限定范围。
* 另外一个是message,这个message信息是要最后返回给前端的,所以需要用友好的提示来表达异常发生的原因或内容
*
*/
public class CustomException extends RuntimeException {
//异常错误编码
private int code;
//异常信息
private String message;
//无参构造函数
private CustomException() {
}
//使用分类固化异常,不希望程序员创建异常 ,===使用CustomExceptionType 来限定范围
public CustomException(CustomExceptionType exceptionTypeEnum) {
this.code = exceptionTypeEnum.getCode();
this.message = exceptionTypeEnum.getDesc();
}
//这个message信息是要最后返回给前端的,所以需要用友好的提示来表达异常发生的原因或内容
public CustomException(CustomExceptionType exceptionTypeEnum,
String message) {
this.code = exceptionTypeEnum.getCode();
this.message = message;
}
public int getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
使用http状态码和业务返回的统一
/***
* AjaxResponse的code是400代表的是业务状态,也就是说用户的请求业务失败了
* 但是HTTP请求是成功的,也就是说数据是正常返回的。
* 公司开发RESTful服务时,要求HTTP状态码能够体现业务的最终执行状态,所以说:我们有必要让业务状态与HTTP协议Response状态码一致。
* 因为在GlobalResponseAdvice 里面会统一再封装为AjaxResponse。
*/
@Component
@ControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
//进行统一封装,不在在Controller 统一返回AjaxResponse结果 做到返回什么就是什么
@Override
public Object beforeBodyWrite(Object body,
MethodParameter methodParameter,
MediaType mediaType, Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
//如果响应结果是JSON数据类型
if(mediaType.equalsTypeAndSubtype(
MediaType.APPLICATION_JSON)){
if(body instanceof AjaxResponse){
AjaxResponse ajaxResponse = (AjaxResponse)body;
if(ajaxResponse.getCode() != 999){ //999 不是标准的HTTP状态码,特殊处理
serverHttpResponse.setStatusCode(HttpStatus.valueOf(
ajaxResponse.getCode()
));
}
return body;
}else{
serverHttpResponse.setStatusCode(HttpStatus.OK);
return AjaxResponse.success(body);
}
}
return body;
}
}
将程序异常转换自定义异常
@ControllerAdvice
public class WebExceptionHandler {
//处理程序员主动转换的自定义异常
@ExceptionHandler(CustomException.class)
@ResponseBody
public AjaxResponse customerException(CustomException e) {
if (e.getCode() == CustomExceptionType.SYSTEM_ERROR.getCode()) {
//400异常不需要持久化,将异常信息以友好的方式告知用户就可以
//TODO 将500异常信息持久化处理,方便运维人员处理
}
return AjaxResponse.error(e);
}
//未能捕获(遗漏的)异常信息
@ExceptionHandler(Exception.class)
@ResponseBody
public AjaxResponse exception(Exception e) {
//TODO 将异常信息持久化处理,方便运维人员处理
//没有被程序员发现,并转换为CustomException的异常,都是其他异常或者未知异常.
return AjaxResponse.error(new CustomException(CustomExceptionType.OTHER_ERROR, "未知异常"));
}
}