平常我们写后端接口时经常遇到大范围使用try catch,或者本应返回封装的response的结果返回了一个异常给前端,针对这些问题,可以考虑给他做全局异常处理,优雅的返回处理每一个异常。
1. 创建一个BaseException类,后续所有自定义异常类都要继承这个类
@Getter
@Setter
public class BaseException extends RuntimeException{
private Integer code;
private String msg;
public BaseException(StateCode stateCode) {
super(stateCode.getMsg());
this.code = stateCode.getCode();
this.msg = stateCode.getMsg();
}
}
2. 自定义异常类,如LoginException
public class LoginException extends BaseException {
public LoginException(StateCode stateCode) {
super(stateCode);
}
}
3. 请求返回状态代码类
public enum StateCode {
OK(0, "请求成功"),
SERVER_ERROR(10001, "网络异常"),
/**
* 用户不存在
*/
USER_NOT_FOUND(50001, "用户不存在"),
/**
* 无token
*/
LOGIN_NOT_TOKEN(50002, "无token,请重新登录"),
/**
* 参数有误
*/
LOGIN_PARAM_ERROR(50003, "参数有误"),
/**
* 无效token
*/
TOKEN_INVALID(50004, "无效token")
;
private Integer code;
private String 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;
}
StateCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
4. 返回结果封装类
@Data
public class ApiResponse<T> implements Serializable {
private static final int SUCCESS_CODE = 0;
private static final int FAIL_CODE = 500;
private T data;
private Integer code;
private String msg;
private Long currentTime;
public static<T> ApiResponse<T> ok(){
ApiResponse<T> apiResponse = new ApiResponse<T>();
apiResponse.setCode(SUCCESS_CODE);
apiResponse.setMsg("success");
apiResponse.setCurrentTime(System.currentTimeMillis());
return apiResponse;
}
public static<T> ApiResponse<T> ok(T data){
ApiResponse<T> apiResponse = ok();
apiResponse.setData(data);
return apiResponse;
}
public static<T> ApiResponse<T> error(String message) {
ApiResponse<T> apiResponse = new ApiResponse<T>();
apiResponse.setCode(FAIL_CODE);
apiResponse.setMsg(message);
apiResponse.setCurrentTime(System.currentTimeMillis());
return apiResponse;
}
public static<T> ApiResponse<T> error(Integer code, String message) {
ApiResponse<T> apiResponse = new ApiResponse<T>();
apiResponse.setCode(code);
apiResponse.setMsg(message);
apiResponse.setCurrentTime(System.currentTimeMillis());
return apiResponse;
}
}
5. 全局异常处理类(重点)
/**
* 全局异常处理
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private final static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
*自定义异常处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(BaseException.class)
public ApiResponse<Void> customException(BaseException e){
log.error("code={},msg={}", e.getCode(), e.getMsg(), e);
return ApiResponse.error(e.getCode(),e.getMessage());
}
/**
* 默认异常处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(Exception.class)
public Object defaultException(Exception e) {
String msg = e.getMessage();
log.error(e.getMessage(), e);
if (StringUtils.isEmpty(msg)) {
msg = StateCode.SERVER_ERROR.getMsg();
}
return ApiResponse.error(StateCode.SERVER_ERROR.getCode(), msg);
}
/**
* 请求类型不支持异常处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ApiResponse<Void> httpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e){
log.error(e.getMessage(), e);
return ApiResponse.error("不支持该请求类型");
}
}
6. 测试
@RestController
public class TestController {
@GetMapping("test1")
public ApiResponse<Integer> test1() {
Integer aa = 100/0;
return ApiResponse.ok(aa);
}
@GetMapping("test2")
public ApiResponse test2() {
throw new LoginException(StateCode.SERVER_ERROR);
}
}
GitHub项目地址:https://github.com/zyz1130083243/GlobalExceptionExample.git