在spring中優(yōu)雅地處理異常

@ExceptionHandler

使用@ExceptionHandler注解可以在攔截當前類中方法拋出的異常,如下面例子中

@RestController
@RequestMapping("/user")
public class UserController {


    @GetMapping("/throwException")
    public String throwException(){
        //拋出一個異常
        int a = 1/0;
        return "abcd";
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String handleException(){
        return "handle";
    }
}

使用get請求中訪問 localhost:8080/user/throwException可以得到如下信息

handle

@ControllerAdvice

看了上面的例子诚些,我們會想 假如有多個controller都會拋出異常飞傀,難道要在每個controller中都寫一個這樣的方法進行異常捕獲嗎?可不可以將ExceptionHandler配置成全局的異常捕獲诬烹,方法很簡單只需要新建一個類在上面添加@ControllerAdvice注解然后將異常攔截方法添加到其中即可

@ControllerAdvice
public class ExceptionHandleAdvice {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String handleException(){
        return "global handle";
    }

}

使用全局異常處理返回統(tǒng)一的錯誤信息

在日常工作中開發(fā)API的時候往往需要返回詳細統(tǒng)一的錯誤信息給前端小伙伴方便前端進行錯誤信息的處理和展示(當然你也可以一個接口一個格式砸烦,不怕被打的話( ̄ ̄"))。在這樣的情況如何優(yōu)雅得進行異常處理就變得很重要了绞吁。一下是個人對異常處理的一些意見幢痘,分享給小伙伴參考,有不同意見的小伙伴可以交流家破。

通常我們會通過code表示具體的錯誤類型颜说、message給出錯誤的信息购岗。因此我們可以得到以及基本的錯誤信息模板如下方

{
    "code": 404,
    "message": "No message available",
    "path": "/u",
    "timestamp": "2020-02-17T14:20:48.049+0000",
}

定義錯誤信息枚舉

將錯誤信息定義成枚舉可以幫助我們管理code避免相同的錯誤返回不一樣的code值或者不同的錯誤返回了同一個code门粪。

public enum ErrorEnum {

    USER_NOT_FOUND_ERROR(1000,"用戶不存在");

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

定義返回錯誤信息實體類

public class ErrorResponse {

    private int code;

    private String message;

    private LocalDateTime timestamp;

    private String path;

    public ErrorResponse() {
    }
    
    //利用一個靜態(tài)工廠方法快速創(chuàng)建實例
    public static ErrorResponse build(ErrorEnum errorEnum,String path){
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode(errorEnum.getCode());
        errorResponse.setMessage(errorEnum.getMessage());
        errorResponse.setPath(path);
        errorResponse.setTimestamp(LocalDateTime.now());
        return errorResponse;
    }
}

創(chuàng)建基礎異常類

創(chuàng)建一個基礎的異常喊积,讓我們的全局ExceptionHandler攔截這個異常。

public abstract class BaseException extends RuntimeException {

    private ErrorEnum error;
    
    public BaseException(ErrorEnum error) {
        this.error = error;
    }

    public ErrorEnum getError() {
        return error;
    }

    public void setError(ErrorEnum error) {
        this.error = error;
    }
}

創(chuàng)建ControllerAdvice

使用@ControllerAdvice創(chuàng)建全局異常攔截器并攔截我們上面定義好的基礎異常類玄妈,在方法內部進行錯誤信息的返回乾吻。

@ControllerAdvice
public class ExceptionHandleAdvice {

    @ExceptionHandler(value = BaseException.class)
    //以寫入到response的body方式返回
    @ResponseBody
    public ErrorResponse handleException(BaseException e, HttpServletRequest request){
        return ErrorResponse.build(e.getError(),request.getRequestURI());
    }

}

使用

在完成了上面的工作之后,終于到了我們使用的時候拟蜻,在我們使用的時候我們通常都會拋出更加具體的異常绎签、下面我們以獲取用戶信息為例子,當查找不到用戶的時候我們會拋出UserNotFoundException

public class UserNotFoundException extends BaseException {

    public UserNotFoundException() {
        super(ErrorEnum.USER_NOT_FOUND_ERROR);
    }
}
@RestController
@RequestMapping("/user")
public class UserController {

    private UserDAO userDAO;

    public UserController(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @GetMapping("/{userId}")
    public User getUserById(@PathVariable("userId") String userId) {
        User user = this.userDAO.getUserById(userId);
        if (user == null) {
            throw new UserNotFoundException();
        }
        return user;
    }
    
}

快打開你的瀏覽器輸入熟悉的localhost:8080/user/123457酝锅,然后

{
    "code": 1000,
    "message": "用戶不存在",
    "timestamp": "2020-02-17T23:03:46.6924162",
    "path": "/user/1234567"
}

以后我們只需要創(chuàng)建和拋出BaseException的子類就可以完成對異常信息的統(tǒng)一格式返回诡必,再也不用擔心被前端小伙伴打了。

最后

以上的代碼只是個人的一種實現屈张,有所不足請小伙伴們給出建議擒权。

如果對你有一點幫助給個start鼓勵一下唄(′?ω?`)。

demo源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末阁谆,一起剝皮案震驚了整個濱河市碳抄,隨后出現的幾起案子,更是在濱河造成了極大的恐慌场绿,老刑警劉巖剖效,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逼蒙,死亡現場離奇詭異畴博,居然都是意外死亡吮铭,警方通過查閱死者的電腦和手機喘鸟,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矗愧,“玉大人柱徙,你說我怎么就攤上這事席怪∨焖冢” “怎么了蛀序?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長活烙。 經常有香客問我徐裸,道長,這世上最難降的妖魔是什么啸盏? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任重贺,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘气笙。我一直安慰自己次企,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布健民。 她就那樣靜靜地躺著抒巢,像睡著了一般贫贝。 火紅的嫁衣襯著肌膚如雪秉犹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天稚晚,我揣著相機與錄音崇堵,去河邊找鬼。 笑死客燕,一個胖子當著我的面吹牛鸳劳,可吹牛的內容都是我干的。 我是一名探鬼主播也搓,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赏廓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傍妒?” 一聲冷哼從身側響起幔摸,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颤练,沒想到半個月后既忆,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡嗦玖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年患雇,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇挫。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡苛吱,死狀恐怖,靈堂內的尸體忽然破棺而出器瘪,到底是詐尸還是另有隱情翠储,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布娱局,位于F島的核電站彰亥,受9級特大地震影響,放射性物質發(fā)生泄漏衰齐。R本人自食惡果不足惜任斋,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧废酷,春花似錦瘟檩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趴俘,卻和暖如春睹簇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寥闪。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工太惠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疲憋。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓凿渊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缚柳。 傳聞我的和親對象是個殘疾皇子埃脏,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容