情景引入
導(dǎo)入
問題
異常統(tǒng)一處理
出現(xiàn)的情景
開發(fā)環(huán)境
開發(fā)步驟
創(chuàng)建自定義異常
創(chuàng)建消息返回的包裝實(shí)體
定義一系列的枚舉返回信息
定義消息返回工具類
定義異常統(tǒng)一處理類(重點(diǎn))
定義異常處理頁面
效果
開發(fā)環(huán)境
正式環(huán)境
總結(jié)
情景引入
(我)呼嚕呼嚕呼嚕呼嚕。。。。。。。。
(小白)起床起床起床,,快點(diǎn)起床。。。
(我)小白,又遇到什么事了,這么火急火燎的,年輕人,做事要穩(wěn)重
(小白)我遇到了一個(gè)很嚴(yán)重的問題,想讓你指導(dǎo)指導(dǎo)我!
(我)哎喲,這次這么虛心請教啦,那我不生氣了,,你說,怎么了呢?
(小白)就是,我在開發(fā)的過程中,因?yàn)槭菆F(tuán)隊(duì)開發(fā),所以,有時(shí)候邏輯就對不上,然后就會 莫名其妙的出現(xiàn)一些問題,并且顯示的效果非常難堪,而且也不容易發(fā)現(xiàn)問題,每次都要查看后臺才能知道問題,可是部署到服務(wù)器之后,都只能看Log日志來定位問題。
(我)對呀,這項(xiàng)目開發(fā)本來就是一個(gè)團(tuán)隊(duì)的事情,這是很正常的事,有什么大驚小怪呢?
(小白)所以,我想著,有沒有什么辦法,可以針對系統(tǒng)中的異常(未知和已知)能夠友好的進(jìn)行顯示呢?這樣,我們在交流的時(shí)候也相對更加方便呀,否則,總是看著一堆亂七八糟的錯(cuò)誤,挺心煩的。
(我)我好像理解了你的意思。你就是想著,能對系統(tǒng)中的異常能夠友好顯示或者說能方便你們團(tuán)隊(duì)開發(fā)嘛。
(小白)對的對的,就是這么個(gè)意思。
(我)這當(dāng)然有了,而且你現(xiàn)在遇到的這個(gè)問題,其實(shí)在每個(gè)系統(tǒng)中都應(yīng)該有進(jìn)行處理,雖然它比較簡單,但是不容小視,也有很多重要的東西的呢~那就好好聽課吧!
(小白)真開心,,,,,迫不及待了
導(dǎo)入
問題
針對Web項(xiàng)目來說,我們都知道,一般都是一個(gè)團(tuán)隊(duì)進(jìn)行開發(fā),而不會是一個(gè)人單打獨(dú)斗,并且開發(fā)團(tuán)隊(duì)還有前后端的人員,那么有一定的規(guī)范就是必不可少的。
我們可能都遇到過一個(gè)問題,就是開發(fā)環(huán)境和正式上線的環(huán)境是有很大的差別的。開發(fā)環(huán)境是針對我們開發(fā)人員,而正式環(huán)境是一種以用戶的角度來審視我們的整個(gè)系統(tǒng)。想想一個(gè)問題,如果遇到了我們在開發(fā)中沒有碰到的異常,而用戶卻發(fā)現(xiàn)了,用戶體驗(yàn)是不是會非常不好,而且這是我們的一個(gè)大忌。。
既然如此,我們也知道,開發(fā)過程中,有如此多的異??赡軙霈F(xiàn),那么里面就包含著我們已經(jīng)考慮到了的,然而還有一些隱藏的異常卻是我們可能忽視的,所以,為了能夠?qū)⒛切撛诘漠惓2槐挥脩糁苯影l(fā)現(xiàn),而影響用戶體驗(yàn),這---------異常統(tǒng)一處理,,,就必不可少!
異常統(tǒng)一處理
定義:
簡單點(diǎn)說,就是針對我們系統(tǒng)中的異常,給予一定規(guī)范的處理結(jié)果。(比如,默認(rèn)的情況,就是將異常堆棧信息直接打印到頁面,然而這種是極其丑陋的)
出現(xiàn)的情景
開發(fā)人員預(yù)測得到的自定義異常:在開發(fā)中,開發(fā)人員對某些可能出現(xiàn)的情形是可以預(yù)知的,這時(shí)候是一種主動處理的狀態(tài)。
開發(fā)人員無法預(yù)測的系統(tǒng)異常:在開發(fā)中,存在著開發(fā)人員無法全面思考到的異常,那么這時(shí)候就是一種潛在性的可能異常狀態(tài)。
前端和后臺交互異常:由于前后端的分離,而且前后端的開發(fā)方向也存在著差異,那么就有可能導(dǎo)致異常的出現(xiàn)。
開發(fā)環(huán)境
windows 7 + 渣渣筆記本
IDEA + SpringBoot + Mybatis +Mysql
開發(fā)步驟
創(chuàng)建自定義異常
分析:在系統(tǒng)中,存在著系統(tǒng)異常和我們?nèi)藶榈淖远x異常,所以,為了能夠有效的針對不同異常進(jìn)行處理,那么擁有我們自定義的異常類是非常有必要的。
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:自定義異常,為了區(qū)分系統(tǒng)異常和更方便系統(tǒng)的特定一些處理 *@ Modified By: *@Version:1 */ publicclassMyExceptionextendsRuntimeException{ //錯(cuò)誤碼 privateIntegercode; publicIntegergetCode(){ returncode; } publicvoidsetCode(Integercode){ this.code=code; } publicMyException(Stringmessage){ super(message); } /** *構(gòu)造器重載,主要是自己考慮某些異常自定義一些返回碼 *@paramcode *@parammessage */ publicMyException(Integercode,Stringmessage){ super(message); this.code=code; } }
創(chuàng)建消息返回的包裝實(shí)體
分析:對于后臺返回給前端的數(shù)據(jù)來說,我們很多情況都是返回的JSON格式的數(shù)據(jù)(當(dāng)然,并不是局限于這一種),那么JSON是一種格式化的形式。
所以,我們應(yīng)該有效的針對這樣的形式來給予一定的返回規(guī)范,這樣也方便前端對于我們返回?cái)?shù)據(jù)的解析。
比如:很多情況一般是如下的格式:
{
"retCode":200,//通過狀態(tài)碼可以得到消息是否返回正常,然后再決定是否去解析data域的內(nèi)容
"data":{//返回的數(shù)據(jù)內(nèi)容
}
"retMes":success//返回的提示內(nèi)容
}
所以,我們可以定義如下的類:
packagecom.hnu.csapp.exception; /** *@ Author :scw *@ Description:異常處理實(shí)體包裝類,自己用泛型進(jìn)行寫,擴(kuò)展性強(qiáng)點(diǎn) *@ Modified By: *@Version:1 */ publicclassResult{ //返回碼 privateIntegercode; //返回消息 privateStringmsg; //返回?cái)?shù)據(jù) privateTdata; publicIntegergetCode(){ returncode; } publicvoidsetCode(Integercode){ this.code=code; } publicStringgetMsg(){ returnmsg; } publicvoidsetMsg(Stringmsg){ this.msg=msg; } publicTgetData(){ returndata; } publicvoidsetData(Tdata){ this.data=data; } }
定義一系列的枚舉返回信息
分析:在系統(tǒng)中,我們應(yīng)該有統(tǒng)一的某些編碼對應(yīng)某些內(nèi)容,這樣能夠方便開發(fā)人員進(jìn)行及時(shí)的處理。
packagecom.hnu.csapp.exception;
/**
*@ Author :scw
*@ Description:自定義一些返回狀態(tài)碼,便于本系統(tǒng)的使用,自己先定義如下的,有需要就后續(xù)補(bǔ)充
*@ Modified By:
*@Version:1
*/
publicenumResultEnum{
/**
*成功.:200(因?yàn)閔ttp中的狀態(tài)碼200一般都是表示成功)
*/
SUCCESS(200,"成功"),
/**
*系統(tǒng)異常.ErrorCode:-1
*/
SystemException(-1,"系統(tǒng)異常"),
/**
*未知異常.ErrorCode:01
*/
UnknownException(01,"未知異常"),
/**
*服務(wù)異常.ErrorCode:02
*/
ServiceException(02,"服務(wù)異常"),
/**
*業(yè)務(wù)錯(cuò)誤.ErrorCode:03
*/
MyException(03,"業(yè)務(wù)錯(cuò)誤"),
/**
*提示級錯(cuò)誤.ErrorCode:04
*/
InfoException(04,"提示級錯(cuò)誤"),
/**
*數(shù)據(jù)庫操作異常.ErrorCode:05
*/
DBException(05,"數(shù)據(jù)庫操作異常"),
/**
*參數(shù)驗(yàn)證錯(cuò)誤.ErrorCode:06
*/
ParamException(06,"參數(shù)驗(yàn)證錯(cuò)誤");
privateIntegercode;
privateStringmsg;
ResultEnum(Integercode,Stringmsg){
this.code=code;
this.msg=msg;
}
publicIntegergetCode(){
returncode;
}
publicStringgetMsg(){
returnmsg;
}
}
定義消息返回工具類
分析:對于消息的返回,這是一個(gè)非常普通的工作,所以,我們可以將其封裝一個(gè)工具類,能夠進(jìn)行有效代碼的封裝,減少多余的代碼
packagecom.hnu.csapp.exception;
/**
*@ Author :scw
*@ Description:返回消息處理的工具類,主要是處理操作成功和失敗的一些內(nèi)容
*@ Modified By:
*@Version:1
*/
publicclassResultUtil{
/**
*操作成功的處理流程
*@paramobject
*@return
*/
publicstaticResultgetSuccess(Objectobject){
Resultresult=newResult();
//設(shè)置操作成功的返回碼
result.setCode(200);
//設(shè)置操作成功的消息
result.setMsg("成功");
result.setData(object);
returnresult;
}
/**
*重載返回成功的方法,因?yàn)橛袝r(shí)候我們不需要任何的消息數(shù)據(jù)被返回
*@return
*/
publicstaticResultgetSuccess(){
returngetSuccess(null);
}
/**
*操作失敗的處理流程
*@paramcode錯(cuò)誤碼
*@parammsg錯(cuò)誤消息
*@paramo錯(cuò)誤數(shù)據(jù)(其實(shí)這個(gè)一般都不需要的,因?yàn)槎家呀?jīng)返回失敗了,數(shù)據(jù)都沒必要返回)
*@return
*/
publicstaticResultgetError(Integercode,Stringmsg,Objecto){
Resultresult=newResult();
result.setCode(code);
result.setMsg(msg);
result.setData(o);
returnresult;
}
/**
*重載,操作失敗的方法(因?yàn)椴僮魇∫话愣疾恍枰祷財(cái)?shù)據(jù)內(nèi)容)
*@paramcode
*@parammsg
*@return
*/
publicstaticResultgetError(Integercode,Stringmsg){
returngetError(code,msg,null);
}
}
定義異常統(tǒng)一處理類(重點(diǎn))
分析:這是如何實(shí)現(xiàn)異常統(tǒng)一處理的關(guān)鍵地方,而且我也將不同的處理情形,進(jìn)行了分開注釋,所以,大家一定可以認(rèn)真的看代碼,我相信你一定能夠明白。
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:異常統(tǒng)一處理類,方便用戶可以更加友好的看到錯(cuò)誤信息 *@ Modified By: *@Version:1 */ @ControllerAdvice publicclassExceptionHandle{ //增加異常日志打印 privatefinalstaticLoggerlogger=LoggerFactory.getLogger(ExceptionHandle.class); //設(shè)置異常錯(cuò)誤的頁面 publicstaticfinalStringDEFAULT_ERROR_VIEW="error"; /** *以json的格式進(jìn)行返回內(nèi)容(開發(fā)環(huán)境一般個(gè)人是用這個(gè)比較好) *@parame *@return */ @ExceptionHandler(Exception.class) @ResponseBody publicObjecthandle(HttpServletRequestreq,Exceptione){ //如果是自定義的異常 if(einstanceofMyException){ MyExceptionmyException=(MyException)e; returnResultUtil.getError(myException.getCode(),myException.getMessage()); }else{ //如果是系統(tǒng)的異常,比如空指針這些異常 logger.error("【系統(tǒng)異?!?{}",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())); } /* //備注: //這個(gè)是正式項(xiàng)目完成之后的錯(cuò)誤統(tǒng)一處理(開發(fā)情況先用上面的的) //我們在開發(fā)過程中還是用json格式的會好一些,要不然看錯(cuò)誤麻煩 @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{ //如果是系統(tǒng)的異常,比如空指針這些異常 logger.error("【系統(tǒng)異?!?{}",e); returnResultUtil.getError(ResultEnum.SystemException.getCode(),ResultEnum.SystemException.getMsg()); } }else{ //如果是系統(tǒng)內(nèi)部發(fā)生異常,那么就返回到錯(cuò)誤頁面進(jìn)行友好的提示 ModelAndViewmav=newModelAndView(); //這些就是要返回到頁面的內(nèi)容(其實(shí)不用都行,反正用戶也不懂,沒必要在頁面顯示都可以,先寫著吧) mav.addObject("exception",e); mav.addObject("url",req.getRequestURL()); mav.setViewName(DEFAULT_ERROR_VIEW); returnmav; } } */ }
定義異常處理頁面
分析:這個(gè)的話,其實(shí)主要是在正式環(huán)境才有,因?yàn)槲覀冊跍y試環(huán)境的時(shí)候,一般都還是會將錯(cuò)誤以JSON或者堆棧的格式顯示在頁面,而當(dāng)上線的時(shí)候,那么就一定要有一個(gè)統(tǒng)一的錯(cuò)誤頁面,這樣就能夠讓用戶發(fā)現(xiàn)不了是系統(tǒng)出現(xiàn)了哪些問題。
效果
開發(fā)環(huán)境

正式環(huán)境
分析:當(dāng)出現(xiàn)異常的時(shí)候,則顯示如下的頁面。(該頁面是參考一個(gè)博友的,感覺挺有意思,,老司機(jī)~)
總結(jié)
異常統(tǒng)一處理,或許我們看起來實(shí)現(xiàn)非常簡單,然而,其他它包含的思想?yún)s是一種大局思想,這是我們開發(fā)人員在開發(fā)過程中都應(yīng)該關(guān)注的點(diǎn),我們并不是只需要關(guān)注我們每個(gè)人開發(fā)的那點(diǎn)任務(wù),而要以一種全局的角度去審視整個(gè)項(xiàng)目,這樣也能夠提升我們開問題的高度。
異常統(tǒng)一處理,是每個(gè)項(xiàng)目都存在的,只是可能實(shí)現(xiàn)的方式不一樣而已,或者顯示的效果不一樣而已,這些都不是關(guān)鍵的地方。
異常統(tǒng)一處理這個(gè)問題,并不是很難,但是這個(gè)可以幫助我們延伸到其他的一些相關(guān)的開發(fā)層面的知識,比如:
登錄攔截
權(quán)限管理
日志管理
事務(wù)處理
數(shù)據(jù)控制和過濾
。。。
所以,我們應(yīng)該學(xué)會從一個(gè)問題,發(fā)散的看到相關(guān)類似的問題,這樣,我們的系統(tǒng)才會更加健壯,高效和可擴(kuò)展性強(qiáng)。
-
Web
+關(guān)注
關(guān)注
2文章
1302瀏覽量
73750 -
服務(wù)器
+關(guān)注
關(guān)注
13文章
10117瀏覽量
91035 -
開發(fā)環(huán)境
+關(guān)注
關(guān)注
1文章
254瀏覽量
17562
原文標(biāo)題:減少 try-catch ,這樣做才叫優(yōu)雅!
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
有承接開發(fā)項(xiàng)目的嗎?
項(xiàng)目的創(chuàng)建及虛擬環(huán)境的配置
構(gòu)建Python開發(fā)環(huán)境的方法
本地搭建Python Web的開發(fā)測試環(huán)境過程詳解
創(chuàng)建 Web 前端開發(fā)環(huán)境
電子商務(wù)項(xiàng)目的實(shí)施與相關(guān)環(huán)境資料說明
初學(xué)Java Web開發(fā)應(yīng)該如何學(xué)習(xí)
Web項(xiàng)目的最佳平臺選擇
AIoT項(xiàng)目的設(shè)計(jì)/開發(fā)/運(yùn)營之6大步驟和3大關(guān)鍵環(huán)節(jié)

Web項(xiàng)目的開發(fā)環(huán)境及步驟
評論