Spring Boot 異常處理

七夕佳節(jié)

前言

先談?wù)劇爱惓L幚怼边@件事。下面有 2 份偽代碼奠骄,對(duì)比下:

// ① 基于 if/else 判斷
if(deletePage(page) == E_OK){
  if(registry.deleteReference(page.name) == E_OK){
    if(configKeys.deleteKey(page.name.makeKey()) == E_OK){
      logger.log("page deleted");
    }else{
      logger.log("configKey not deleted");
    }
  }else{
    logger.log("deleteReference from registry failed");
  }
}else{
  logger.log("delete failed");
  return E_RROR;
}
// ② 基于異常處理
try{
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}catch(Exception e){
  logError(e);
}

可以看出,如果使用異常替代返回錯(cuò)誤碼番刊,錯(cuò)誤處理代碼就能從主路徑邏輯中分離出來(lái)含鳞,得到簡(jiǎn)化!

②中撵枢,基于異常處理的代碼真的好嗎民晒?其實(shí)是丑陋不堪的,它搞亂了代碼結(jié)構(gòu)锄禽,把錯(cuò)誤處理與正常流程混為一談潜必。最好把 try 和 catch 代碼塊的主體部分抽離出來(lái),形成另外的函數(shù)沃但。

// ③ 優(yōu)雅的異常處理邏輯
public void delete(Page page){
  try{
    deletePageAndAllReferences(page);
  }catch(Exception e){
    logError(e);
  }
}

private void deletePageAndAllReferences(Page page) throw Exception{
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}

private void logError(Exception e){
  logger.log(e.getMessage());
}

③中磁滚,函數(shù)各司其職,更易于理解和修改了宵晚。

總結(jié):使用異常而不是錯(cuò)誤碼垂攘,優(yōu)雅地使用異常!函數(shù)應(yīng)該只做一件事淤刃,處理錯(cuò)誤就是一件事晒他。因此,處理錯(cuò)誤的函數(shù)不該做其他事逸贾!

在 Spring Boot 中處理異常

1陨仅、默認(rèn)的異常處理

例如 401,404铝侵,500灼伤,5XX 等異常,Spring Boot 默認(rèn)會(huì)跳轉(zhuǎn)到預(yù)配置的頁(yè)面咪鲜,此處以 thymeleaf 模板引擎為例:

+ resources
  + templates
    + error
      - 401.html
      - 404.html
      - 500.html

只需在 resources/templates/error/ 路徑下添加對(duì)應(yīng)的html文件即可狐赡。

2、局部異常處理

局部異常一般處理業(yè)務(wù)邏輯出現(xiàn)的異常情況疟丙,在 Controller 下使用 @ExceptionHandler 注解來(lái)處理異常颖侄。舉個(gè)小例子:

先定義 ResponseBean 和 ExceptionEnum 兩個(gè)對(duì)象,輔助完成優(yōu)雅的代碼隆敢。

/**
 * 統(tǒng)一響應(yīng)
 * @author anoy
 */
public class ResponseBean<T> {

    private int code;

    private String message;

    private T data;

    public ResponseBean(){}

    public ResponseBean(ExceptionEnum exceptionEnum){
        this.code = exceptionEnum.getCode();
        this.message = exceptionEnum.getMessage();
    }

    // 省略 setter/getter
}
/**
 * 異常類型枚舉
 * @author anoy
 */
public enum ExceptionEnum {

    GIRL_FRIEND_NOT_FOUND(100000, "girl friend not found");

    private int code;

    private String message;

    ExceptionEnum(int code, String message){
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

今天七夕发皿,寫個(gè) GirlFriendNotFoundException(很有同感,是不是拂蝎?)

@Controller
public class UserController {

    @RequestMapping("/friend/{id}")
    public String friend(@PathVariable("id") Long id) throws GirlFriendNotFoundException {
        if (id == 1L){
            throw new GirlFriendNotFoundException();
        }
        return "friend";
    }

    @ExceptionHandler(GirlFriendNotFoundException.class)
    @ResponseBody
    public ResponseBean handleGirlFriendNotFound(GirlFriendNotFoundException exception){
        loggerError(exception);
        return new ResponseBean(ExceptionEnum.GIRL_FRIEND_NOT_FOUND);
    }
    
    private void logError(Exception e){
        logger.error(e.getMessage());
    }
}

3穴墅、全局異常處理

個(gè)人觀點(diǎn):全局異常應(yīng)該處理系統(tǒng)故障級(jí)別的問題,像參數(shù)校驗(yàn)這種類型的異常温自,應(yīng)該作為局部異常來(lái)處理玄货,例如 Redis 連接斷開,無(wú)法請(qǐng)求數(shù)據(jù)悼泌,這種異常就應(yīng)該當(dāng)做全局異常來(lái)處理松捉,在異常處理的邏輯中,還應(yīng)該添加通知到開發(fā)人員的功能馆里,方便開發(fā)人員及時(shí)處理錯(cuò)誤隘世!

全局異常處理可柿,使用 @ControllerAdvice@ExceptionHandler 來(lái)配合。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RedisConnectionFailureException.class)
    public void handlerRedisConnectionFailureException(RedisConnectionFailureException exception){
        logError(exception);
        noticeToDev();
    }

    private void logError(Exception e){
        logger.error(e.getMessage());
    }

    private void noticeToDev(){
        // 通知具體開發(fā)人員
    }

}

常見問題

1丙者、局部異常和全局異常處理同一種類型的 Exception复斥,會(huì)發(fā)生什么結(jié)果?
答:只會(huì)執(zhí)行局部異常的處理邏輯械媒!

2目锭、GirlFriendNotFoundException 繼承了 RuntimeException, 使用
@ExceptionHandler(RuntimeException.class) 能處理異常嗎纷捞?
答:可以的痢虹!所以對(duì)于局部比較公用的異常可以定義一個(gè)父類主儡,拋出異常時(shí)可以拋出具體的子類異常奖唯,處理時(shí),處理父類異常即可(即只用寫一個(gè)方法處理一系列類似的異常)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缀辩,一起剝皮案震驚了整個(gè)濱河市臭埋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臀玄,老刑警劉巖瓢阴,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異健无,居然都是意外死亡荣恐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門累贤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叠穆,“玉大人,你說(shuō)我怎么就攤上這事臼膏∨鸨唬” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵渗磅,是天一觀的道長(zhǎng)嚷硫。 經(jīng)常有香客問我,道長(zhǎng)始鱼,這世上最難降的妖魔是什么仔掸? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮医清,結(jié)果婚禮上起暮,老公的妹妹穿的比我還像新娘。我一直安慰自己会烙,他們只是感情好负懦,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布筒捺。 她就那樣靜靜地躺著,像睡著了一般纸厉。 火紅的嫁衣襯著肌膚如雪焙矛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天残腌,我揣著相機(jī)與錄音,去河邊找鬼贫导。 笑死抛猫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的孩灯。 我是一名探鬼主播闺金,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼峰档!你這毒婦竟也來(lái)了败匹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤讥巡,失蹤者是張志新(化名)和其女友劉穎掀亩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欢顷,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡槽棍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抬驴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炼七。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖布持,靈堂內(nèi)的尸體忽然破棺而出豌拙,到底是詐尸還是另有隱情,我是刑警寧澤题暖,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布按傅,位于F島的核電站,受9級(jí)特大地震影響芙委,放射性物質(zhì)發(fā)生泄漏逞敷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一灌侣、第九天 我趴在偏房一處隱蔽的房頂上張望推捐。 院中可真熱鬧,春花似錦侧啼、人聲如沸牛柒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)皮壁。三九已至椭更,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛾魄,已是汗流浹背虑瀑。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滴须,地道東北人舌狗。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扔水,于是被迫代替她去往敵國(guó)和親痛侍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 第一部分 打好基礎(chǔ) Laying the Foundation 第一章 歡迎進(jìn)入軟件構(gòu)建的世界 Welcome t...
    白樺葉閱讀 4,600評(píng)論 0 17
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法魔市,類相關(guān)的語(yǔ)法主届,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法待德,異常的語(yǔ)法君丁,線程的語(yǔ)...
    子非魚_t_閱讀 31,587評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit将宪,java的開發(fā)和運(yùn)行環(huán)境谈截,java的開發(fā)工...
    ZaneInTheSun閱讀 2,629評(píng)論 0 11
  • 從前,有一個(gè)小男孩名叫安迪涧偷。他住在一個(gè)很漂亮的房子里簸喂。安迪的爸爸和媽媽都很富有,他的爸爸是當(dāng)律師的燎潮,他的媽媽開了一...
    后翼張景源閱讀 439評(píng)論 1 3
  • 我這前十多天在上海喻鳄,就是在忙淘寶造物節(jié),盒而特(設(shè)計(jì)生產(chǎn)可改造的快遞盒子的社會(huì)企業(yè)确封,我是盒而特的創(chuàng)意設(shè)計(jì)顧問)被青...
    v偉偉v閱讀 1,647評(píng)論 2 51