1-異常處理-異常處理的問題分析
參考文檔:
https://blog.csdn.net/kinginblue/article/details/70186586
自定義異常:
1:
10001 非法參數
10002 參數缺失
2:
2001 數據庫異常
2003 網絡異常
從添加頁面的service方法中找問題:
//添加頁面
public CmsPageResult add(CmsPage cmsPage){
//校驗頁面是否存在,根據頁面名稱、站點Id、頁面webpath查詢
CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
if(cmsPage1==null){
cmsPage.setPageId(null);//添加頁面主鍵由spring data 自動生成
cmsPageRepository.save(cmsPage);
//返回結果
CmsPageResult cmsPageResult = new CmsPageResult(CommonCode.SUCCESS,cmsPage);
return cmsPageResult;
}
return new CmsPageResult(CommonCode.FAIL,null);
}
問題:
1、上邊的代碼只要操作不成功僅向用戶返回“錯誤代碼:11111,失敗信息:操作失敗”,無法區別具體的錯誤信
息。
2、service方法在執行過程出現異常在哪捕獲?在service中需要都加try/catch,如果在controller也需要添加
try/catch,代碼冗餘嚴重且不易維護。
解決方案:
1、在Service方法中的編碼順序是先校驗判斷,有問題則拋出具體的異常信息,最後執行具體的業務操作,返回成
功信息。
2、在統一異常處理類中去捕獲異常,無需controller捕獲異常,向用戶返回統一規範的響應信息。
//添加頁面
public CmsPageResult add(CmsPage cmsPage){
//校驗cmsPage是否爲空
if(cmsPage == null){
//拋出異常,非法請求
//...
}
//根據頁面名稱查詢(頁面名稱已在mongodb創建了唯一索引)
CmsPage cmsPage1 =
cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(),
cmsPage.getSiteId(), cmsPage.getPageWebPath());
//校驗頁面是否存在,已存在則拋出異常
if(cmsPage1 !=null){
//拋出異常,已存在相同的頁面名稱
//...
}
cmsPage.setPageId(null);//添加頁面主鍵由spring data 自動生成
CmsPage save = cmsPageRepository.save(cmsPage);
//返回結果
CmsPageResult cmsPageResult = new CmsPageResult(CommonCode.SUCCESS,save);
return cmsPageResult;
}
2-異常處理-異常處理流程
系統對異常的處理使用統一的異常處理流程:
1、自定義異常類型。
2、自定義錯誤代碼及錯誤信息。
3、對於可預知的異常由程序員在代碼中主動拋出,由SpringMVC統一捕獲。
可預知異常是程序員在代碼中手動拋出本系統定義的特定異常類型,由於是程序員拋出的異常,通常異常信息比較
齊全,程序員在拋出時會指定錯誤代碼及錯誤信息,獲取異常信息也比較方便。
4、對於不可預知的異常(運行時異常)由SpringMVC統一捕獲Exception類型的異常。
不可預知異常通常是由於系統出現bug、或一些不要抗拒的錯誤(比如網絡中斷、服務器宕機等),異常類型爲
RuntimeException類型(運行時異常)。
5、可預知的異常及不可預知的運行時異常最終會採用統一的信息格式(錯誤代碼+錯誤信息)來表示,最終也會隨請求響應給客戶端。``
異常拋出及處理流程:
1、在controller、service、dao中程序員拋出自定義異常;springMVC框架拋出框架異常類型
2、統一由異常捕獲類捕獲異常,並進行處理
3、捕獲到自定義異常則直接取出錯誤代碼及錯誤信息,響應給用戶。
4、捕獲到非自定義異常類型首先從Map中找該異常類型是否對應具體的錯誤代碼,如果有則取出錯誤代碼和錯誤
信息並響應給用戶,如果從Map中找不到異常類型所對應的錯誤代碼則統一爲99999錯誤代碼並響應給用戶。
5、將錯誤代碼及錯誤信息以Json格式響應給用戶。
3-異常處理-可預知異常處理-自定義異常類型和拋出類
CustomException.java
/**
* 自定義異常類
*/
public class CustomException extends RuntimeException {
private ResultCode resultCode;
public CustomException(ResultCode resultCode) {
//異常信息爲錯誤代碼+異常信息
super("錯誤代碼:" + resultCode.code() + "錯誤信息:" + resultCode.message());
this.resultCode = resultCode;
}
public ResultCode getResultCode() {
return this.resultCode;
}
}
ExceptionCast.java
public class ExceptionCast {
//使用此靜態方法拋出自定義異常
public static void cast(ResultCode resultCode){
throw new CustomException(resultCode);
}
}
ExceptionCatch.java
/**
* 統一異常捕獲類
*
* 在spring 3.2中,新增了@ControllerAdvice 註解,
* 可以用於定義@ExceptionHandler、@InitBinder、@ModelAttribute,並應用到所有@RequestMapping中。
*/
@ControllerAdvice // 控制器增強
public class ExceptionCatch {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class);
//捕獲 CustomException異常
@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseResult customException(CustomException e) {
// 記錄日誌
LOGGER.error("catch exception : {} exception: ",e.getMessage(), e);
ResultCode resultCode = e.getResultCode();
ResponseResult responseResult = new ResponseResult(resultCode);
return responseResult;
}
}
4-異常處理-可預知異常處理-異常處理測試
PageService.java
在add()的代碼中加入異常處理:
//校驗cmsPage是否爲空
if(cmsPage1 != null){
//拋出異常,非法請求
ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
}
CmsCode.java
@ToString
public enum CmsCode implements ResultCode {
CMS_ADDPAGE_EXISTSNAME(false,24001,"頁面名稱已存在!"),
CMS_GENERATEHTML_DATAURLISNULL(false,24002,"從頁面信息中找不到獲取數據的url!"),
CMS_GENERATEHTML_DATAISNULL(false,24003,"根據頁面的數據url獲取不到數據!"),
CMS_GENERATEHTML_TEMPLATEISNULL(false,24004,"頁面模板爲空!"),
CMS_GENERATEHTML_HTMLISNULL(false,24005,"生成的靜態html爲空!"),
CMS_GENERATEHTML_SAVEHTMLERROR(false,24005,"保存靜態html出錯!"),
CMS_COURSE_PERVIEWISNULL(false,24007,"預覽頁面爲空!");
//操作代碼
boolean success;
//操作代碼
int code;
//提示信息
String message;
private CmsCode(boolean success, int code, String message){
this.success = success;
this.code = code;
this.message = message;
}
@Override
public boolean success() {
return success;
}
@Override
public int code() {
return code;
}
@Override
public String message() {
return message;
}
}
ManageCmsApplication.java
在覈心啓動類上加入包掃描,去掃描common項目的包
@SpringBootApplication
@EntityScan("com.yunke.framework.domain.cms")//掃描實體類
@ComponentScan(basePackages={"com.yunke.api"})//掃描接口
@ComponentScan(basePackages={"com.yunke.framework"})//掃描common包下的類
@ComponentScan(basePackages={"com.yunke.manage_cms"})//掃描本項目下的所有類
public class ManageCmsApplication {
public static void main(String[] args) {
SpringApplication.run(ManageCmsApplication.class,args);
}
}
測試
當出現重複頁面的時候,無法進行保存,錯誤提示也是我們自己定義的了.
5-異常處理-不可預知異常處理
ExceptionCatch.java
//使用EXCEPTIONS存放異常類型和錯誤代碼的映射,ImmutableMap的特點的一旦創建不可改變,並且線程安全
private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
//使用builder來構建一個異常類型和錯誤代碼的異常
protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();
static{
//在這裏加入一些基礎的異常類型判斷
builder.put(HttpMessageNotReadableException.class,CommonCode.INVALID_PARAM);
}
//捕獲Exception異常
@ResponseBody
@ExceptionHandler(Exception.class)
public ResponseResult exception(Exception e) {
LOGGER.error("catch exception : {} \r\n exception: ",e.getMessage(), e);
if(EXCEPTIONS == null) {
EXCEPTIONS = builder.build(); // EXCEPTIONS構建完畢
}
// 從EXCEPTIONS中尋找異常類型對應的錯誤代碼,如果找到了將錯誤代碼響應給用戶,如果找不到就返回給用戶9999
final ResultCode resultCode = EXCEPTIONS.get(e.getClass());
if (resultCode != null) {
return new ResponseResult(resultCode);
} else {
return new ResponseResult(CommonCode.SERVER_ERROR);
}
}
CommonCode.java
@ToString
public enum CommonCode implements ResultCode{
INVALID_PARAM(false,10003,"非法參數!"),
}