对于全局异常需要认识两个注解
@RestControllerAdvice,@ExceptionHandler
1、 @RestControllerAdvice
组成:@ControllerAdvice、@ResponseBody
@RestControllerAdvice特点:
(1)通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置,他可以管理所有的Controller。
(2)注解了@RestControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
(3)@RestControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。
(4)@ExceptionHandler:用于指定异常处理方法。当与@RestControllerAdvice配合使用时,用于全局处理控制器里的异常。
(5)
@InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
@ModelAttribute:本来作用是绑定键值对到Model中,当与@ControllerAdvice配合使用时,可以让全局的@RequestMapping都能获得在此处设置的键值对**
2、@ExceptionHandler注解我们一般是用来自定义异常的。
可以认为它是一个异常拦截器(处理器)。
@ExceptionHandler(xxx.class)
xxx.class是具体的异常类
例如:NullPointerException
例子
全局异常捕获
自定义异常类
自定义异常类继承RuntimeException
public class Mall4cloudException extends RuntimeException {
private static final long serialVersionUID = 1L;
private Object object;
private ResponseEnum responseEnum;
public Mall4cloudException(String msg) {
super(msg);
}
public Mall4cloudException(String msg, Object object) {
super(msg);
this.object = object;
}
public Mall4cloudException(String msg, Throwable cause) {
super(msg, cause);
}
public Mall4cloudException(ResponseEnum responseEnum) {
super(responseEnum.getMsg());
this.responseEnum = responseEnum;
}
public Mall4cloudException(ResponseEnum responseEnum, Object object) {
super(responseEnum.getMsg());
this.responseEnum = responseEnum;
this.object = object;
}
public Object getObject() {
return object;
}
public ResponseEnum getResponseEnum() {
return responseEnum;
}
}
自定义返回状态码类型
package com.mall4j.cloud.common.response;
/**
* @author FrozenWatermelon
* @date 2020/7/9
*/
public enum ResponseEnum {
/**
* ok
*/
OK("00000", "ok"),
/**
* 用于直接显示提示用户的错误,内容由输入内容决定
*/
SHOW_FAIL("A00001", ""),
/**
* 方法参数没有校验,内容由输入内容决定
*/
METHOD_ARGUMENT_NOT_VALID("A00002", ""),
/**
* 无法读取获取请求参数
*/
HTTP_MESSAGE_NOT_READABLE("A00003", "请求参数格式有误"),
/**
* 未授权
*/
UNAUTHORIZED("A00004", "Unauthorized"),
/**
* 服务器出了点小差
*/
EXCEPTION("A00005", "服务器出了点小差"),
/**
* 数据异常
*/
DATA_ERROR("A00007", "数据异常,请刷新后重新操作"),
/**
* 一些需要登录的接口,而实际上因为前端无法知道token是否已过期,导致token已失效时,
* 应该返回一个状态码,告诉前端token已经失效了,及时清理
*/
CLEAN_TOKEN("A00008", "clean token"),
/**
* 刷新token已过期
*/
REFRESH_TOKEN_EXIST("A00009", "refresh token exist"),
/**
* 数据不完整
*/
DATA_INCOMPLETE("A00010", "数据不完整"),
/**
* 01开头代表商品
*/
SPU_NOT_EXIST("A01000", "spu not exist"),
/**
* 02开头代表购物车
*/
SHOP_CART_NOT_EXIST("A02000", "shop cart not exist"),
/**
* 03开头代表订单
*/
ORDER_NOT_EXIST("A03000", "order not exist"),
/**
* 请勿重复提交订单,
* 1.当前端遇到该异常时,说明前端防多次点击没做好
* 2.提示用户 订单已发生改变,请勿重复下单
*/
REPEAT_ORDER("A03002", "please don't repeat order"),
/**
* 订单已过期,当前端看到该状态码的时候,提示订单信息已过期,请重新确认后提交,此时用户点击确定,前端刷新页面。
*/
ORDER_EXPIRED("A03003", "order expired"),
/**
* 订单已支付,无法取消订单
*/
ORDER_PAYED("A03007", "order payed"),
/**
* 订单未发货,无法确认收货
*/
ORDER_NO_DELIVERY("A03008", "order no delivery"),
/**
* 库存不足,body会具体返回那个skuid的库存不足
*/
NOT_STOCK("A03010", "not stock"),
/**
* 订单未完成或未关闭,无法删除订单
*/
ORDER_NOT_FINISH_OR_CLOSE("A03011", "order not finish or close"),
/**
* 订单未支付
*/
ORDER_NOT_PAYED("A03012", "order not payed"),
/**
* 订单已失败
*/
ORDER_HAS_FAILED("A03013", "order has failed"),
/**
* 没有查询权限
*/
REFUND_NOT_PERMISSION("A03024", "refund not permission"),
/**
* 撤销失败 当前状态不允许此操作
*/
REFUND_STATUS_CHECK("A03034", "refund status check"),
/**
* 04 开头代表注册登录之类的异常状态
* 社交账号未绑定,当前端看到该异常时,应该在合适的时间(比如在购买的时候跳)根据社交账号的类型,跳转到绑定系统账号的页面
*/
SOCIAL_ACCOUNT_NOT_BIND("A04001", "social account not bind"),
/**
* 有些时候第三方系统授权之后,会有个临时的key,比如小程序的session_key
* 这个异常代表session_key过期,前端遇到这个问题的时候,应该再次调用社交登录的接口,刷新session_key
*/
BIZ_TEMP_SESSION_KEY_EXPIRE("A04002", "biz temp session key expire"),
/**
* 账号未注册,前端看到这个状态码,弹出选择框,提示用户账号未注册,是否进入注册页面,用户选择是,进入注册页面
*/
ACCOUNT_NOT_REGISTER("A04003", "account not register");
private final String code;
private final String msg;
public String value() {
return code;
}
public String getMsg() {
return msg;
}
ResponseEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String toString() {
return "ResponseEnum{" + "code='" + code + ''' + ", msg='" + msg + ''' + "} " + super.toString();
}
}
这个是返回状态码的初始化,就是每个接口都会返回状态码的格式
package com.mall4j.cloud.common.response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Objects;
/**
* 统一的返回数据
*
* @author FrozenWatermelon
* @date 2020/7/3
*/
public class ServerResponseEntity implements Serializable {
private static final Logger log = LoggerFactory.getLogger(ServerResponseEntity.class);
/**
* 状态码
*/
private String code;
/**
* 信息
*/
private String msg;
/**
* 数据
*/
private T 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 T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public boolean isSuccess() {
return Objects.equals(ResponseEnum.OK.value(), this.code);
}
@Override
public String toString() {
return "ServerResponseEntity{" + "code=" + code + ", msg='" + msg + ''' + ", data=" + data + '}';
}
public static ServerResponseEntity success(T data) {
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setData(data);
serverResponseEntity.setCode(ResponseEnum.OK.value());
return serverResponseEntity;
}
public static ServerResponseEntity success() {
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(ResponseEnum.OK.value());
serverResponseEntity.setMsg(ResponseEnum.OK.getMsg());
return serverResponseEntity;
}
/**
* 前端显示失败消息
* @param msg 失败消息
* @return
*/
public static ServerResponseEntity showFailMsg(String msg) {
log.error(msg);
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(msg);
serverResponseEntity.setCode(ResponseEnum.SHOW_FAIL.value());
return serverResponseEntity;
}
public static ServerResponseEntity fail(ResponseEnum responseEnum) {
log.error(responseEnum.toString());
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value());
return serverResponseEntity;
}
public static ServerResponseEntity fail(ResponseEnum responseEnum, T data) {
log.error(responseEnum.toString());
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value());
serverResponseEntity.setData(data);
return serverResponseEntity;
}
public static ServerResponseEntity transform(ServerResponseEntity> oldServerResponseEntity) {
ServerResponseEntity serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(oldServerResponseEntity.getMsg());
serverResponseEntity.setCode(oldServerResponseEntity.getCode());
log.error(serverResponseEntity.toString());
return serverResponseEntity;
}
}
接口层会返回固定的格式
后续更新自定义异常处理
码云地址:https://gitee.com/yuisuiWork/spring_project_demo/
欢迎交流,一起进步!
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦