一、前言:
SpringBoot的項目已經對有一定的異常處理了,但是對於我們開發者而言可能就不太合適了,因此我們需要對這些異常進行統一的捕獲並處理。SpringBoot中有一個ControllerAdvice
的注解,使用該注解表示開啟了全局異常的捕獲,我們只需在自定義一個方法使用ExceptionHandler
注解然后定義捕獲異常的類型即可對這些捕獲的異常進行統一的處理。
二、目的
解決錯誤異常清晰、異常擴展性強、統一管理異常枚舉類。
看了網上一些自定義異常,覺得不是太適用項目,異常展示不是太清晰,自己寫了一套全局異常,只是為了解決開發者易於觀察,方便擴展,如有不足之處還望大佬賜教。
三、目錄截圖
四、開始編碼
1.配置application.yml,方便開發者自定義開發模式,用於項目獲取模式,展示異常。
1 server: 2 port: 80 3 #spring相關配置 4 spring: 5 profiles: 6 active: @spring.active@
2.異常枚舉基類,多個實現,用於統一管理異常枚舉類。
1 /** 2 * 異常基類 3 */ 4 public interface BaseExceptionEnum { 5 6 public String getMessage(); 7 8 }
3.鑒權模塊異常枚舉類、只定義了一個異常類,如果有其他模塊、可以定義多個實現BaseExceptionEnum ,用於異常管理,好找。
1 /** 2 * 鑒權模塊異常----按照模塊划分 3 */ 4 public enum AuthExceptionEnum implements BaseExceptionEnum { 5 /** 6 * 賬號或密碼為空 7 */ 8 USERNAME_PASS_NULL("賬號或密碼為空"), 9 /** 10 * 登錄驗證碼為空或過期 11 */ 12 USER_VERIFICATION_CODE_NULL("登錄驗證碼為空或已過期"), 13 /** 14 * 登錄驗證碼錯誤 15 */ 16 USER_VERIFICATION_CODE("登錄驗證碼錯誤"), 17 /** 18 * 登錄密碼錯誤 19 */ 20 USERNAME_PASS_ERROR("登錄密碼錯誤"), 21 /** 22 * 登錄失敗 23 */ 24 USER_LOGIN__ERROR("登錄失敗"), 25 /** 26 * 登錄用戶不存在 27 */ 28 USER_NON_EXISTENT("登錄用戶不存在"), 29 /** 30 * 登錄用戶不存在 31 */ 32 USER_HAS_BEEN_DELETE("登錄用戶不存在!"), 33 /** 34 * 登錄用戶已凍結 35 */ 36 USER_FROZEN( "登錄用戶已凍結!"); 37 38 39 40 private final String message; 41 42 AuthExceptionEnum(String message) { 43 this.message = message; 44 } 45 AuthExceptionEnum(BaseExceptionEnum baseExceptionEnum) { 46 this.message =baseExceptionEnum.getMessage(); 47 } 48 49 @Override 50 public String getMessage() { 51 return message; 52 } 53 }
4.定義統一異常類
1 /** 2 * 異常統一 3 */ 4 public class BaseException extends RuntimeException { 5 6 private static final long serialVersionUID = 1L; 7 8 private final int code; 9 private final String value; 10 11 protected BaseException(int code, String message) { 12 super(message); 13 this.code = code; 14 this.value = message; 15 } 16 public int getCode() { 17 return this.code; 18 } 19 }
5.自定義響應用戶異常類
1 /** 2 * 用戶請求錯誤 3 * 向用戶展示的異常錯誤對象 400 {"code":"1","message":"exception.message"} 4 */ 5 public class UserAlertException extends BaseException { 6 7 public UserAlertException(String message) { 8 super(1, message); 9 } 10 public UserAlertException(int code, String message) { 11 super(code, message); 12 } 13 public UserAlertException(BaseExceptionEnum exceptionEnum) { 14 super(1, exceptionEnum.getMessage()); 15 } 16 }
4.編寫開發模式工廠類獲取,方便擴展、易於維護。
1 /** 2 * @ClassName: ExceptionPattern 3 * @Description: 異常模式 4 * @Author: fuzongle 5 * @create: 2020-11-24 13:43 6 **/ 7 public class ExceptionPatternFactory { 8 9 public Map<String, Function<Exception, ResponseResult>> map = new HashMap<>(); 10 11 { 12 map.put("dev", this::dev); 13 map.put("prod", this::prod); 14 } 15 16 //編寫生產環境的業務錯誤異常邏輯 17 public ResponseResult prod(Exception e) { 18 return ResponseResult.builder().build(); 19 } 20 21 //編寫開發環境的業務錯誤異常邏輯 22 public ResponseResult dev(Exception e) { 23 return new ExceptionFactory().map.get(e.getClass().getName()).apply(e); 24 } 25 26 27 }
5.編寫異常統一返回格式、打印日志工廠類、本身想把這個用在開發模式、線上模式在建一個類維護線上的異常、現在項目上線大部分異常看日志的話、阿里雲不是太方便、定位問題太慢,想集成存儲異常日志,提供ui展示、也是再次基礎上擴展生成模式即可。
1 /** 2 * @ClassName: ExceptionPattern 3 * @Description: 異常模式 4 * @Author: fuzongle 5 * @create: 2020-11-24 13:43 6 **/ 7 @Log4j2 8 public class ExceptionFactory { 9 10 public Map<Object, Function<Object, ResponseResult>> map = new HashMap<>(); 11 12 { 13 map.put(UserAlertException.class.getName(), this::UserAlertException); 14 map.put(ArithmeticException.class.getName(), this::ArithmeticException); 15 } 16 17 18 /** 19 * 用戶請求錯誤 像用戶展示 20 */ 21 public ResponseResult UserAlertException(Object e) { 22 UserAlertException userAlertException = (UserAlertException) e; 23 24 PrintlnErrorLog.printlnErrorLog("->>>自定義異常-給用戶展示錯誤對象", 25 ErrorUtils.getStackTrace(userAlertException), 26 userAlertException.getStackTrace()[0]); 27 28 return ResponseResult.builder().code(userAlertException.getCode()).message(userAlertException.getMessage()).build(); 29 } 30 31 /** 32 * 算術運算異常 33 */ 34 public ResponseResult ArithmeticException(Object e) { 35 ArithmeticException userAlertException = (ArithmeticException) e; 36 37 PrintlnErrorLog.printlnErrorLog("->>>算術運算異常", 38 ErrorUtils.getStackTrace(userAlertException), 39 userAlertException.getStackTrace()[0]); 40 41 return ResponseResult.builder().code(HttpStatus.BAD_REQUEST.value()).message(userAlertException.getMessage()).build(); 42 } 43 44 45 46 }
5.打印異常日志、方法、可以提供開發者快速定位問題。
1 /** 2 * 異常日志 3 */ 4 public static void printlnErrorLog(String title,String errInfo,StackTraceElement stackTraceElement) { 5 6 log.info("\n-----------------------異常分析 start-----------------------------------\n\t" + 7 "異常標題:{}\n\t" + 8 "文件名:{}\n\t" + 9 "類名:{}\n\t" + 10 "方法名:{}\n\t" + 11 "拋出異常行號:{}\n\t" + 12 "異常棧信息:{}\n\t" + 13 "解決方案: {}\n" + 14 "------------------異常分析 end ---------------------------------------", 15 title, 16 stackTraceElement.getFileName(), 17 stackTraceElement.getClassName(), 18 stackTraceElement.getMethodName(), 19 stackTraceElement.getLineNumber(), 20 errInfo, 21 "暫無"); 22 }
6.實現全局控制器通知、全局捕獲異常、統一返回方式。@ExceptionHandler 攔截了異常,我們可以通過該注解實現自定義異常處理。其中,@ExceptionHandler 配置的 value 指定需要攔截的異常類型,上面攔截了 Exception.class 這種異常。
1 /** 2 * @ClassName: ExceptionPattern 3 * @Description: 全局異常配置 4 * @Author: fuzongle 5 * @create: 2020-11-25 12:43 6 **/ 7 @Slf4j 8 @RestControllerAdvice 9 public class GlobalExceptionHandler { 10 11 12 /** 13 * 獲取開發模式、生產模式、默認dev 14 */ 15 @Value("${spring.profiles.active}") 16 private String var; 17 18 /** 19 * 全局異常. 20 */ 21 @ExceptionHandler(Exception.class) 22 public ResponseEntity<ResponseResult> handleGlobalException(Exception e) { 23 ResponseResult apply = new ExceptionPatternFactory().map.get(var).apply(e); 24 int httpStatus = Objects.equals(HttpStatus.INTERNAL_SERVER_ERROR.value(), apply.getCode()) ? HttpStatus.INTERNAL_SERVER_ERROR.value() : HttpStatus.BAD_REQUEST.value(); 25 return new ResponseEntity<>(apply, HttpStatus.valueOf(httpStatus)); 26 } 27 28 29 }
五、測試異常
1.直接編寫API瀏覽器請求看結果。
1 /** 2 * @Description: 測試 3 **/ 4 @RestController 5 public class ErrorController { 6 7 /** 8 * 自定義異常測試 9 * @return 10 */ 11 @RequestMapping("/test") 12 public String test() { 13 throw new UserAlertException(AuthExceptionEnum.USER_FROZEN); 14 } 15 16 /** 17 * 系統捕獲的異常 18 */ 19 @RequestMapping("/ArithmeticException") 20 public void ArithmeticException() { 21 System.out.println(1/0); 22 } 23 }
2.響應結果,結果非常清晰,可以在開發的地方遇見異常記錄異常維護、ExceptionFactory維護異常,百度找到的解決方案可以再次記錄,方便下次不在忘記錯誤,提高了開發效率。
六、溫馨提示
1.如果有任何不懂的地方可以咨詢我,隨時歡迎互相幫助,如果寫的不好的地方請大佬指教。
2.技術交流群QQ:422167709。
3.如果希望學習更多,希望微信掃碼,長按掃碼,幫忙關注一下,舉手之勞,當您無助的時候真的能幫你。
4.獲取源代碼:掃碼關注。回復任意字符、加作者微信秒發源碼。