項(xiàng)目中出現(xiàn)異常怎么辦饺律?是時(shí)候?qū)W會(huì)SpringBoot全局異常處理

前言

  1. 我們?nèi)粘5拈_發(fā)中,不管是對(duì)底層數(shù)據(jù)庫操作跺株,還是業(yè)務(wù)層或控制層操作复濒,都會(huì)不可避免地遇到各種可預(yù)知的、不可預(yù)知的異常需要處理乒省。
  2. 如果每個(gè)過程都單獨(dú)處理異常巧颈,那么系統(tǒng)的代碼耦合度高,工作量大且不好統(tǒng)一袖扛,以后維護(hù)的工作量也很大砸泛。
  3. 如果能將所有類型的異常處理從各層中解耦出來十籍,這樣既保證了相關(guān)處理過程的功能單一,又實(shí)現(xiàn)了異常信息的統(tǒng)一處理和維護(hù)唇礁。

上面闡述的問題勾栗,我們?cè)谑褂肧pringBoot之后都能解決,我們可以使用如下3種方式處理異常:

  1. 使用@ExceptionHandler注解
  2. 實(shí)現(xiàn)HandlerExceptionResolver接口
  3. 使用@ControllerAdvice注解+@ExceptionHandler注解

1. 使用@ExceptionHandler注解

假設(shè)前端發(fā)送請(qǐng)求后端盏筐,然后后端處理的時(shí)候發(fā)生異常围俘,這時(shí)可以有三種方式通知前端:

  1. 返回異常頁面(不包含錯(cuò)誤信息)。下面返回"exception"為異常視圖名稱(我們自己編寫的異常頁面)琢融。
@Controller
public class ExceptionHandlerController {

    @ExceptionHandler(RuntimeException.class)
    public String exception(Exception e){
        e.printStackTrace();
        return "exception";
    }

    @RequestMapping("/exception")
    public void exception(){
        int i = 5/0;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>exception</title>
</head>
<body>
    正在處理中界牡,請(qǐng)稍等...
</body>
</html>
  1. 返回ModelAndView。既返回視圖漾抬,也返回異常信息宿亡。
@ExceptionHandler(RuntimeException.class)
public ModelAndView exception(RuntimeException e){
    ModelAndView mv = new ModelAndView();
    mv.addObject("msg",e.getMessage());
    mv.setViewName("/exception");
    e.printStackTrace();
    return mv;
}

@RequestMapping("/exception")
public void exception(){
    int i = 5/0;
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>exception</title>
</head>
<body>
    <div th:text="${msg}">正在處理中,請(qǐng)稍等...</div>
</body>
</html>

在上面我們把異常信息存儲(chǔ)在Model纳令,然后在異常頁面顯示異常信息挽荠。


在這里插入圖片描述
  1. 返回JSON格式數(shù)據(jù)。在前后端分離的情況下泊碑,大多都是返回JSON格式數(shù)據(jù)坤按,這里我們規(guī)定如果出現(xiàn)異常,也返回JSON格式數(shù)據(jù)馒过。
    響應(yīng)實(shí)體類
@Data
public class MyResponse<T> {
    private Long statusCode;    //響應(yīng)狀態(tài)碼
    private T data; //響應(yīng)數(shù)據(jù)
}
@ExceptionHandler(RuntimeException.class)
//表示返回JSON格式數(shù)據(jù)
@ResponseBody
public MyResponse<String> exception(RuntimeException e){
    //在控制臺(tái)打印
    e.printStackTrace();
    MyResponse<String> response = new MyResponse();
    //出現(xiàn)的異常都返回500狀態(tài)碼
    response.setStatusCode(500);
    response.setData(e.getMessage());
    return response;
}

@RequestMapping("/exception")
public void exception(){
    int i = 5/0;
}

這樣我們?cè)诎l(fā)生異常的時(shí)候臭脓,也能返回JSON數(shù)據(jù)了。

在這里插入圖片描述

注意點(diǎn)

  1. 使用@ExceptionHandler注解有一個(gè)不好的地方就是:進(jìn)行異常處理的方法必須與出錯(cuò)的方法在同一個(gè)Controller里面腹忽。
  2. 這種方式不能實(shí)現(xiàn)全局異常處理来累。

2.實(shí)現(xiàn)HandlerExceptionResolver接口

  1. 這種方式可以實(shí)現(xiàn)全局的異常控制窘奏,只要在系統(tǒng)運(yùn)行中發(fā)生異常嘹锁,它都會(huì)捕獲到。
  2. 實(shí)現(xiàn)該接口着裹,必須重寫resolveException方法领猾,該方法就是異常處理邏輯,只能返回ModelAndView 對(duì)象骇扇。
@Component
public class MyGlobalException implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg",e.getMessage());
        mv.setViewName("/exception");
        e.printStackTrace();
        return mv;
    }
}

3.使用@ControllerAdvice注解+@ExceptionHandler注解

  1. 上面說到@ExceptionHandler需要進(jìn)行異常處理的方法必須與出錯(cuò)的方法在同一個(gè)Controller里面摔竿。那么當(dāng)代碼加入了 @ControllerAdvice,則不需要必須在同一個(gè)controller中了少孝。
  2. 從名字上可以看出大體意思是控制器增強(qiáng)继低。 也就是說,@controlleradvice+@ExceptionHandler也可以實(shí)現(xiàn)全局的異常捕捉稍走。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExceptionResponse<T> {
    private T data;
}
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandle {

    /**
     *  捕獲404異常
     * @return
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public ExceptionResponse notFoundException(NoHandlerFoundException e){
        log.error("資源未找到",e);
        return new ExceptionResponse<>("你好袁翁,你要的資源找不到柴底!");
    }

    /**
     * 400——Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
     public ExceptionResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException  e) {
        log.error("參數(shù)解析失敗", e);
        return new ExceptionResponse<>("bad request");
    }

    /**
     *  405——Method Not Allowed
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ExceptionResponse<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException  e){
        log.error("不支持當(dāng)前請(qǐng)求方法",e);
        return new ExceptionResponse<>("request_method_not_supported");
    }

    /**
     * 415——Unsupported Media Type
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ExceptionResponse handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e){
        log.error("不支持當(dāng)前媒體",e);
        return new ExceptionResponse("content_type_not_supported");
    }

    /**
     * 500:服務(wù)器內(nèi)部異常
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler
    public ExceptionResponse internalServerError(Exception e){
        log.error("服務(wù)器內(nèi)部異常",e);
        return new ExceptionResponse("你好,請(qǐng)稍等會(huì)...");
    }
}
  1. 在上面代碼中粱胜,定義了捕獲各種異常處理方法柄驻,不同的類型異常由不同的異常處理方法進(jìn)行處理。
  2. 需要注意一點(diǎn)年柠,就是SpringBoot默認(rèn)不支持捕獲404異常凿歼,需要添加下面兩行配置才能使捕獲404異常生效。
#出現(xiàn)錯(cuò)誤時(shí), 直接拋出異常
spring.mvc.throw-exception-if-no-handler-found=true
#不要為我們工程中的資源文件建立映射
spring.resources.add-mappings=false

測(cè)試404異常以及500異常

  1. 在瀏覽器中輸入:http://localhost:8888/exception/404exception冗恨,就會(huì)報(bào)404異常答憔,由上面定義的異常處理方法捕獲
    在這里插入圖片描述
  2. 在瀏覽器輸入:http://localhost:8888/exception,就會(huì)報(bào)500異常掀抹,也是由上面定義的異常處理方法捕獲
    在這里插入圖片描述

上面我們是具體的異常類型分別定義異常捕獲方法虐拓,我們也可以不那樣做,不區(qū)分類型捕獲全部異常

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler
    @ResponseBody
    String globalHandleException(Exception e){
        return "Exception Deal! " + e.getMessage();
    }
}

上面的全局異常處理方法我們都是返回JSON數(shù)據(jù)傲武。我們只需要把方法返回值修改為ModelAndView蓉驹,也能返回視圖域與模型數(shù)據(jù)了。
這樣介紹完了SpringBoot全局異常處理機(jī)制揪利,上面所說的幾乎包含了開發(fā)中常見的異常處理方式态兴。
如果大家覺得不錯(cuò)的話,可以??或者關(guān)注一下博主我疟位。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞻润,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子甜刻,更是在濱河造成了極大的恐慌绍撞,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件得院,死亡現(xiàn)場(chǎng)離奇詭異傻铣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祥绞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門非洲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜕径,你說我怎么就攤上這事怪蔑。” “怎么了丧荐?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)喧枷。 經(jīng)常有香客問我虹统,道長(zhǎng)弓坞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任车荔,我火速辦了婚禮渡冻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忧便。我一直安慰自己族吻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布珠增。 她就那樣靜靜地躺著超歌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蒂教。 梳的紋絲不亂的頭發(fā)上巍举,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音凝垛,去河邊找鬼懊悯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梦皮,可吹牛的內(nèi)容都是我干的炭分。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼剑肯,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼捧毛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起退子,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤岖妄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后寂祥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荐虐,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年丸凭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了福扬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惜犀,死狀恐怖铛碑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虽界,我是刑警寧澤汽烦,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站莉御,受9級(jí)特大地震影響撇吞,放射性物質(zhì)發(fā)生泄漏俗冻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一牍颈、第九天 我趴在偏房一處隱蔽的房頂上張望迄薄。 院中可真熱鬧,春花似錦煮岁、人聲如沸讥蔽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冶伞。三九已至,卻和暖如春色罚,著一層夾襖步出監(jiān)牢的瞬間碰缔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工戳护, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留金抡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓腌且,卻偏偏與公主長(zhǎng)得像梗肝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铺董,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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

  • 前言 今天來一起學(xué)習(xí)一下Spring Boot中的異常處理巫击,在日常web開發(fā)中發(fā)生了異常,往往是需要通過一個(gè)統(tǒng)一的...
    嘟爺MD閱讀 25,878評(píng)論 8 79
  • PS: 本文講得比較細(xì)精续,所以篇幅較長(zhǎng)坝锰。 閱讀時(shí)間:30m~1h。請(qǐng)認(rèn)真讀完重付,希望你一小時(shí)后能對(duì)統(tǒng)一異常處理有一個(gè)清...
    sprainkle閱讀 19,351評(píng)論 21 157
  • 假如能看到別人的“死亡時(shí)間”确垫,要不要告訴TA們弓颈。本期《奇葩說》的辯題,是我從看第五季以來最想說的一個(gè)話題删掀,最想說最...
    間歇性渴望癥患者閱讀 544評(píng)論 0 1
  • 梁以熏和姐姐的復(fù)雜心臟病必然性的死亡翔冀,在愛的存在下,奇跡也不可能發(fā)生了披泪,最后一個(gè)滅亡的殘酷纤子,命運(yùn)似乎已經(jīng)注了腳。 ...
    苔絲威閱讀 384評(píng)論 0 0
  • 我現(xiàn)在還在周口老家的農(nóng)村跌捆,沒有也沒辦法回鄭州。 正好也給忙碌的人生一個(gè)小憩象颖。 據(jù)說出去也是高速不讓上,意思不讓出去...
    朱團(tuán)輝閱讀 396評(píng)論 0 4