Spring Boot框架錯(cuò)誤處理
推薦 + 挑錯(cuò) + 收藏(0) + 用戶(hù)評(píng)論(0)
《blockquote》 《p》《strong》原文《/strong》:《a href=“https://www.toptal.com/java/spring-boot-rest-api-error-handling”》Guide to Spring Boot REST API Error Handling《/a》 《br》 《strong》作者《/strong》:BRUNO LEITE 《br》 《strong》翻譯《/strong》:雁驚寒《/p》 《/blockquote》《p》《em》摘要:本文通過(guò)實(shí)例介紹了使用Spring Boot在設(shè)計(jì)API的時(shí)候如何正確地對(duì)異常進(jìn)行處理。以下是譯文《/em》《/p》《p》API在提供錯(cuò)誤消息的同時(shí)進(jìn)行適當(dāng)?shù)腻e(cuò)誤處理,是一個(gè)非常有用的功能,因?yàn)檫@能讓API客戶(hù)端對(duì)問(wèn)題進(jìn)行正確地響應(yīng)。API處理錯(cuò)誤的默認(rèn)行為通常是返回難以理解的堆棧跟蹤,而這些對(duì)API客戶(hù)端來(lái)說(shuō)并沒(méi)有什么用。將錯(cuò)誤信息切分成多個(gè)字段可以方便API客戶(hù)端的解析,以此向用戶(hù)提供更加友好的錯(cuò)誤消息。本文將介紹在使用《a href=“https://www.toptal.com/spring”》Spring Boot《/a》構(gòu)建REST API的時(shí)候如何進(jìn)行合適的錯(cuò)誤處理。《/p》《p》《/p》《center》《img src=“?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240” alt=“Person confused about a cryptic and long error message” title=“”》《/center》《p》《/p》《p》在過(guò)去幾年里,使用Spring構(gòu)建REST API已經(jīng)成為Java開(kāi)發(fā)人員的標(biāo)準(zhǔn)方法。而使用Spring Boot則有助于API的構(gòu)建,因?yàn)樗鼊h除了大量的樣板代碼,并實(shí)現(xiàn)了各種組件的自動(dòng)化配置。我們假設(shè)你對(duì)利用這些技術(shù)進(jìn)行API開(kāi)發(fā)的基礎(chǔ)知識(shí)已經(jīng)非常了解。如果你對(duì)如何開(kāi)發(fā)基本的REST API并不熟悉,那么你應(yīng)該先閱讀這篇關(guān)于《a href=“https://www.toptal.com/spring/beginners-guide-to-mvc-with-spring-framework”》Spring MVC《/a》的文章或另一篇有關(guān)《a href=“https://spring.io/guides/gs/rest-service/”》構(gòu)建Spring REST服務(wù)《/a》的文章?!?p》《h2》讓錯(cuò)誤響應(yīng)更清晰《/h2》《p》在本文中,我們將實(shí)現(xiàn)一個(gè)通過(guò)REST API來(lái)檢索鳥(niǎo)類(lèi)(代表一個(gè)對(duì)象)的應(yīng)用程序,《a href=“https://github.com/brunocleite/spring-boot-exception-handling”》代碼托管在GitHub上《/a》。這個(gè)示例包含了本文描述的所有功能,以及比較多的錯(cuò)誤處理場(chǎng)景。以下是該程序?qū)崿F(xiàn)的端點(diǎn)URL:《/p》《table》 《thead》 《tr》 《th》《/th》 《th》《/th》 《/tr》 《/thead》 《tbody》《tr》 《td》《code》GET /birds/{birdId}《/code》《/td》 《td》獲取鳥(niǎo)的相關(guān)信息,如果沒(méi)有找到,則拋出異常?!?td》 《/tr》 《tr》 《td》《code》GET /birds/noexception/{birdId}《/code》《/td》 《td》這個(gè)調(diào)用也可以獲取鳥(niǎo)的相關(guān)信息,但是即使沒(méi)有找到相應(yīng)的鳥(niǎo),也不會(huì)拋出異常?!?td》 《/tr》 《tr》 《td》《code》POST /birds《/code》《/td》 《td》創(chuàng)建一只鳥(niǎo)?!?td》 《/tr》 《/tbody》《/table》《p》Spring框架的MVC模塊在錯(cuò)誤處理方面提供了一些很不錯(cuò)的功能,但是這些功能需要由開(kāi)發(fā)人員主動(dòng)調(diào)用,才能返回對(duì)API客戶(hù)端的有具體意義的響應(yīng)?!?p》《p》我們來(lái)看一下這個(gè)Spring Boot默認(rèn)響應(yīng)的例子。當(dāng)我們向《code》/birds《/code》發(fā)送一個(gè)HTTP POST的時(shí)候,消息內(nèi)容是下面這個(gè)JSON對(duì)象,字段“mass”的值是字符串“aaa”,這個(gè)字段本應(yīng)該填一個(gè)整數(shù):《/p》《pre class=“prettyprint”》《code class=“ hljs json”》{ “《span class=”hljs-attribute“》scientificName《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“Common blackbird”《/span》《/span》, “《span class=”hljs-attribute“》specie《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“Turdus merula”《/span》《/span》, “《span class=”hljs-attribute“》mass《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“aaa”《/span》《/span》, “《span class=”hljs-attribute“》length《/span》”: 《span class=“hljs-value”》《span class=“hljs-number”》4《/span》 《/span》} 《/code》《/pre》《p》Spring Boot的默認(rèn)響應(yīng),沒(méi)有正確的處理錯(cuò)誤:《/p》《pre class=“prettyprint”》《code class=“ hljs scilab”》{ 《span class=“hljs-string”》“timestamp”《/span》: 《span class=“hljs-number”》1500597044204《/span》, 《span class=“hljs-string”》“status”《/span》: 《span class=“hljs-number”》400《/span》, 《span class=“hljs-string”》“error”《/span》: 《span class=“hljs-string”》“Bad Request”《/span》, 《span class=“hljs-string”》“exception”《/span》: 《span class=“hljs-string”》“org.springframework.http.converter.HttpMessageNotReadableException”《/span》, 《span class=“hljs-string”》“message”《/span》: 《span class=“hljs-string”》“JSON parse error: Unrecognized token ‘《/span》《span class=”hljs-transposed_variable“》three’《/span》: was expecting (《span class=”hljs-string“》‘true’《/span》, 《span class=”hljs-string“》‘false’《/span》 《span class=”hljs-built_in“》or《/span》 《span class=”hljs-string“》‘null’《/span》); nested exception is 《span class=”hljs-transposed_variable“》com.《/span》《span class=”hljs-transposed_variable“》fasterxml.《/span》《span class=”hljs-transposed_variable“》jackson.《/span》《span class=”hljs-transposed_variable“》core.《/span》JsonParseException: Unrecognized token 《span class=”hljs-string“》‘a(chǎn)aa’《/span》: was expecting (《span class=”hljs-string“》‘true’《/span》, 《span class=”hljs-string“》‘false’《/span》 《span class=”hljs-built_in“》or《/span》 《span class=”hljs-string“》‘null’《/span》)\n at 《span class=”hljs-matrix“》[Source: java.io.PushbackInputStream@cba7ebc; line: 《span class=”hljs-number“》4《/span》, column: 《span class=”hljs-number“》17《/span》]《/span》《span class=”hljs-string“》”, “《/span》path《span class=”hljs-string“》”: “《/span》/birds《span class=”hljs-string“》” } 《/span》《/code》《/pre》《p》呃…… 響應(yīng)消息里有一些很有用的字段,但它里面有關(guān)異常的內(nèi)容太多了。 順便說(shuō)一句,這是Spring Boot中《code》DefaultErrorAttributes《/code》類(lèi)的內(nèi)容。 《code》timestamp《/code》字段是一個(gè)整數(shù),不攜帶什么度量單位的時(shí)間戳信息?!禼ode》exception《/code》字段只有Java開(kāi)發(fā)人員會(huì)感興趣,該消息使API消費(fèi)者迷失在與它們無(wú)關(guān)的細(xì)節(jié)中。是否有更多的細(xì)節(jié)可以從錯(cuò)誤產(chǎn)生的異常中提取出來(lái)呢? 下面,我們來(lái)學(xué)習(xí)如何正確地處理這些異常,并將它們包裝成更好的JSON表示形式,讓API客戶(hù)端更容易識(shí)別?!?p》《p》由于我們要使用Java 8的日期和時(shí)間類(lèi),因此首先需要為Jackson JSR310轉(zhuǎn)換器添加一個(gè)Maven依賴(lài)關(guān)系。這個(gè)包使用注解《code》@JsonFormat《/code》將Java 8的日期和時(shí)間類(lèi)轉(zhuǎn)換為JSON:《/p》《pre class=“prettyprint”》《code class=“ hljs xml”》《span class=“hljs-tag”》《《span class=“hljs-title”》dependency《/span》》《/span》 《span class=“hljs-tag”》《《span class=“hljs-title”》groupId《/span》》《/span》com.fasterxml.jackson.datatype《span class=“hljs-tag”》《/《span class=“hljs-title”》groupId《/span》》《/span》 《span class=“hljs-tag”》《《span class=“hljs-title”》artifactId《/span》》《/span》jackson-datatype-jsr310《span class=“hljs-tag”》《/《span class=“hljs-title”》artifactId《/span》》《/span》 《span class=“hljs-tag”》《/《span class=“hljs-title”》dependency《/span》》《/span》 《/code》《/pre》《p》好的,我們來(lái)定義一個(gè)表示API錯(cuò)誤的類(lèi)。 我們將創(chuàng)建一個(gè)名為《code》ApiError《/code》的類(lèi),該類(lèi)用于保存REST調(diào)用期間發(fā)生錯(cuò)誤的相關(guān)信息?!?p》《pre class=“prettyprint”》《code class=“l(fā)anguage-java hljs ”》class ApiError { 《span class=“hljs-keyword”》private《/span》 HttpStatus status; 《span class=“hljs-annotation”》@JsonFormat《/span》(shape = JsonFormat.Shape.STRING, pattern = 《span class=“hljs-string”》“dd-MM-yyyy hh:mm:ss”《/span》) 《span class=“hljs-keyword”》private《/span》 LocalDateTime timestamp; 《span class=“hljs-keyword”》private《/span》 String message; 《span class=“hljs-keyword”》private《/span》 String debugMessage; 《span class=“hljs-keyword”》private《/span》 List《ApiSubError》 subErrors; 《span class=“hljs-keyword”》private《/span》 《span class=“hljs-title”》ApiError《/span》() { timestamp = LocalDateTime.now(); } ApiError(HttpStatus status) { 《span class=“hljs-keyword”》this《/span》(); 《span class=“hljs-keyword”》this《/span》.status = status; } ApiError(HttpStatus status, Throwable ex) { 《span class=“hljs-keyword”》this《/span》(); 《span class=“hljs-keyword”》this《/span》.status = status; 《span class=“hljs-keyword”》this《/span》.message = 《span class=“hljs-string”》“Unexpected error”《/span》; 《span class=“hljs-keyword”》this《/span》.debugMessage = ex.getLocalizedMessage(); } ApiError(HttpStatus status, String message, Throwable ex) { 《span class=“hljs-keyword”》this《/span》(); 《span class=“hljs-keyword”》this《/span》.status = status; 《span class=“hljs-keyword”》this《/span》.message = message; 《span class=“hljs-keyword”》this《/span》.debugMessage = ex.getLocalizedMessage(); } } 《/code》《/pre》《ul》 《li》《p》《code》status《/code》屬性保存了操作調(diào)用的狀態(tài)。 比如,4xx表示客戶(hù)端錯(cuò)誤,5xx意味著服務(wù)器錯(cuò)誤。 比較常見(jiàn)的情況是:http返回碼400表示BAD_REQUEST,例如,客戶(hù)端發(fā)送了格式不正確的字段(如無(wú)效的電子郵件地址)?!?p》《/li》 《li》《p》《code》timestamp《/code》屬性保存了發(fā)生錯(cuò)誤的日期時(shí)間?!?p》《/li》 《li》《p》《code》message《/code》屬性保存了對(duì)用戶(hù)友好的錯(cuò)誤信息。《/p》《/li》 《li》《p》《code》debugMessage《/code》屬性更詳細(xì)地描述了錯(cuò)誤?!?p》《/li》 《li》《p》《code》subErrors《/code》屬性保存了發(fā)生的子錯(cuò)誤的數(shù)組。 這用于表示在單個(gè)調(diào)用中出現(xiàn)的多個(gè)錯(cuò)誤。比如,校驗(yàn)的時(shí)候有多個(gè)字段驗(yàn)證失敗。用《code》ApiSubError《/code》類(lèi)進(jìn)行封裝?!?p》《/li》 《/ul》《pre class=“prettyprint”》《code class=“l(fā)anguage-java hljs ”》《span class=“hljs-keyword”》abstract《/span》 class ApiSubError { } 《span class=“hljs-annotation”》@Data《/span》 《span class=“hljs-annotation”》@EqualsAndHashCode《/span》(callSuper = 《span class=“hljs-keyword”》false《/span》) 《span class=“hljs-annotation”》@AllArgsConstructor《/span》 class ApiValidati extends ApiSubError { 《span class=“hljs-keyword”》private《/span》 String object; 《span class=“hljs-keyword”》private《/span》 String field; 《span class=“hljs-keyword”》private《/span》 Object rejectedValue; 《span class=“hljs-keyword”》private《/span》 String message; ApiValidati(String object, String message) { 《span class=“hljs-keyword”》this《/span》.object = object; 《span class=“hljs-keyword”》this《/span》.message = message; } } 《/code》《/pre》《p》《code》ApiValidati《/code》是類(lèi)《code》ApiSubError《/code》的擴(kuò)展類(lèi),表示REST調(diào)用時(shí)遇到的校驗(yàn)問(wèn)題?!?p》《p》下面,你將看到幾個(gè)JSON響應(yīng)的例子,這些響應(yīng)根據(jù)我們上面的描述做了改進(jìn)?!?p》《p》以下這個(gè)JSON是在調(diào)用URL《code》GET /birds/2《/code》后找不到實(shí)體的時(shí)候返回的:《/p》《pre class=“prettyprint”》《code class=“ hljs json”》{ “《span class=”hljs-attribute“》apierror《/span》”: 《span class=“hljs-value”》{ “《span class=”hljs-attribute“》status《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“NOT_FOUND”《/span》《/span》, “《span class=”hljs-attribute“》timestamp《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“18-07-2017 06:20:19”《/span》《/span》, “《span class=”hljs-attribute“》message《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“Bird was not found for parameters {id=2}”《/span》 《/span》} 《/span》} 《/code》《/pre》《p》下面是調(diào)用《code》POST /birds《/code》時(shí)傳入了無(wú)效值后返回的JSON示例:《/p》《pre class=“prettyprint”》《code class=“ hljs json”》{ “《span class=”hljs-attribute“》apierror《/span》”: 《span class=“hljs-value”》{ “《span class=”hljs-attribute“》status《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“BAD_REQUEST”《/span》《/span》, “《span class=”hljs-attribute“》timestamp《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“18-07-2017 06:49:25”《/span》《/span》, “《span class=”hljs-attribute“》message《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“Validation errors”《/span》《/span》, “《span class=”hljs-attribute“》subErrors《/span》”: 《span class=“hljs-value”》[ { “《span class=”hljs-attribute“》object《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“bird”《/span》《/span》, “《span class=”hljs-attribute“》field《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“mass”《/span》《/span》, “《span class=”hljs-attribute“》rejectedValue《/span》”: 《span class=“hljs-value”》《span class=“hljs-number”》999999《/span》《/span》, “《span class=”hljs-attribute“》message《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“must be less or equal to 104000”《/span》 《/span》} ] 《/span》} 《/span》} 《/code》《/pre》《h2》Spring Boot 錯(cuò)誤處理《/h2》《p》我們來(lái)探討一些用于異常處理的Spring注解?!?p》《p》《a href=“https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html”》《code》RestController《/code》《/a》是用于REST操作類(lèi)的最基本的注解?!?p》《p》《a href=“https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html”》《code》ExceptionHandler《/code》《/a》這個(gè)Spring注解提供了一種機(jī)制,用來(lái)處理在執(zhí)行程序期間拋出的異常。此注解將作為處理此控制器中拋出的異常的入口點(diǎn)??偠灾?,最常見(jiàn)的方法是在《code》@ControllerAdvice《/code》類(lèi)的方法上使用《code》@ExceptionHandler《/code》,以便將異常處理應(yīng)用于全局或控制器的子集。《/p》《p》《a href=“https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html”》《code》ControllerAdvice《/code》《/a》是Spring 3.2中引入的注解,顧名思義,它是多控制器的“建議”。它使得單個(gè)《code》ExceptionHandler《/code》應(yīng)用于多個(gè)控制器上。這樣我們可以在一個(gè)地方定義如何處理這樣的異常,當(dāng)《code》ControllerAdvice《/code》覆蓋的類(lèi)拋出異常時(shí),這個(gè)處理程序就會(huì)被調(diào)用。受影響的控制器子集可以在《code》@ControllerAdvice《/code》上使用以下選擇器進(jìn)行定義:《code》annotations()《/code》,《code》basePackageClasses()《/code》和《code》basePackages()《/code》。如果沒(méi)有提供選擇器,則《code》ControllerAdvice《/code》將應(yīng)用于全局所有的控制器?!?p》《p》所以,通過(guò)使用《code》@ExceptionHandler《/code》和《code》@ControllerAdvice《/code》,我們可以定義一個(gè)用于處理異常的中心點(diǎn),并將異常包裝在《code》ApiError《/code》對(duì)象中,這比Spring Boot默認(rèn)的錯(cuò)誤處理機(jī)制更好?!?p》《h2》處理異?!?h2》《p》《/p》《center》《img src=“?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240” alt=“Representation of what happens with a successful and failed REST client call” title=“”》《/center》《p》《/p》《p》下一步是創(chuàng)建處理異常的類(lèi)。為了簡(jiǎn)單起見(jiàn),我們稱(chēng)之為《code》RestExceptionHandler《/code》,它必須繼承自Spring Boot的《code》ResponseEntityExceptionHandler《/code》。我們也將從《code》ResponseEntityExceptionHandler《/code》繼承,因?yàn)樗呀?jīng)提供了對(duì)Spring MVC異常的一些基本處理方法,所以,我們將改進(jìn)現(xiàn)有的異常處理手段,并同時(shí)添加針對(duì)新異常的處理。《/p》《p》如果看一下《code》ResponseEntityExceptionHandler《/code》的源代碼,你會(huì)看到有很多方法名為《code》handle******()《/code》,像《code》handleHttpMessageNotReadable()《/code》或《code》handleHttpMessageNotWritable()《/code》。我們來(lái)看看如何對(duì)《code》handleHttpMessageNotReadable()《/code》進(jìn)行擴(kuò)展來(lái)處理《code》HttpMessageNotReadableException《/code》異常。我們只需要在《code》RestExceptionHandler《/code》類(lèi)中重寫(xiě)方法《code》handleHttpMessageNotReadable()《/code》:《/p》《pre class=“prettyprint”》《code class=“l(fā)anguage-java hljs ”》《span class=“hljs-annotation”》@Order《/span》(Ordered.HIGHEST_PRECEDENCE) 《span class=“hljs-annotation”》@ControllerAdvice《/span》 《span class=“hljs-keyword”》public《/span》 《span class=“hljs-class”》《span class=“hljs-keyword”》class《/span》 《span class=“hljs-title”》RestExceptionHandler《/span》 《span class=“hljs-keyword”》extends《/span》 《span class=“hljs-title”》ResponseEntityExceptionHandler《/span》 {《/span》 《span class=“hljs-annotation”》@Override《/span》 《span class=“hljs-keyword”》protected《/span》 ResponseEntity《Object》 《span class=“hljs-title”》handleHttpMessageNotReadable《/span》(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { String error = 《span class=“hljs-string”》“Malformed JSON request”《/span》; 《span class=“hljs-keyword”》return《/span》 buildResponseEntity(《span class=“hljs-keyword”》new《/span》 ApiError(HttpStatus.BAD_REQUEST, error, ex)); } 《span class=“hljs-keyword”》private《/span》 ResponseEntity《Object》 《span class=“hljs-title”》buildResponseEntity《/span》(ApiError apiError) { 《span class=“hljs-keyword”》return《/span》 《span class=“hljs-keyword”》new《/span》 ResponseEntity《》(apiError, apiError.getStatus()); } 《span class=“hljs-comment”》//other exception handlers below《/span》 } 《/code》《/pre》《p》如果拋出一個(gè)《code》HttpMessageNotReadableException《/code》,則錯(cuò)誤消息將是“Malformed JSON request(格式錯(cuò)誤的JSON請(qǐng)求)”,該錯(cuò)誤封裝在《code》ApiError《/code》對(duì)象內(nèi)。下面我們可以看到新的應(yīng)答:《/p》《pre class=“prettyprint”》《code class=“ hljs scilab”》{ 《span class=“hljs-string”》“apierror”《/span》: { 《span class=“hljs-string”》“status”《/span》: 《span class=“hljs-string”》“BAD_REQUEST”《/span》, 《span class=“hljs-string”》“timestamp”《/span》: 《span class=“hljs-string”》“21-07-2017 03:53:39”《/span》, 《span class=“hljs-string”》“message”《/span》: 《span class=“hljs-string”》“Malformed JSON request”《/span》, 《span class=“hljs-string”》“debugMessage”《/span》: 《span class=“hljs-string”》“JSON parse error: Unrecognized token ‘《/span》《span class=”hljs-transposed_variable“》aaa’《/span》: was expecting (《span class=”hljs-string“》‘true’《/span》, 《span class=”hljs-string“》‘false’《/span》 《span class=”hljs-built_in“》or《/span》 《span class=”hljs-string“》‘null’《/span》); nested exception is 《span class=”hljs-transposed_variable“》com.《/span》《span class=”hljs-transposed_variable“》fasterxml.《/span》《span class=”hljs-transposed_variable“》jackson.《/span》《span class=”hljs-transposed_variable“》core.《/span》JsonParseException: Unrecognized token 《span class=”hljs-string“》‘a(chǎn)aa’《/span》: was expecting (《span class=”hljs-string“》‘true’《/span》, 《span class=”hljs-string“》‘false’《/span》 《span class=”hljs-built_in“》or《/span》 《span class=”hljs-string“》‘null’《/span》)\n at 《span class=”hljs-matrix“》[Source: java.io.PushbackInputStream@《span class=”hljs-number“》7《/span》b5e8d8a; line: 《span class=”hljs-number“》4《/span》, column: 《span class=”hljs-number“》17《/span》]《/span》《span class=”hljs-string“》” } } 《/span》《/code》《/pre》《h3》處理自定義異?!?h3》《p》現(xiàn)在,我們來(lái)看看如何創(chuàng)建一個(gè)方法來(lái)處理沒(méi)有在Spring Boot的《code》ResponseEntityExceptionHandler《/code》中聲明的異常?!?p》《p》Spring程序處理數(shù)據(jù)庫(kù)調(diào)用的一個(gè)常見(jiàn)場(chǎng)景是使用庫(kù)類(lèi)通過(guò)id去查找記錄。但是,如果研究一下《code》CrudRepository.findOne()《/code》方法,我們會(huì)發(fā)現(xiàn),如果找不到對(duì)象,它將返回《code》null《/code》。這意味著如果我們的服務(wù)只是調(diào)用這個(gè)方法并直接返回給控制器,那么即使找不到資源,我們也會(huì)得到HTTP返回碼200(OK)。實(shí)際上,正確的方法是返回《a href=“https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html”》HTTP/1.1規(guī)范《/a》中指定的HTTP返回碼404(NOT FOUND)?!?p》《p》為了處理這種情況,我們將創(chuàng)建一個(gè)名為《code》EntityNotFoundException《/code》的自定義異常。它與《code》javax.persistence.EntityNotFoundException《/code》不同,因?yàn)樗峁┑囊恍?gòu)造函數(shù)可以用來(lái)選擇以不同的方式處理《code》javax.persistence《/code》異常。《/p》《p》《/p》《center》《img src=“?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240” alt=“Example of a failed REST call” title=“”》《/center》《p》《/p》《p》也就是說(shuō),我們可以在《code》RestExceptionHandler《/code》類(lèi)中為這個(gè)新創(chuàng)建的《code》EntityNotFoundException《/code》創(chuàng)建一個(gè)《code》ExceptionHandler《/code》。為此,創(chuàng)建一個(gè)名為《code》handleEntityNotFound()《/code》的方法,并使用《code》@ExceptionHandler《/code》對(duì)其進(jìn)行注釋?zhuān)瑢㈩?lèi)對(duì)象《code》EntityNotFoundException.class《/code》傳遞給它。這表示每次拋出《code》EntityNotFoundException《/code》的時(shí)候,Spring應(yīng)該調(diào)用此方法來(lái)處理它。當(dāng)用《code》@ExceptionHandler《/code》注釋一個(gè)方法時(shí),它將接受各種自動(dòng)注入的參數(shù),如《code》WebRequest《/code》、《code》Locale《/code》,以及在《a href=“https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html”》這里《/a》提到的其他參數(shù)。我們將提供異?!禼ode》EntityNotFoundException《/code》本身作為《code》handleEntityNotFound《/code》方法的參數(shù)。《/p》《pre class=“prettyprint”》《code class=“l(fā)anguage-java hljs ”》《span class=“hljs-annotation”》@Order《/span》(Ordered.HIGHEST_PRECEDENCE) 《span class=“hljs-annotation”》@ControllerAdvice《/span》 《span class=“hljs-keyword”》public《/span》 《span class=“hljs-class”》《span class=“hljs-keyword”》class《/span》 《span class=“hljs-title”》RestExceptionHandler《/span》 《span class=“hljs-keyword”》extends《/span》 《span class=“hljs-title”》ResponseEntityExceptionHandler《/span》 {《/span》 《span class=“hljs-comment”》//other exception handlers《/span》 《span class=“hljs-annotation”》@ExceptionHandler《/span》(EntityNotFoundException.class) 《span class=“hljs-keyword”》protected《/span》 ResponseEntity《Object》 《span class=“hljs-title”》handleEntityNotFound《/span》( EntityNotFoundException ex) { ApiError apiError = 《span class=“hljs-keyword”》new《/span》 ApiError(NOT_FOUND); apiError.setMessage(ex.getMessage()); 《span class=“hljs-keyword”》return《/span》 buildResponseEntity(apiError); } } 《/code》《/pre》《p》太好了!我們?cè)凇禼ode》handleEntityNotFound()《/code》方法里將HTTP狀態(tài)代碼設(shè)置為《code》NOT_FOUND《/code》,并使用了新的異常消息。以下是《code》GET /birds/2《/code》的響應(yīng)示例:《/p》《pre class=“prettyprint”》《code class=“ hljs json”》{ “《span class=”hljs-attribute“》apierror《/span》”: 《span class=“hljs-value”》{ “《span class=”hljs-attribute“》status《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“NOT_FOUND”《/span》《/span》, “《span class=”hljs-attribute“》timestamp《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“21-07-2017 04:02:22”《/span》《/span》, “《span class=”hljs-attribute“》message《/span》”: 《span class=“hljs-value”》《span class=“hljs-string”》“Bird was not found for parameters {id=2}”《/span》 《/span》} 《/span》} 《/code》《/pre》《h2》結(jié)論《/h2》《p》對(duì)異常處理的控制非常重要,所以我們需要將這些異常正確映射到《code》ApiError《/code》對(duì)象上,以提供給API客戶(hù)端一些重要的信息,讓它們知道發(fā)生了。接下來(lái)的步驟就是為拋出的異常創(chuàng)建更多的處理方法(帶有@ExceptionHandler的方法)。你可以在《a href=“https://github.com/brunocleite/spring-boot-exception-handling”》GitHub代碼倉(cāng)庫(kù)《/a》中找到更多的示例?!?p》《p》這里另外還有一些資源,可對(duì)本文起到補(bǔ)充作用:《/p》《ul》 《li》Baeldung - 《a href=“http://www.baeldung.com/exception-handling-for-rest-with-spring”》使用Spring對(duì)REST進(jìn)行錯(cuò)誤處理《/a》《/li》 《li》Spring Blog - 《a href=“https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc”》Spring MVC中的異常處理《/a》《/li》 《/ul》
非常好我支持^.^
(0) 0%
不好我反對(duì)
(0) 0%
下載地址
Spring Boot框架錯(cuò)誤處理下載
相關(guān)電子資料下載
- SpringBoot物理線程、虛擬線程、Webflux性能比較 37
- Spring Cloud :打造可擴(kuò)展的微服務(wù)網(wǎng)關(guān) 60
- Pipeline中throwIt的用法 62
- Python怎么使用漫威庫(kù) 62
- 如何實(shí)現(xiàn)RTOS、中間件和芯片廠商API的跟蹤可觀察性? 178
- 深入探討Granite Rapids和Sierra Forest處理器架構(gòu)技術(shù) 20
- 基于OpenVINO Python API部署RT-DETR模型 107
- MaaS,云廠商在打一場(chǎng)“翻身仗” 525
- Nginx常用配置與命令 20
- 愛(ài)立信消費(fèi)者實(shí)驗(yàn)室報(bào)告:差異化的5G連接為運(yùn)營(yíng)商帶來(lái)商機(jī) 230