错误处理
几个要点:1、异常类,使用
@ControllerAdvice
注解,配合@ExceptionHandler
注解处理各种异常。2、统一响应格式 3、统一异常枚举类
后台发生的所有错误,@ControllerAdvice + @ExceptionHandler
进行统一异常处理。
- 首先所有的异常被抛出来,都会进入到RestControllerAdvice里面被处理
- 我们就在这里面对异常进行
自定义处理
(让spring能够感知异常让我们自己去处理) - 处理的话就需要给定
响应结果
(统一前后端 请求体 ) - 还需要定义
异常的枚举类
(对错误异常进行统一管理)
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* Exception
*/
@ExceptionHandler(value={Exception.class})
public R exceptionHandle(HttpServletRequest req, Exception e) {
String msg = StrUtil.sub(StrUtil.isEmpty(e.getMessage()) ? e.toString() : e.getMessage(), 0, 256);
JSONObject jsonObject = new JSONObject();
jsonObject.set("code", "E001");
jsonObject.set("message", msg);
log.error("请求 " + req.getRequestURL() + " 抛出异常: " + e);
log.error(msg, e);
return R.builder().code(500).message("异常:" + msg).data(jsonObject).build();
}
/**
* 自定义业务异常
*/
@ExceptionHandler(BusinessException.class)
public R BusinessExceptionHandle(HttpServletRequest req, WorkSystemException e) {
String msg = StrUtil.sub(StrUtil.isEmpty(e.getMessage()) ? e.toString() : e.getMessage(), 0, 256);
JSONObject jsonObject = new JSONObject();
jsonObject.set("code", e.getCode());
jsonObject.set("message", msg);
log.error("请求 " + req.getRequestURL() + " 抛出异常: " + e);
log.error(msg, e);
return R.builder().code(500).message("异常:" + msg).data(jsonObject).build();
}
}
标准模板
统一响应格式R
import lombok.*;
import java.io.Serializable;
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class R<T> implements Serializable {
private static final long serialVersionUID = 111111111111111L;
/**
* 成功标记
*/
static Integer SUCCESS = 0;
/**
* 失败标记
*/
static Integer FAIL = 1;
private int code;
private String message;
private T data;
public static <T> R<T> success() {
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> success(T data) {
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> success(T data, String msg) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> failure() {
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> failure(T data) {
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> failure(T data, String msg) {
return restResult(data, FAIL, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
return new R<>(code, msg, data);
}
}
GlobalExceptionHandler
使用
@ControllerAdvice
注解,配合@ExceptionHandler
注解处理各种异常。
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* Exception
*/
@ExceptionHandler(Exception.class)
public R exceptionHandle(HttpServletRequest req, Exception e) {
String msg = StrUtil.sub(StrUtil.isEmpty(e.getMessage()) ? e.toString():e.getMessage(), 0, 256);
JSONObject jsonObject = new JSONObject();
jsonObject.set("code", "E001");
jsonObject.set("message", msg);
log.error("请求 " + req.getRequestURL() + " 抛出异常: " + e);
log.error(msg, e);
return R.builder().code(500).message("异常:" + msg).data(jsonObject).build();
}
/**
* 自定义业务异常
*/
@ExceptionHandler(CustomException.class)
public R CustomExceptionHandle(HttpServletRequest req, CustomException e) {
String msg = StrUtil.sub(StrUtil.isEmpty(e.getMessage()) ? e.toString():e.getMessage(), 0, 256);
JSONObject jsonObject = new JSONObject();
jsonObject.set("code", e.getCode());
jsonObject.set("message", msg);
log.error("请求 " + req.getRequestURL() + " 抛出异常: " + e);
log.error(msg, e);
return R.builder().code(500).message("异常:" + msg).data(jsonObject).build();
}
/**
* 处理业务校验过程中碰到的非法参数异常 该异常基本由{@link org.springframework.util.Assert}抛出
*
* @param exception 参数校验异常
* @return API返回结果对象包装后的错误输出结果
*/
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.OK)
public R handleIllegalArgumentException(IllegalArgumentException exception) {
log.error("非法参数,ex = {}", exception.getMessage(), exception);
return R.failure(exception.getMessage());
}
/**
* validation Exception
*
* @param exception
* @return R
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleBodyValidException(MethodArgumentNotValidException exception) {
List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
log.warn("参数绑定异常,ex = {}", fieldErrors.get(0).getDefaultMessage());
return R.failure(fieldErrors.get(0).getDefaultMessage());
}
/**
* validation Exception (以form-data形式传参)
*
* @param exception
* @return R
*/
@ExceptionHandler({BindException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R bindExceptionHandler(BindException exception) {
List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
log.warn("参数绑定异常,ex = {}", fieldErrors.get(0).getDefaultMessage());
return R.failure(fieldErrors.get(0).getDefaultMessage());
}
}
异常枚举类
public enum CustomExceptionInfoEnum {
/**
* 系统通用异常 001~500
*/
REQUEST_PARAM_MISS("001", "请求缺少接口必要参数:{0}"),
UNKNOWN_EXCEPTION("002", "未知异常"),
SYSTEM_RUN_EXCEPTION("003", "系统运行异常"),
TIMEOUT("004", "超时"),
DATA_FORMAT_ERR("005", "数据格式异常"),
INTERFACE_MESSAGE_ERR("006", "接口通讯异常"),
;
/**
* 异常码
*/
private String code;
private String name;
CustomExceptionInfoEnum(String code, String name) {
this.code = code;
this.name = name;
}
}