高端網(wǎng)站建設(shè)上海深圳網(wǎng)絡(luò)推廣哪家公司好
統(tǒng)一異常處理
- 1. 說明
- 2. 問題描述
- 3. 異常處理器使用
- 3.1 創(chuàng)建異常處理器類
- 3.2 讓程序拋出異常
- 3.3 測(cè)試
- 4. 項(xiàng)目異常處理方案
- 4.1 異常分類
- 4.2 異常解決方案
- 4.3 異常解決方案的具體實(shí)現(xiàn)
- 4.4 測(cè)試
- 5. 總結(jié)
1. 說明
\quad本篇文章是在文章SpringMVC:SSM整合(SpringMVC+Spring+Mybatis)案例(9)和SpringMVC:統(tǒng)一封裝結(jié)果(10)的基礎(chǔ)上進(jìn)行講解的,建議在讀本篇文章之前建議預(yù)先了解這兩篇文章。
2. 問題描述
前端接收到這個(gè)信息后和之前我們約定的格式(統(tǒng)一返回Result類)不一致,這個(gè)問題該如何解決?
在解決問題之前,我們先來看下異常的種類及出現(xiàn)異常的原因:
- 框架內(nèi)部拋出的異常:因使用不合規(guī)導(dǎo)致
- 數(shù)據(jù)層拋出的異常:因外部服務(wù)器故障導(dǎo)致(例如:服務(wù)器訪問超時(shí))
- 業(yè)務(wù)層拋出的異常:因業(yè)務(wù)邏輯書寫錯(cuò)誤導(dǎo)致(例如:遍歷業(yè)務(wù)書寫操作,導(dǎo)致索引異常等)
- 表現(xiàn)層拋出的異常:因數(shù)據(jù)收集、校驗(yàn)等規(guī)則導(dǎo)致(例如:不匹配的數(shù)據(jù)類型間導(dǎo)致異常)
- 工具類拋出的異常:因工具類書寫不嚴(yán)謹(jǐn)不夠健壯導(dǎo)致(例如:必要釋放的連接長(zhǎng)期未釋放等)
在開發(fā)的任何一個(gè)位置都有可能出現(xiàn)異常,而且這些異常是不能避免的。所以我們就得將異常進(jìn)行處理。
-
各個(gè)層級(jí)均出現(xiàn)異常,異常處理代碼書寫在哪一層?
所有的異常均拋出到表現(xiàn)層進(jìn)行處理
-
異常的種類很多,表現(xiàn)層如何將所有的異常都處理到呢?
異常分類
-
表現(xiàn)層處理異常,每個(gè)方法中單獨(dú)書寫,代碼書寫量巨大且意義不強(qiáng),如何解決?
AOP
3. 異常處理器使用
3.1 創(chuàng)建異常處理器類
在controller層下創(chuàng)建異常處理器類:
// @RestControllerAdvice用于標(biāo)識(shí)當(dāng)前類為REST風(fēng)格對(duì)應(yīng)的異常處理器
// @ControllerAdvice用于標(biāo)識(shí)當(dāng)前類為普通風(fēng)格對(duì)應(yīng)的異常處理器
@RestControllerAdvice
public class ProjectExceptionAdvice {// 除了自定義的異常處理器,保留對(duì)Exception類型的異常處理,用于處理非預(yù)期的異常@ExceptionHandler(Exception.class)public void doException(Exception ex){System.out.println("出現(xiàn)異常。")}
}
3.2 讓程序拋出異常
修改BookController
的getById方法,添加int i = 1/0
.
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {int i = 1/0;Book book = bookService.getById(id);Integer code = book != null ? Code.GET_OK : Code.GET_ERR;String msg = book != null ? "" : "數(shù)據(jù)查詢失敗,請(qǐng)重試!";return new Result(code,book,msg);
}
3.3 測(cè)試
說明異常已經(jīng)被攔截并執(zhí)行了doException
方法。
4. 項(xiàng)目異常處理方案
4.1 異常分類
因?yàn)楫惓5姆N類有很多,如果每一個(gè)異常都對(duì)應(yīng)一個(gè)@ExceptionHandler,那得寫多少個(gè)方法來處理各自的異常,所以我們?cè)谔幚懋惓V?#xff0c;需要對(duì)異常進(jìn)行一個(gè)分類:
-
業(yè)務(wù)異常(BusinessException)
-
規(guī)范的用戶行為產(chǎn)生的異常
- 用戶在頁面輸入內(nèi)容的時(shí)候未按照指定格式進(jìn)行數(shù)據(jù)填寫,如在年齡框輸入的是字符串
-
不規(guī)范的用戶行為操作產(chǎn)生的異常
- 如用戶故意傳遞錯(cuò)誤數(shù)據(jù)
-
-
系統(tǒng)異常(SystemException)
- 項(xiàng)目運(yùn)行過程中可預(yù)計(jì)但無法避免的異常
- 比如數(shù)據(jù)庫(kù)或服務(wù)器宕機(jī)
- 項(xiàng)目運(yùn)行過程中可預(yù)計(jì)但無法避免的異常
-
其他異常(Exception)
- 編程人員未預(yù)期到的異常,如:用到的文件不存在
將異常分類以后,針對(duì)不同類型的異常,要提供具體的解決方案:
4.2 異常解決方案
- 業(yè)務(wù)異常(BusinessException)
- 發(fā)送對(duì)應(yīng)消息傳遞給用戶,提醒規(guī)范操作
- 大家常見的就是提示用戶名已存在或密碼格式不正確等
- 發(fā)送對(duì)應(yīng)消息傳遞給用戶,提醒規(guī)范操作
- 系統(tǒng)異常(SystemException)
- 發(fā)送固定消息傳遞給用戶,安撫用戶
- 系統(tǒng)繁忙,請(qǐng)稍后再試
- 系統(tǒng)正在維護(hù)升級(jí),請(qǐng)稍后再試
- 系統(tǒng)出問題,請(qǐng)聯(lián)系系統(tǒng)管理員等
- 發(fā)送特定消息給運(yùn)維人員,提醒維護(hù)
- 可以發(fā)送短信、郵箱或者是公司內(nèi)部通信軟件
- 記錄日志
- 發(fā)消息和記錄日志對(duì)用戶來說是不可見的,屬于后臺(tái)程序
- 發(fā)送固定消息傳遞給用戶,安撫用戶
- 其他異常(Exception)
- 發(fā)送固定消息傳遞給用戶,安撫用戶
- 發(fā)送特定消息給編程人員,提醒維護(hù)(納入預(yù)期范圍內(nèi))
- 一般是程序沒有考慮全,比如未做非空校驗(yàn)等
- 記錄日志
4.3 異常解決方案的具體實(shí)現(xiàn)
思路:
-
先通過自定義異常,完成BusinessException和SystemException的定義
-
將其他異常包裝成自定義異常類型
-
在異常處理器類中對(duì)不同的異常進(jìn)行處理
步驟一:定義兩個(gè)異常處理器
自定義系統(tǒng)異常處理器,用于封裝異常信息,對(duì)異常進(jìn)行分類:
public class SystemException extends RuntimeException{private Integer code;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public SystemException(Integer code, String message) {super(message);this.code = code;}public SystemException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;}}
自定義業(yè)務(wù)異常處理器,用于封裝異常信息,對(duì)異常進(jìn)行分類:
public class BusinessException extends RuntimeException{private Integer code;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public BusinessException(Integer code, String message) {super(message);this.code = code;}public BusinessException(Integer code, String message, Throwable cause) {super(message, cause);this.code = code;}
}
說明:
- 讓自定義異常類繼承
RuntimeException
的好處是,后期在拋出這兩個(gè)異常的時(shí)候,就不用在try…catch…或throws了 - 自定義異常類中添加
code
屬性的原因是為了更好的區(qū)分異常是來自哪個(gè)業(yè)務(wù)的
步驟2:將其他異常包成自定義異常
public Book getById(Integer id) {//模擬業(yè)務(wù)異常,包裝成自定義異常if(id == 15){throw new BusinessException(Code.BUSINESS_ERR,"業(yè)務(wù)層出現(xiàn)異常");}//模擬系統(tǒng)異常,將可能出現(xiàn)的異常進(jìn)行包裝,轉(zhuǎn)換成自定義異常try{int i = 1/0;}catch (Exception e){throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服務(wù)器訪問超時(shí),請(qǐng)重試!",e);}return bookDao.getById(id);
}
狀態(tài)碼Code類:
// 狀態(tài)碼
public class Code {public static final Integer SAVE_OK = 20011;public static final Integer SAVE_ERR = 20010;public static final Integer DELETE_OK = 20021;public static final Integer DELETE_ERR = 20020;public static final Integer UPDATE_OK = 20031;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_OK = 20041;public static final Integer GET_ERR = 20040;public static final Integer SYSTEM_ERR = 50001;public static final Integer SYSTEM_TIMEOUT_ERR = 60001;public static final Integer SYSTEM_UNKNOW_ERR = 70001;public static final Integer BUSINESS_ERR = 80001;}
步驟3:處理器類中處理自定義異常
package com.itheima.controller;import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @Author Mr.Lu* @Date 2023/2/11 9:36* @ClassName ProjectExceptionAdvice* @Version 1.0*/
// @RestControllerAdvice用于標(biāo)識(shí)當(dāng)前類為REST風(fēng)格對(duì)應(yīng)的異常處理器
@RestControllerAdvice
public class ProjectExceptionAdvice {@ExceptionHandler(BusinessException.class)public Result doBusinessException(BusinessException ex){return new Result(ex.getCode(), null, ex.getMessage());}@ExceptionHandler(SystemException.class)public Result doSystemException(SystemException ex){// 記錄日志// 發(fā)送消息給運(yùn)維// 發(fā)送郵件給開發(fā)人員,ex對(duì)象發(fā)送給開發(fā)人員return new Result(ex.getCode(), null, ex.getMessage());}// 除了自定義的異常處理器,保留對(duì)Exception類型的異常處理,用于處理非預(yù)期的異常@ExceptionHandler(Exception.class)public Result doOtherException(Exception ex){//記錄日志//發(fā)送消息給運(yùn)維//發(fā)送郵件給開發(fā)人員,ex對(duì)象發(fā)送給開發(fā)人員return new Result(8888,null, "系統(tǒng)繁忙,請(qǐng)稍后再試!");}
}
4.4 測(cè)試
根據(jù)ID查詢,如果傳入的參數(shù)為15,會(huì)報(bào)BusinessException
如果傳入的是其他參數(shù),會(huì)報(bào)SystemException
5. 總結(jié)
項(xiàng)目中的異常處理方式: