SpringBoot進行優雅的全域性異常處理
在專案中經常出現系統異常的情況,比如NullPointerException
等等。如果預設未處理的情況下,springboot
會響應預設的錯誤提示,這樣對使用者體驗不是友好,系統層面的錯誤,使用者不能感知到,即使為500
的錯誤,可以給使用者提示一個類似伺服器開小差
的友好提示等。這時候便可以使用全域性異常處理器來優雅的處理全域性異常
定義錯誤訊息類
-
在全域性異常類中會使用該錯誤訊息進行初始化
-
注意該訊息的toString方法要寫成Json格式的
-
具體的錯誤訊息初始化的時候也可以使用%s一類的佔位符,後期呼叫靜態方法,來填充多個引數
-
這裡使用了@Data註解省去了自己編寫建構函式,詳情可以查詢lombook使用方法
@Data
@AllArgsConstructor
@Slf4j
public class CodeMsg implements Serializable {
private int code;
private String msg;
public static CodeMsg SUCCESS = new CodeMsg(200, "success");
public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "伺服器錯誤");
public static CodeMsg INSERT_ERROR = new CodeMsg(500200, "插入錯誤");
public static CodeMsg UNKNOWN_ERROR = new CodeMsg(-999, "未知錯誤:%s");
//填充多個錯誤資訊
public static CodeMsg BIND_ERROR = new CodeMsg(500300,"引數校驗異常:%s");
public static CodeMsg UNSELECT_FILE_ERROR = new CodeMsg(500400,"未選擇檔案");
public static CodeMsg FILE_NOT_EXIST_ERROR = new CodeMsg(500500, "檔案或資料夾不存在");
public static CodeMsg UPLOADING = new CodeMsg(500600, "正在上傳");
//補充未知錯誤的具體資訊
public CodeMsg fillArgs(Object... args){
int code = this.code;
String message = String.format(this.msg,args);
return new CodeMsg(code,message);
}
//處理異常時返回json的toString
@Override
public String toString() {
return "CodeMsg{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
// public static void main(String[] args) {
// log.info(new CodeMsg(0, "hello").toString());
// }
}
複製程式碼
定義全域性異常類
- 之後遇到什麼錯誤,可以用錯誤訊息類初始化全域性異常類,並丟擲該異常,該異常之後會被全域性異常處理器捕獲
//繼承RuntimeException,並定義serialVersionUID
public class GlobalException extends RuntimeException {
private static final long serialVersionUID = -3586828184536704147L;
private CodeMsg codeMsg;
public GlobalException(CodeMsg codeMsg) {
super(codeMsg.toString());
this.codeMsg = codeMsg;
}
public CodeMsg getCodeMsg() {
return codeMsg;
}
}
複製程式碼
定義返回結果類
- 返回結果有兩種,一種是返回相應的錯誤碼,一種是返回正確的驗證碼+資料,因此我們編寫返回結果類
@Data
@ApiModel(description = "返回結果")
public class Result<T> implements Serializable {
private int code;
private T data;
private String msg;
private Result(T data) {
this.code = 0;
this.msg = "success";
this.data = data;
}
private Result() {
this.code = 0;
this.msg = "success";
this.data = null;
}
private Result(CodeMsg codeMsg) {
if (codeMsg == null) {
return;
}
this.code = codeMsg.getCode();
this.msg = codeMsg.getMsg();
}
public static <T> Result<T> success(T data) {
return new Result<T>(data);
}
public static <T> Result<T> success() {
return new Result<T>();
}
public static <T> Result<T> error(CodeMsg codeMsg) {
return new Result<T>(codeMsg);
}
}
複製程式碼
定義全域性異常處理器
-
使用@ControllerAdvice來指定全域性異常處理
-
使用@RestController返回json資料
-
使用@ExceptionHandler來捕獲特定的異常種類
@ControllerAdvice
@RestController
@Slf4j
public class GlobalExceptionHandler {
//自定義異常類
@ExceptionHandler(value = GlobalException.class)
public Result<String> globalExceptionHandler(HttpServletRequest request, GlobalException e) {
log.error(e.getCodeMsg().getMsg());
return Result.error(e.getCodeMsg());
}
//引數檢測不合格
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result<String> bindExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
log.error(e.getClass().toString());
// log.error(e.toString());
List<ObjectError> errors = e.getBindingResult().getAllErrors();
StringBuilder errorMsg = new StringBuilder();
//此處僅取第一個
// ObjectError objectError = errors.get(0);
for (ObjectError error : errors) {
errorMsg.append(error.getDefaultMessage()).append(" ");
}
// String errorMsg = objectError.getDefaultMessage();
//填充具體異常
return Result.error(CodeMsg.BIND_ERROR.fillArgs(errorMsg.toString()));
}
//其他異常類
@ExceptionHandler(value = Exception.class)
public Result<String> defaultExceptionHandler(HttpServletRequest request, Exception e) {
log.error(e.getClass().toString());
log.error(e.toString());
e.printStackTrace();
return Result.error(CodeMsg.UNKNOWN_ERROR.fillArgs(e.getClass().toString()));
}
//可定義詳細的其他異常類
// @ExceptionHandler(AuthenticationException.class) //此處為shiro未登入異常類
// @ResponseStatus(HttpStatus.UNAUTHORIZED)
// public String unAuth(AuthenticationException e) {
// log.error("使用者未登陸:", e);
// return "/login.html";
// }
}
複製程式碼
效果
至此,便完成了自定義的全域性異常處理方法,訪問效果如下
//成功
{
code = 0;
msg = "success";
data = 456;
}
//失敗
{
code = 500100;
msg = "伺服器錯誤";
data = null;
}
複製程式碼