成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

SpringBoot RESTful 應(yīng)用中的異常處理小結(jié)

jackzou / 1332人閱讀

摘要:和的區(qū)別方法注解作用于級(jí)別注解為一個(gè)定義一個(gè)異常處理器類(lèi)注解作用于整個(gè)工程注解定義了一個(gè)全局的異常處理器需要注意的是的優(yōu)先級(jí)比高即拋出的異常如果既可以讓標(biāo)注的方法處理又可以讓標(biāo)注的類(lèi)中的方法處理則優(yōu)先讓標(biāo)注的方法處理處理中的異常為了方便地展

@ControllerAdvice 和 @ExceptionHandler 的區(qū)別

ExceptionHandler, 方法注解, 作用于 Controller 級(jí)別. ExceptionHandler 注解為一個(gè) Controler 定義一個(gè)異常處理器.

ControllerAdvice, 類(lèi)注解, 作用于 整個(gè) Spring 工程. ControllerAdvice 注解定義了一個(gè)全局的異常處理器.

需要注意的是, ExceptionHandler 的優(yōu)先級(jí)比 ControllerAdvice 高, 即 Controller 拋出的異常如果既可以讓 ExceptionHandler 標(biāo)注的方法處理, 又可以讓 ControllerAdvice 標(biāo)注的類(lèi)中的方法處理, 則優(yōu)先讓 ExceptionHandler 標(biāo)注的方法處理.

處理 Controller 中的異常

為了方便地展示 Controller 異常處理的方式, 我創(chuàng)建了一個(gè)工程 SpringBootRESTfulErrorHandler, 其源碼可以到我的 Github: github.com/yongshun 中找到.
SpringBootRESTfulErrorHandler 工程的目錄結(jié)構(gòu)如下:

首先我們定義了三個(gè)自定義的異常:
BaseException:

public class BaseException extends Exception {
    public BaseException(String message) {
        super(message);
    }
}

MyException1:

public class MyException1 extends BaseException {
    public MyException1(String message) {
        super(message);
    }
}

MyException2:

public class MyException2 extends BaseException {
    public MyException2(String message) {
        super(message);
    }
}

接著我們?cè)?DemoController 中分別拋出這些異常:

@RestController
public class DemoController {
    private Logger logger = LoggerFactory.getLogger("GlobalExceptionHandler");

    @RequestMapping("/ex1")
    public Object throwBaseException() throws Exception {
        throw new BaseException("This is BaseException.");
    }

    @RequestMapping("/ex2")
    public Object throwMyException1() throws Exception {
        throw new MyException1("This is MyException1.");
    }

    @RequestMapping("/ex3")
    public Object throwMyException2() throws Exception {
        throw new MyException2("This is MyException1.");
    }

    @RequestMapping("/ex4")
    public Object throwIOException() throws Exception {
        throw new IOException("This is IOException.");
    }

    @RequestMapping("/ex5")
    public Object throwNullPointerException() throws Exception {
        throw new NullPointerException("This is NullPointerException.");
    }

    @ExceptionHandler(NullPointerException.class)
    public String controllerExceptionHandler(HttpServletRequest req, Exception e) {
        logger.error("---ControllerException Handler---Host {} invokes url {} ERROR: {}", req.getRemoteHost(), req.getRequestURL(), e.getMessage());
        return e.getMessage();
    }
}

/ex1: 拋出 BaseException

/ex2: 拋出 MyException1

/ex3: 拋出 MyException2

/ex4: 拋出 IOException

/ex5: 拋出 NullPointerException

當(dāng) DemoController 拋出未捕獲的異常時(shí), 我們?cè)?GlobalExceptionHandler 中進(jìn)行捕獲并處理:
GlobalExceptionHandler:

@RestController
@ControllerAdvice
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger("GlobalExceptionHandler");

    @ExceptionHandler(value = BaseException.class)
    @ResponseBody
    public Object baseErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        logger.error("---BaseException Handler---Host {} invokes url {} ERROR: {}", req.getRemoteHost(), req.getRequestURL(), e.getMessage());
        return e.getMessage();
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Object defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        logger.error("---DefaultException Handler---Host {} invokes url {} ERROR: {}", req.getRemoteHost(), req.getRequestURL(), e.getMessage());
        return e.getMessage();
    }
}

我們看到, GlobalExceptionHandler 類(lèi)有兩個(gè)注解:

RestController, 表明 GlobalExceptionHandler 是一個(gè) RESTful Controller, 即它會(huì)以 RESTful 的形式返回回復(fù).

ControllerAdvice, 表示 GlobalExceptionHandler 是一個(gè)全局的異常處理器.

在 GlobalExceptionHandler 中, 我們使用了 ExceptionHandler 注解標(biāo)注了兩個(gè)方法:

ExceptionHandler(value = BaseException.class): 表示 baseErrorHandler 處理 BaseException 異常和其子異常.

ExceptionHandler(value = Exception.class): 表示 defaultErrorHandler 會(huì)處理 Exception 異常和其所用子異常.

要注意的是, 和 try...catch 語(yǔ)句塊, 異常處理的順序也是從具體到一般, 即如果 baseErrorHandler 可以處理此異常, 則調(diào)用此方法來(lái)處理異常, 反之使用 defaultErrorHandler 來(lái)處理異常.

既然我們已經(jīng)實(shí)現(xiàn)了 Controller 的異常處理, 那么接下來(lái)我們就來(lái)測(cè)試一下吧.
在瀏覽器中分別訪(fǎng)問(wèn)這些鏈接, 結(jié)果如下:
/ex1:

/ex2:

/ex3:

/ex4:

/ex5:

可以看到, /ex1, /ex2, /ex3 拋出的異常都由 GlobalExceptionHandler.baseErrorHandler 處理; /ex4 拋出的 IOException 異常由 GlobalExceptionHandler.defaultErrorHandler 處理. 但是 /ex5 拋出的 NullPointerException 異常為什么不是 defaultErrorHandler 處理, 而是由 controllerExceptionHandler 來(lái)處理呢? 回想到 @ControllerAdvice 和 @ExceptionHandler 的區(qū)別 這以小節(jié)中的內(nèi)容時(shí), 我們就知道原因了: 因?yàn)槲覀冊(cè)?DemoController 中使用 ExceptionHandler 注解定義了一個(gè) Controller 級(jí)的異常處理器, 這個(gè)級(jí)別的異常處理器的優(yōu)先級(jí)比全局的異常處理器優(yōu)先級(jí)高, 因此 Spring 發(fā)現(xiàn) controllerExceptionHandler 可以處理 NullPointerException 異常時(shí), 就調(diào)用這個(gè)方法, 而不會(huì)調(diào)用全局的 defaultErrorHandler 方法了.

處理 404 錯(cuò)誤 Spring MVC

SpringBoot 默認(rèn)提供了一個(gè)全局的 handler 來(lái)處理所有的 HTTP 錯(cuò)誤, 并把它映射為 /error. 當(dāng)發(fā)生一個(gè) HTTP 錯(cuò)誤, 例如 404 錯(cuò)誤時(shí), SpringBoot 內(nèi)部的機(jī)制會(huì)將頁(yè)面重定向到 /error 中.
例如下圖中是一個(gè)默認(rèn)的 SpringBoot 404 異常頁(yè)面.

這個(gè)頁(yè)面實(shí)在是太丑了, 我們能不能自定義一個(gè)異常頁(yè)面呢? 當(dāng)然可以了, 并且 SpringBoot 也給我們提示了: This application has no explicit mapping for /error, so you are seeing this as a fallback.
因此我們實(shí)現(xiàn)一個(gè) /error 映射的 Controller 即可.

public class HttpErrorHandler implements ErrorController {

    private final static String ERROR_PATH = "/error";

    /**
     * Supports the HTML Error View
     *
     * @param request
     * @return
     */
    @RequestMapping(value = ERROR_PATH, produces = "text/html")
    public String errorHtml(HttpServletRequest request) {
        return "404";
    }

    /**
     * Supports other formats like JSON, XML
     *
     * @param request
     * @return
     */
    @RequestMapping(value = ERROR_PATH)
    @ResponseBody
    public Object error(HttpServletRequest request) {
        return "404";
    }

    /**
     * Returns the path of the error page.
     *
     * @return the error path
     */
    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}

根據(jù)上面代碼我們看到, 為了實(shí)現(xiàn)自定義的 404 頁(yè)面, 我們實(shí)現(xiàn)了 ErrorController 接口:

public interface ErrorController {
    String getErrorPath();
}

這個(gè)接口只有一個(gè)方法, 當(dāng)出現(xiàn) HTTP 錯(cuò)誤時(shí), SpringBoot 會(huì)將頁(yè)面重定向到 getErrorPath 方法返回的頁(yè)面中. 這樣我們就可以實(shí)現(xiàn)自定義的錯(cuò)誤頁(yè)面了.

RESTful API

提供一個(gè)自定義的 "/error" 頁(yè)面對(duì) Spring MVC 的服務(wù)來(lái)說(shuō)自然是沒(méi)問(wèn)題的, 但是如果我們的服務(wù)是一個(gè) RESTful 服務(wù)的話(huà), 這樣做就不行了.
當(dāng)用戶(hù)調(diào)用了一個(gè)不存在的 RESTful API 時(shí), 我們想記錄下這個(gè)異常訪(fǎng)問(wèn), 并返回一個(gè)代表錯(cuò)誤的 JSON 給客戶(hù)端, 這該怎么實(shí)現(xiàn)呢?
我們很自然地想到, 我們可以使用處理異常的那一套來(lái)處理 404 錯(cuò)誤碼.
那么我們來(lái)試一下這個(gè)想法是否可行吧.

奇怪的是, 當(dāng)我們?cè)跒g覽器中隨意輸入一個(gè)路徑時(shí), 代碼并沒(méi)有執(zhí)行到異常處理邏輯中, 而是返回了一個(gè) HTML 頁(yè)面給我們, 這又是怎么回事呢?
原來(lái) Spring Boot 中, 當(dāng)用戶(hù)訪(fǎng)問(wèn)了一個(gè)不存在的鏈接時(shí), Spring 默認(rèn)會(huì)將頁(yè)面重定向到 **/error** 上, 而不會(huì)拋出異常.
既然如此, 那我們就告訴 Spring Boot, 當(dāng)出現(xiàn) 404 錯(cuò)誤時(shí), 拋出一個(gè)異常即可. 在 application.properties 中添加兩個(gè)配置:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

上面的配置中, 第一個(gè) spring.mvc.throw-exception-if-no-handler-found 告訴 SpringBoot 當(dāng)出現(xiàn) 404 錯(cuò)誤時(shí), 直接拋出異常. 第二個(gè) spring.resources.add-mappings 告訴 SpringBoot 不要為我們工程中的資源文件建立映射. 這兩個(gè)配置正是 RESTful 服務(wù)所需要的.
當(dāng)加上這兩個(gè)配置后, 我們?cè)賮?lái)試一下:

可以看到, 現(xiàn)在確實(shí)是在 defaultErrorHandler 中處理了.

本文由 yongshun 發(fā)表于個(gè)人博客, 采用署名-非商業(yè)性使用-相同方式共享 3.0 中國(guó)大陸許可協(xié)議.
非商業(yè)轉(zhuǎn)載請(qǐng)注明作者及出處. 商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者本人
Email: yongshun1228@gmail.com
本文標(biāo)題為: SpringBoot RESTful 應(yīng)用中的異常處理小結(jié)
本文鏈接為: https://segmentfault.com/a/1190000006749441

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/65073.html

相關(guān)文章

  • Web開(kāi)發(fā)框架推導(dǎo)

    摘要:邊界清晰,有利于理解開(kāi)發(fā)測(cè)試和部署。前后端分離考慮到目前開(kāi)發(fā)流行前后端分離,為了適應(yīng)潮流,引入前后端分離的約束。該請(qǐng)求被接受處理,但是該處理是不完整的。 本文欲回答這樣一個(gè)問(wèn)題:在 「特定環(huán)境 」下,如何規(guī)劃Web開(kāi)發(fā)框架,使其能滿(mǎn)足 「期望 」? 假設(shè)我們的「特定環(huán)境 」如下: 技術(shù)層面 使用Java語(yǔ)言進(jìn)行開(kāi)發(fā) 通過(guò)Maven構(gòu)建 基于SpringBoot 使用Intelli...

    vpants 評(píng)論0 收藏0
  • SpringBoot就是這么簡(jiǎn)單

    摘要:熱加載代表的是我們不需要重啟服務(wù)器,就能夠類(lèi)檢測(cè)得到,重新生成類(lèi)的字節(jié)碼文件無(wú)論是熱部署或者是熱加載都是基于類(lèi)加載器來(lái)完成的。驗(yàn)證階段字節(jié)碼文件不會(huì)對(duì)造成危害準(zhǔn)備階段是會(huì)賦初始值,并不是程序中的值。 一、SpringBoot入門(mén) 今天在慕課網(wǎng)中看見(jiàn)了Spring Boot這么一個(gè)教程,這個(gè)Spring Boot作為JavaWeb的學(xué)習(xí)者肯定至少會(huì)聽(tīng)過(guò),但我是不知道他是什么玩意。 只是大...

    whinc 評(píng)論0 收藏0
  • Spring Boot 2.x 系列教程:WebFlux REST API 全局異常處理 Error

    摘要:挺多人咨詢(xún)的,異常處理用切面注解去實(shí)現(xiàn)去全局異常處理。全局異常處理類(lèi),代碼如下代碼解析如下抽象類(lèi)是用來(lái)處理全局錯(cuò)誤時(shí)進(jìn)行擴(kuò)展和實(shí)現(xiàn)注解標(biāo)記的切面排序,值越小擁有越高的優(yōu)先級(jí),這里設(shè)置優(yōu)先級(jí)偏高。 本文內(nèi)容 為什么要全局異常處理? WebFlux REST 全局異常處理實(shí)戰(zhàn) 小結(jié) 摘錄:只有不斷培養(yǎng)好習(xí)慣,同時(shí)不斷打破壞習(xí)慣,我們的行為舉止才能夠自始至終都是正確的。 一、為什么要全局...

    BicycleWarrior 評(píng)論0 收藏0
  • SpringBoot基礎(chǔ)篇AOP之基本使用姿勢(shì)小結(jié)

    摘要:通知和切點(diǎn)共同定義了關(guān)于切面的全部?jī)?nèi)容,它是什么時(shí)候,在何時(shí)和何處完成功能引入允許我們向現(xiàn)有的類(lèi)添加新的方法或者屬性組裝方面來(lái)創(chuàng)建一個(gè)被通知對(duì)象。這可以在編譯時(shí)完成例如使用編譯器,也可以在運(yùn)行時(shí)完成。和其他純框架一樣,在運(yùn)行時(shí)完成織入。 原文:190301-SpringBoot基礎(chǔ)篇AOP之基本使用姿勢(shì)小結(jié) 一般來(lái)講,談到Spring的特性,繞不過(guò)去的就是DI(依賴(lài)注入)和AOP(切...

    timger 評(píng)論0 收藏0
  • Java經(jīng)典

    摘要:請(qǐng)注意,我們?cè)诹牧膯卧獪y(cè)試遇到問(wèn)題多思考多查閱多驗(yàn)證,方能有所得,再勤快點(diǎn)樂(lè)于分享,才能寫(xiě)出好文章。單元測(cè)試是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證。 JAVA容器-自問(wèn)自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們?cè)诠ぷ髦薪?jīng)常會(huì)使用,而且面試中也很頻繁會(huì)問(wèn)到,因?yàn)樗锩嫣N(yùn)含著很多知識(shí)點(diǎn),可以很好的考察個(gè)人基礎(chǔ)。但一個(gè)這么重要的東西,我為什么沒(méi)有在一開(kāi)始...

    xcold 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

jackzou

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<