亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring中的@ControllerAdvice和@ExceptionHandler注解處理全局異常

 更新時(shí)間:2024年01月09日 09:23:19   作者:Java架構(gòu)何哥  
這篇文章主要介紹了Spring中的@ControllerAdvice和@ExceptionHandler注解處理全局異常,@ControllerAdvice ,@ControllerAdvice是一個(gè)非常有用的注解,顧名思義,這是一個(gè)增強(qiáng)的 Controller,一般配合@ExceptionHandler使用來(lái)處理全局異常,需要的朋友可以參考下

前言

開發(fā)過(guò)程中,難免有的程序會(huì)因?yàn)槟承┰驋伋霎惓?,而這些異常一般都是利用try ,catch的方式處理異?;蛘遲hrow,throws的方式拋出異常不管。

這種方法對(duì)于程序員來(lái)說(shuō)處理也比較麻煩,對(duì)客戶來(lái)說(shuō)也不太友好,所以我們希望既能方便程序員編寫代碼,不用過(guò)多的自己去處理各種異常編寫重復(fù)的代碼又能提升用戶的體驗(yàn),這時(shí)候全局異常處理就顯得很重要也很便捷了。

一、@ControllerAdvice和@ExceptionHandler簡(jiǎn)介

在構(gòu)建RestFul接口的今天,我們一般會(huì)限定好返回?cái)?shù)據(jù)的格式,有利于前端調(diào)用解析,比如:

{
  "code": 0,
  "data": {},
  "msg": "操作成功"
}

但有時(shí)卻往往會(huì)產(chǎn)生一些bug,這時(shí)候就破壞了返回?cái)?shù)據(jù)的一致性,導(dǎo)致調(diào)用者無(wú)法解析。所以我們常常會(huì)定義一個(gè)全局的異常攔截器。

1.1、@ControllerAdvice

@ControllerAdvice 是Spring 3.2提供的新注解,可以對(duì)Controller中使用到@RequestMapping注解的方法做邏輯處理。

@ControllerAdvice ,很多初學(xué)者可能都沒有聽說(shuō)過(guò)這個(gè)注解,實(shí)際上這是一個(gè)非常有用的注解。顧名思義,這是一個(gè)增強(qiáng)的 Controller,一般配合@ExceptionHandler使用來(lái)處理全局異常。注意不能自己try和catch異常,否則就不會(huì)被全局異常處理捕獲到。

使用這個(gè)注解 ,可以實(shí)現(xiàn)三個(gè)方面的功能:

  • 全局異常處理
  • 全局?jǐn)?shù)據(jù)綁定
  • 全局?jǐn)?shù)據(jù)預(yù)處理

靈活使用這三個(gè)功能,可以幫助我們簡(jiǎn)化很多工作,需要注意的是,這是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,這里只介紹全局異常處理,需要其他功能可以訪問(wèn)參考鏈接。

1.2、全局異常處理

Springboot對(duì)于全局異常的處理做了不錯(cuò)的支持,它提供了兩個(gè)可用的注解。

@ControllerAdvice:用來(lái)開啟全局的異常捕獲

@ExceptionHandler:說(shuō)明捕獲哪些異常,對(duì)哪些異常進(jìn)行處理。

使用 @ControllerAdvice結(jié)合@ExceptionHandler 實(shí)現(xiàn)全局異常處理,只需要定義類,添加該注解即可定義方式如下:

//可以使Spring自動(dòng)把要返回的對(duì)象轉(zhuǎn)化成json文本寫入到響應(yīng)體中,比如自定義的ResultBean
@ResponseBody
@ControllerAdvice
public class MyGlobalExceptionHandler 
{
    // 專門用來(lái)捕獲和處理Controller層的異常
    @ExceptionHandler(Exception.class)
    public ModelAndView customException(Exception e) 
    {
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("myerror");
        return mv;
    }
    // 專門用來(lái)捕獲和處理Controller層的空指針異常
    @ExceptionHandler(NullPointerException.class)
    public ModelAndView nullPointerExceptionHandler(NullPointerException e)
    {
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("success",false);
        mv.addObject("mesg","請(qǐng)求發(fā)生了空指針異常,請(qǐng)稍后再試");
        return mv;
   }
}

在該類中,可以定義多個(gè)方法,不同的方法處理不同的異常,例如專門處理空指針的方法、專門處理數(shù)組越界的方法...,也可以直接向上面代碼一樣,在一個(gè)方法中處理所有的異常信息。

@ExceptionHandler 注解用來(lái)指明異常的處理類型,即如果這里指定為 NullpointerException,則數(shù)組越界異常就不會(huì)進(jìn)到這個(gè)方法中來(lái)。

二、為什么要做Controller層的異常統(tǒng)一處理以及統(tǒng)一結(jié)果返回

不知道你平時(shí)在寫Controller層接口的時(shí)候,有沒有注意過(guò)拋出異常該怎么處理,是否第一反應(yīng)是想著用個(gè)try-catch來(lái)捕獲異常?但是這樣地處理只適合那種編譯器主動(dòng)提示的檢查時(shí)異常,因?yàn)槟悴挥胻ry-catch就過(guò)不了編譯檢查,所以你能主動(dòng)地抓獲異常并進(jìn)行處理。但是,如果存在運(yùn)行時(shí)異常且你沒有來(lái)得及想到去處理它的時(shí)候會(huì)發(fā)生什么呢?我們可以來(lái)先看看下面的這個(gè)沒有處理運(yùn)行時(shí)異常的例子:

@RestController
public class ExceptionRest {
    @GetMapping("getNullPointerException")
    public Map<String,Object> getNullPointerException(){
        throw new NullPointerException("出現(xiàn)了空指針異常");
    }
}

以上代碼在基于maven的SpringMVC項(xiàng)目中,使用tomcat啟動(dòng)后,瀏覽器端發(fā)起如下請(qǐng)求:

//localhost:8080/zxtest/getNullPointerException

訪問(wèn)后得到的結(jié)果是這樣的,瀏覽器收到的報(bào)錯(cuò)信息:

 可以看到,我們?cè)贑ontroller接口層拋出了一個(gè)空指針異常,然后沒有捕獲,結(jié)果異常堆棧就會(huì)返回給前端瀏覽器,給用戶造成了非常不好的體驗(yàn)。

除此之外,前端從報(bào)錯(cuò)信息中能看到后臺(tái)系統(tǒng)使用的服務(wù)器及中間件類型、所采用的框架信息及類信息,甚至如果后端拋出的是SQL異常,那么還可以看到SQL異常的具體查詢的參數(shù)信息,這是一個(gè)中危安全漏洞,是必須要修復(fù)的。

三、使用@ExceptionHandler和@ControllerAdvice做到統(tǒng)一處理

當(dāng)出現(xiàn)這種運(yùn)行時(shí)異常的時(shí)候,我們想到的最簡(jiǎn)單的方法也許就是給可能會(huì)拋出異常的代碼加上異常處理,如下所示:

@RestController
public class ExceptionRest {
    private Logger log = LoggerFactory.getLogger(ExceptionRest.class);
    @GetMapping("getNullPointerException")
    public Map<String,Object> getNullPointerException(){
        Map<String,Object> returnMap = new HashMap<String,Object>();
        try{
            throw new NullPointerException("出現(xiàn)了空指針異常");
        }catch(NullPointerException e){
            log.error("出現(xiàn)了空指針異常",e);
            returnMap.put("success",false);
            returnMap.put("mesg","請(qǐng)求發(fā)生異常,請(qǐng)稍后再試");
        }
        return returnMap;
    }
}

因?yàn)槲覀兪謩?dòng)地在拋出異常的地方加上了處理,并妥善地返回發(fā)生異常時(shí)該返回給前端的內(nèi)容,因此,當(dāng)我們?cè)俅卧跒g覽器發(fā)起相同的請(qǐng)求時(shí)得到就是以下內(nèi)容:

{
  success: false,
  mesg: "請(qǐng)求發(fā)生異常,請(qǐng)稍后再試"
}

貌似問(wèn)題得到了解決,但是你能確保你可以在所有可能會(huì)發(fā)生異常的地方都正好捕獲了異常并處理嗎?你能確保團(tuán)隊(duì)的其他人也這么做?

很明顯,你需要一個(gè)統(tǒng)一的異常捕獲與處理方案。

Spring3.2以后,SpringMVC引入了ExceptionHandler的處理方法,使得對(duì)異常的處理變得更加簡(jiǎn)單和精確,你唯一需要做的就是新建一個(gè)Controller,然后再里面加上兩個(gè)注解即可完成Controller層所有異常的捕獲與處理。

3.1、@ExceptionHandler和@ControllerAdvice基本使用

新建一個(gè)Controller如下:

@ControllerAdvice
public class ExceptionConfigController {
    @ExceptionHandler
    public ModelAndView exceptionHandler(Exception e){
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("success",false);
        mv.addObject("mesg","請(qǐng)求發(fā)生了異常,請(qǐng)稍后再試");
        return mv;
    }
}

我們?cè)谌缟系拇a中,類上加了@ControllerAdvice注解,表示它是一個(gè)增強(qiáng)版的controller,然后在里面創(chuàng)建了一個(gè)返回ModelAndView對(duì)象的exceptionHandler方法,其上加上@ExceptionHandler注解,表示這是一個(gè)異常處理方法,然后在方法里面寫上具體的異常處理及返回參數(shù)邏輯即可,如此就完成了所有的工作,真的是太方便了。

我們?cè)跒g覽器發(fā)起調(diào)用后就返回了如下的結(jié)果:

{
success: false,
mesg: "請(qǐng)求發(fā)生了異常,請(qǐng)稍后再試"
}

3.2、@ExceptionHandler具體異常的處理

相比與HandlerExceptionResolver而言,使用@ExceptionHandler更能靈活地對(duì)不同的異常進(jìn)行分別的處理。并且,當(dāng)拋出的異常是指定異常的子類,那么照樣能夠被捕獲和處理。

我們改變下controller層的代碼如下:

@RestController
public class ExceptionController {
 
    @GetMapping("getNullPointerException")
    public Map<String, Object> getNullPointerException() {
        throw new NullPointerException("出現(xiàn)了空指針異常");
    }
 
    @GetMapping("getClassCastException")
    public Map<String, Object> getClassCastException() {
        throw new ClassCastException("出現(xiàn)了類型轉(zhuǎn)換異常");
    }
 
    @GetMapping("getIOException")
    public Map<String, Object> getIOException() throws IOException {
        throw new IOException("出現(xiàn)了IO異常");
    }
}

已知NullPointerException和ClassCastException都繼承RuntimeException,而RuntimeException和IOException都繼承Exception。

我們?cè)贓xceptionConfigController做這樣的處理:

@ControllerAdvice
public class ExceptionConfigController 
{
    // 專門用來(lái)捕獲和處理Controller層的空指針異常
    @ExceptionHandler(NullPointerException.class)
    public ModelAndView nullPointerExceptionHandler(NullPointerException e){
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("success",false);
        mv.addObject("mesg","請(qǐng)求發(fā)生了空指針異常,請(qǐng)稍后再試");
        return mv;
    }
 
    // 專門用來(lái)捕獲和處理Controller層的運(yùn)行時(shí)異常
    @ExceptionHandler(RuntimeException.class)
    public ModelAndView runtimeExceptionHandler(RuntimeException e){
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("success",false);
        mv.addObject("mesg","請(qǐng)求發(fā)生了運(yùn)行時(shí)異常,請(qǐng)稍后再試");
        return mv;
    }
 
    // 專門用來(lái)捕獲和處理Controller層的異常
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception e){
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("success",false);
        mv.addObject("mesg","請(qǐng)求發(fā)生了異常,請(qǐng)稍后再試");
        return mv;
    }
}

當(dāng)我們?cè)贑ontroller層拋出NullPointerException時(shí),就會(huì)被nullPointerExceptionHandler進(jìn)行處理,然后攔截。

{
success: false,
mesg: "請(qǐng)求發(fā)生了空指針異常,請(qǐng)稍后再試"
}

當(dāng)我們?cè)贑ontroller層拋出ClassCastException時(shí),就會(huì)被runtimeExceptionHandler進(jìn)行處理,然后攔截。

{
success: false,
mesg: "請(qǐng)求發(fā)生了運(yùn)行時(shí)異常,請(qǐng)稍后再試"
}

當(dāng)我們?cè)贑ontroller層拋出IOException時(shí),就會(huì)被exceptionHandler進(jìn)行處理,然后攔截。

{
success: false,
mesg: "請(qǐng)求發(fā)生了異常,請(qǐng)稍后再試"
}

SpringMVC為我們提供的Controller層異常處理真的是太方便了,尤其是@ExceptionHandler,推薦大家使用。

四、自定義異常處理類CustomUserException

4.1、自定義異常處理類

在程序中,可能會(huì)遇到JDK提供的任何標(biāo)準(zhǔn)異常類都無(wú)法充分描述清楚我們想要表達(dá)的問(wèn)題,又或者捕捉數(shù)據(jù)庫(kù)異常時(shí)候不知道具體異常名字,這種情況下可以創(chuàng)建自己的異常類,即自定義異常類,在需要的時(shí)候手動(dòng)throw出,然后再全局異常統(tǒng)一處理。

自定義異常類只需從Exception類或者它的子類派生一個(gè)子類即可。自定義異常類如果繼承Exception類,則為受檢查異常,必須對(duì)其進(jìn)行處理;如果不想處理,可以讓自定義異常類繼承運(yùn)行時(shí)異常RuntimeException類。習(xí)慣上,自定義異常類應(yīng)該包含2個(gè)構(gòu)造器:一個(gè)是默認(rèn)的構(gòu)造器,另一個(gè)是帶有詳細(xì)信息的構(gòu)造器。

/**
*   自定義異常的步驟:
*  (1)繼承 Exception 或 RuntimeException
*  (2)定義構(gòu)造方法
*/
public class CustomUserException extends RuntimeException {
    private Integer code;
    public CustomUserException(UserResponseEnum userResponseEnum){
        super(userResponseEnum.getDescription());
        this.code = userResponseEnum.getCode();
    }
    public Integer getCode() {
        return code;
    }
}

在構(gòu)造自定義業(yè)務(wù)異常對(duì)象時(shí)使用了枚舉的方式,將常見的業(yè)務(wù)錯(cuò)誤提示語(yǔ)對(duì)應(yīng)的錯(cuò)誤代碼進(jìn)行映射,枚舉類如下所示:

public enum UserResponseEnum {
    USER_NOT_FOUND(50001,"用戶不存在"),
    USER_AUTHENTICATION_ERROR(50002,"用戶密碼不正確");
    private Integer code;
    private String description;
    UserResponseEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

4.2、通過(guò)@ControllerAdvice和@ExceptionHandler注解,實(shí)現(xiàn)統(tǒng)一異常捕獲

@RestController
@ControllerAdvice(basePackages = {"com.hs.controller"})
public class CustomExceptionAdvice 
{
    private static final Logger logger = LoggerFactory.getLogger(CustomExceptionAdvice.class);
    /**
     * 處理與用戶相關(guān)的業(yè)務(wù)異常
     * @return
     */
    @ExceptionHandler(CustomUserException.class)
    public BaseResult UserExceptionHandler(HttpServletRequest request,CustomUserException e){
        logger.error("用戶信息異常:Host:{} invoke URL:{},錯(cuò)誤信息:{}",request.getRemoteHost(),request.getRequestURL(),e.getMessage());
        return new BaseResult(e.getCode(),false,e.getMessage());
    }
}
 

4.3、在業(yè)務(wù)代碼中在需要拋出異常的地方拋出對(duì)應(yīng)的異常即可

	/**
     * 根據(jù)主鍵獲取用戶實(shí)體
     * @param id
     * @return
     */
    public User selectById(String id) 
    {
        User user = userMapper.selectByPrimaryId(id);
        if (user == null) {
            throw new CustomUserException(UserResponseEnum.USER_NOT_FOUND);
        }
        return user;
    }
 

    返回信息如下:
    {
        "code": 50001,
        "data": false,
        "message": "用戶不存在"
    }

前端即可根據(jù)返回信息對(duì)用戶進(jìn)行友好的提示。

到此這篇關(guān)于Spring中的@ControllerAdvice和@ExceptionHandler注解處理全局異常的文章就介紹到這了,更多相關(guān)@ControllerAdvice和@ExceptionHandler注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java String字符串和Unicode字符相互轉(zhuǎn)換代碼

    Java String字符串和Unicode字符相互轉(zhuǎn)換代碼

    這篇文章主要介紹了Java String字符串和Unicode字符相互轉(zhuǎn)換代碼,需要的朋友可以參考下
    2014-10-10
  • hibernate通過(guò)session實(shí)現(xiàn)增刪改查操作實(shí)例解析

    hibernate通過(guò)session實(shí)現(xiàn)增刪改查操作實(shí)例解析

    這篇文章主要介紹了hibernate通過(guò)session實(shí)現(xiàn)增刪改查操作實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • Java反射之深入理解

    Java反射之深入理解

    這篇文章主要介紹了Java反射機(jī)制的深入理解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • RabbitMQ使用SpringAMQP的配置方法

    RabbitMQ使用SpringAMQP的配置方法

    這篇文章主要介紹了RabbitMQ使用SpringAMQP的配置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-03-03
  • 詳談spring boot中幾種常見的依賴注入問(wèn)題

    詳談spring boot中幾種常見的依賴注入問(wèn)題

    這篇文章主要介紹了spring boot中幾種常見的依賴注入問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java多線程實(shí)戰(zhàn)之單例模式與多線程的實(shí)例詳解

    Java多線程實(shí)戰(zhàn)之單例模式與多線程的實(shí)例詳解

    今天小編就為大家分享一篇關(guān)于Java多線程實(shí)戰(zhàn)之單例模式與多線程的實(shí)例詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • SpringBoot中Filter沒有生效原因及解決方案

    SpringBoot中Filter沒有生效原因及解決方案

    Servlet 三大組件 Servlet、Filter、Listener 在傳統(tǒng)項(xiàng)目中需要在 web.xml 中進(jìn)行相應(yīng)的配置,這篇文章主要介紹了SpringBoot中Filter沒有生效原因及解決方案,需要的朋友可以參考下
    2024-04-04
  • Java深入講解static操作符

    Java深入講解static操作符

    static關(guān)鍵字基本概念我們可以一句話來(lái)概括:方便在沒有創(chuàng)建對(duì)象的情況下來(lái)進(jìn)行調(diào)用。也就是說(shuō):被static關(guān)鍵字修飾的不需要?jiǎng)?chuàng)建對(duì)象去調(diào)用,直接根據(jù)類名就可以去訪問(wèn),讓我們來(lái)了解一下你可能還不知道情況
    2022-07-07
  • Java可重入鎖ReentrantLock詳解

    Java可重入鎖ReentrantLock詳解

    這篇文章主要介紹了Java可重入鎖ReentrantLock詳解,ReentrantLock是一個(gè)可重入且獨(dú)占式的鎖,是一種遞歸無(wú)阻塞的同步機(jī)制,它支持重復(fù)進(jìn)入鎖,即該鎖能夠支持一個(gè)線程對(duì)資源的重復(fù)加鎖,除此之外,該鎖的還支持獲取鎖時(shí)的公平和非公平性選擇,需要的朋友可以參考下
    2023-09-09
  • Java實(shí)現(xiàn)班級(jí)管理系統(tǒng)

    Java實(shí)現(xiàn)班級(jí)管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)班級(jí)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論