情景引入
導入
問題
異常統一處理
出現的情景
開發環境
開發步驟
創建自定義異常
創建消息返回的包裝實體
定義一系列的枚舉返回信息
定義消息返回工具類
定義異常統一處理類(重點)
定義異常處理頁面
效果
開發環境
正式環境
總結
情景引入
(我)呼嚕呼嚕呼嚕呼嚕。。。。。。。。
(小白)起床起床起床,,快點起床。。。
(我)小白,又遇到什么事了,這么火急火燎的,年輕人,做事要穩重
(小白)我遇到了一個很嚴重的問題,想讓你指導指導我!
(我)哎喲,這次這么虛心請教啦,那我不生氣了,,你說,怎么了呢?
(小白)就是,我在開發的過程中,因為是團隊開發,所以,有時候邏輯就對不上,然后就會 莫名其妙的出現一些問題,并且顯示的效果非常難堪,而且也不容易發現問題,每次都要查看后臺才能知道問題,可是部署到服務器之后,都只能看Log日志來定位問題。
(我)對呀,這項目開發本來就是一個團隊的事情,這是很正常的事,有什么大驚小怪呢?
(小白)所以,我想著,有沒有什么辦法,可以針對系統中的異常(未知和已知)能夠友好的進行顯示呢?這樣,我們在交流的時候也相對更加方便呀,否則,總是看著一堆亂七八糟的錯誤,挺心煩的。
(我)我好像理解了你的意思。你就是想著,能對系統中的異常能夠友好顯示或者說能方便你們團隊開發嘛。
(小白)對的對的,就是這么個意思。
(我)這當然有了,而且你現在遇到的這個問題,其實在每個系統中都應該有進行處理,雖然它比較簡單,但是不容小視,也有很多重要的東西的呢~那就好好聽課吧!
(小白)真開心,,,,,迫不及待了
導入
問題
針對Web項目來說,我們都知道,一般都是一個團隊進行開發,而不會是一個人單打獨斗,并且開發團隊還有前后端的人員,那么有一定的規范就是必不可少的。
我們可能都遇到過一個問題,就是開發環境和正式上線的環境是有很大的差別的。開發環境是針對我們開發人員,而正式環境是一種以用戶的角度來審視我們的整個系統。想想一個問題,如果遇到了我們在開發中沒有碰到的異常,而用戶卻發現了,用戶體驗是不是會非常不好,而且這是我們的一個大忌。。
既然如此,我們也知道,開發過程中,有如此多的異常可能會出現,那么里面就包含著我們已經考慮到了的,然而還有一些隱藏的異常卻是我們可能忽視的,所以,為了能夠將那些潛在的異常不被用戶直接發現,而影響用戶體驗,這---------異常統一處理,,,就必不可少!
異常統一處理
定義:
簡單點說,就是針對我們系統中的異常,給予一定規范的處理結果。(比如,默認的情況,就是將異常堆棧信息直接打印到頁面,然而這種是極其丑陋的)
出現的情景
開發人員預測得到的自定義異常:在開發中,開發人員對某些可能出現的情形是可以預知的,這時候是一種主動處理的狀態。
開發人員無法預測的系統異常:在開發中,存在著開發人員無法全面思考到的異常,那么這時候就是一種潛在性的可能異常狀態。
前端和后臺交互異常:由于前后端的分離,而且前后端的開發方向也存在著差異,那么就有可能導致異常的出現。
開發環境
windows 7 + 渣渣筆記本
IDEA + SpringBoot + Mybatis +Mysql
開發步驟
創建自定義異常
分析:在系統中,存在著系統異常和我們人為的自定義異常,所以,為了能夠有效的針對不同異常進行處理,那么擁有我們自定義的異常類是非常有必要的。
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:自定義異常,為了區分系統異常和更方便系統的特定一些處理 *@ Modified By: *@Version:1 */ publicclassMyExceptionextendsRuntimeException{ //錯誤碼 privateIntegercode; publicIntegergetCode(){ returncode; } publicvoidsetCode(Integercode){ this.code=code; } publicMyException(Stringmessage){ super(message); } /** *構造器重載,主要是自己考慮某些異常自定義一些返回碼 *@paramcode *@parammessage */ publicMyException(Integercode,Stringmessage){ super(message); this.code=code; } }
創建消息返回的包裝實體
分析:對于后臺返回給前端的數據來說,我們很多情況都是返回的JSON格式的數據(當然,并不是局限于這一種),那么JSON是一種格式化的形式。
所以,我們應該有效的針對這樣的形式來給予一定的返回規范,這樣也方便前端對于我們返回數據的解析。
比如:很多情況一般是如下的格式:
{ "retCode":200,//通過狀態碼可以得到消息是否返回正常,然后再決定是否去解析data域的內容 "data":{//返回的數據內容 } "retMes":success//返回的提示內容 }
所以,我們可以定義如下的類:
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:異常處理實體包裝類,自己用泛型進行寫,擴展性強點 *@ Modified By: *@Version:1 */ publicclassResult{ //返回碼 privateIntegercode; //返回消息 privateStringmsg; //返回數據 privateTdata; publicIntegergetCode(){ returncode; } publicvoidsetCode(Integercode){ this.code=code; } publicStringgetMsg(){ returnmsg; } publicvoidsetMsg(Stringmsg){ this.msg=msg; } publicTgetData(){ returndata; } publicvoidsetData(Tdata){ this.data=data; } }
定義一系列的枚舉返回信息
分析:在系統中,我們應該有統一的某些編碼對應某些內容,這樣能夠方便開發人員進行及時的處理。
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:自定義一些返回狀態碼,便于本系統的使用,自己先定義如下的,有需要就后續補充 *@ Modified By: *@Version:1 */ publicenumResultEnum{ /** *成功.:200(因為http中的狀態碼200一般都是表示成功) */ SUCCESS(200,"成功"), /** *系統異常.ErrorCode:-1 */ SystemException(-1,"系統異常"), /** *未知異常.ErrorCode:01 */ UnknownException(01,"未知異常"), /** *服務異常.ErrorCode:02 */ ServiceException(02,"服務異常"), /** *業務錯誤.ErrorCode:03 */ MyException(03,"業務錯誤"), /** *提示級錯誤.ErrorCode:04 */ InfoException(04,"提示級錯誤"), /** *數據庫操作異常.ErrorCode:05 */ DBException(05,"數據庫操作異常"), /** *參數驗證錯誤.ErrorCode:06 */ ParamException(06,"參數驗證錯誤"); privateIntegercode; privateStringmsg; ResultEnum(Integercode,Stringmsg){ this.code=code; this.msg=msg; } publicIntegergetCode(){ returncode; } publicStringgetMsg(){ returnmsg; } }
定義消息返回工具類
分析:對于消息的返回,這是一個非常普通的工作,所以,我們可以將其封裝一個工具類,能夠進行有效代碼的封裝,減少多余的代碼
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:返回消息處理的工具類,主要是處理操作成功和失敗的一些內容 *@ Modified By: *@Version:1 */ publicclassResultUtil{ /** *操作成功的處理流程 *@paramobject *@return */ publicstaticResultgetSuccess(Objectobject){ Resultresult=newResult(); //設置操作成功的返回碼 result.setCode(200); //設置操作成功的消息 result.setMsg("成功"); result.setData(object); returnresult; } /** *重載返回成功的方法,因為有時候我們不需要任何的消息數據被返回 *@return */ publicstaticResultgetSuccess(){ returngetSuccess(null); } /** *操作失敗的處理流程 *@paramcode錯誤碼 *@parammsg錯誤消息 *@paramo錯誤數據(其實這個一般都不需要的,因為都已經返回失敗了,數據都沒必要返回) *@return */ publicstaticResultgetError(Integercode,Stringmsg,Objecto){ Resultresult=newResult(); result.setCode(code); result.setMsg(msg); result.setData(o); returnresult; } /** *重載,操作失敗的方法(因為操作失敗一般都不需要返回數據內容) *@paramcode *@parammsg *@return */ publicstaticResultgetError(Integercode,Stringmsg){ returngetError(code,msg,null); } }
定義異常統一處理類(重點)
分析:這是如何實現異常統一處理的關鍵地方,而且我也將不同的處理情形,進行了分開注釋,所以,大家一定可以認真的看代碼,我相信你一定能夠明白。
packagecom.hnu.csapp.exception; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.web.bind.annotation.ControllerAdvice; importorg.springframework.web.bind.annotation.ExceptionHandler; importorg.springframework.web.bind.annotation.ResponseBody; importorg.springframework.web.servlet.ModelAndView; importjavax.servlet.http.HttpServletRequest; /** *@ Author :scw *@ Description:異常統一處理類,方便用戶可以更加友好的看到錯誤信息 *@ Modified By: *@Version:1 */ @ControllerAdvice publicclassExceptionHandle{ //增加異常日志打印 privatefinalstaticLoggerlogger=LoggerFactory.getLogger(ExceptionHandle.class); //設置異常錯誤的頁面 publicstaticfinalStringDEFAULT_ERROR_VIEW="error"; /** *以json的格式進行返回內容(開發環境一般個人是用這個比較好) *@parame *@return */ @ExceptionHandler(Exception.class) @ResponseBody publicObjecthandle(HttpServletRequestreq,Exceptione){ //如果是自定義的異常 if(einstanceofMyException){ MyExceptionmyException=(MyException)e; returnResultUtil.getError(myException.getCode(),myException.getMessage()); }else{ //如果是系統的異常,比如空指針這些異常 logger.error("【系統異常】={}",e); returnResultUtil.getError(ResultEnum.SystemException.getCode(),ResultEnum.SystemException.getMsg()); } } /** *判斷是否是Ajax的請求 *@paramrequest *@return */ publicbooleanisAjax(HttpServletRequestrequest){ return(request.getHeader("X-Requested-With")!=null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString())); } /* //備注: //這個是正式項目完成之后的錯誤統一處理(開發情況先用上面的的) //我們在開發過程中還是用json格式的會好一些,要不然看錯誤麻煩 @ExceptionHandler(value=Exception.class) publicModelAndViewdefaultErrorHandler(HttpServletRequestreq,Exceptione)throwsException{ e.printStackTrace(); //判斷是否是Ajax的異常請求(如果是Ajax的那么就是返回json格式) if(isAjax(req)){ //如果是自定義的異常 if(einstanceofMyException){ MyExceptionmyException=(MyException)e; returnResultUtil.getError(myException.getCode(),myException.getMessage()); }else{ //如果是系統的異常,比如空指針這些異常 logger.error("【系統異常】={}",e); returnResultUtil.getError(ResultEnum.SystemException.getCode(),ResultEnum.SystemException.getMsg()); } }else{ //如果是系統內部發生異常,那么就返回到錯誤頁面進行友好的提示 ModelAndViewmav=newModelAndView(); //這些就是要返回到頁面的內容(其實不用都行,反正用戶也不懂,沒必要在頁面顯示都可以,先寫著吧) mav.addObject("exception",e); mav.addObject("url",req.getRequestURL()); mav.setViewName(DEFAULT_ERROR_VIEW); returnmav; } } */ }
定義異常處理頁面
分析:這個的話,其實主要是在正式環境才有,因為我們在測試環境的時候,一般都還是會將錯誤以JSON或者堆棧的格式顯示在頁面,而當上線的時候,那么就一定要有一個統一的錯誤頁面,這樣就能夠讓用戶發現不了是系統出現了哪些問題。
效果
開發環境
正式環境
分析:當出現異常的時候,則顯示如下的頁面。(該頁面是參考一個博友的,感覺挺有意思,,老司機~)
總結
異常統一處理,或許我們看起來實現非常簡單,然而,其他它包含的思想卻是一種大局思想,這是我們開發人員在開發過程中都應該關注的點,我們并不是只需要關注我們每個人開發的那點任務,而要以一種全局的角度去審視整個項目,這樣也能夠提升我們開問題的高度。
異常統一處理,是每個項目都存在的,只是可能實現的方式不一樣而已,或者顯示的效果不一樣而已,這些都不是關鍵的地方。
異常統一處理這個問題,并不是很難,但是這個可以幫助我們延伸到其他的一些相關的開發層面的知識,比如:
登錄攔截
權限管理
日志管理
事務處理
數據控制和過濾
。。。
所以,我們應該學會從一個問題,發散的看到相關類似的問題,這樣,我們的系統才會更加健壯,高效和可擴展性強。
-
Web
+關注
關注
2文章
1255瀏覽量
69336 -
服務器
+關注
關注
12文章
9021瀏覽量
85183 -
開發環境
+關注
關注
1文章
222瀏覽量
16586
原文標題:減少 try-catch ,這樣做才叫優雅!
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論