一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語(yǔ)言|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

2021-07-14 15:21趙俊 Java教程

這篇文章主要給大家介紹了關(guān)于Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

之前一篇文章介紹了基本的統(tǒng)一異常處理思路: spring mvc/boot 統(tǒng)一異常處理最佳實(shí)踐.

上篇文章也有許多人提出了一些問(wèn)題:

  • 如何區(qū)分 ajax 請(qǐng)求和普通頁(yè)面請(qǐng)求, 以分別返回 json 錯(cuò)誤信息和錯(cuò)誤頁(yè)面.
  • 如何結(jié)合 http 狀態(tài)碼進(jìn)行統(tǒng)一異常處理.

今天這篇文章就主要來(lái)講講這些, 以及其他的一些拓展點(diǎn).

區(qū)分請(qǐng)求方式

其實(shí) spring boot 本身是內(nèi)置了一個(gè)異常處理機(jī)制的, 會(huì)判斷請(qǐng)求頭的參數(shù)來(lái)區(qū)分要返回 json 數(shù)據(jù)還是錯(cuò)誤頁(yè)面. 源碼為: org.springframework.boot.autoconfigure.web.servlet.error.basicerrorcontroller, 他會(huì)處理 /error 請(qǐng)求. 核心處理代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@requestmapping(
 produces = {"text/html"}
)
// 如果請(qǐng)求頭是 text/html, 則找到錯(cuò)誤頁(yè)面, 并返回
public modelandview errorhtml(httpservletrequest request, httpservletresponse response) {
 // 1. 獲取 http 錯(cuò)誤狀態(tài)碼
 httpstatus status = this.getstatus(request);
 // 2. 調(diào)用 geterrorattributes 獲取響應(yīng)的 map 結(jié)果集.
 map<string, object> model = collections.unmodifiablemap(this.geterrorattributes(request, this.isincludestacktrace(request, mediatype.text_html)));
 // 3. 設(shè)置響應(yīng)頭的狀態(tài)碼
 response.setstatus(status.value());
 // 4. 獲取錯(cuò)誤頁(yè)面的路徑
 modelandview modelandview = this.resolveerrorview(request, response, status, model);
 return modelandview != null ? modelandview : new modelandview("error", model);
}
 
@requestmapping
@responsebody
public responseentity<map<string, object>> error(httpservletrequest request) {
 // 調(diào)用 geterrorattributes 獲取響應(yīng)的 map 結(jié)果集.
 map<string, object> body = this.geterrorattributes(request, this.isincludestacktrace(request, mediatype.all));
 // 獲取 http 錯(cuò)誤狀態(tài)碼
 httpstatus status = this.getstatus(request);
 // 返回給頁(yè)面 json 信息.
 return new responseentity(body, status);
}

這兩個(gè)方法的共同點(diǎn)是: 他們都調(diào)用了 this.geterrorattributes(…) 方法來(lái)獲取響應(yīng)信息.

然后來(lái)看看他默認(rèn)情況下對(duì)于 ajax 請(qǐng)求和 html 請(qǐng)求, 分別的返回結(jié)果是怎樣的:

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

對(duì)于返回錯(cuò)誤頁(yè)面, 其中還調(diào)用了一個(gè)非常重要的方法: this.resolveerrorview(...) 方法, 源碼我就不帶大家看了, 他的作用就是根據(jù) http 狀態(tài)碼來(lái)去找錯(cuò)誤頁(yè)面, 如 500 錯(cuò)誤會(huì)去找 /error/500.html, 403 錯(cuò)誤回去找 /error/403.html, 如果找不到則再找 /error/4xx.html 或 /error/5xx.html 頁(yè)面. 還找不到的話, 則會(huì)去找 /error.html 頁(yè)面, 如果都沒(méi)有配置, 則會(huì)使用 spring boot 默認(rèn)的頁(yè)面. 即:

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

看到這里, 應(yīng)該就清楚了, 我們主要需要做四件事:

  • 發(fā)送異常后, 重定向到 basicerrorcontroller 來(lái)處理 (既然spring boot 都已經(jīng)寫(xiě)好了區(qū)分請(qǐng)求的功能, 我們就不必要再寫(xiě)這些判斷代碼了)
  • 自定義 http 錯(cuò)誤狀態(tài)碼
  • 他返回的信息格式可能不是我們想要的, 所以必須要改造 geterrorattributes(...) 方法, 以自定義我們向頁(yè)面返回的數(shù)據(jù). (自定義錯(cuò)誤信息)
  • 創(chuàng)建我們自己的 /error/4xx.html 或 /error/5xx.html 等頁(yè)面, (自定義錯(cuò)誤頁(yè)面)

basicerrorcontroller

第一點(diǎn)很簡(jiǎn)單, basicerrorcontroller 他處理 /error 請(qǐng)求, 我們只需要將頁(yè)面重定向到 /error 即可, 在 controlleradvice 中是這樣的:

?
1
2
3
4
5
6
7
8
9
@controlleradvice
public class webexceptionhandler {
 
 @exceptionhandler
 public string methodargumentnotvalid(bindexception e) {
 // do something
 return "/error";
 }
}

自定義 http 錯(cuò)誤狀態(tài)碼

我們來(lái)看下 this.getstatus(request); 的源碼, 看他原來(lái)時(shí)如何獲取錯(cuò)誤狀態(tài)碼的:

?
1
2
3
4
5
6
7
8
9
10
11
12
protected httpstatus getstatus(httpservletrequest request) {
 integer statuscode = (integer)request.getattribute("javax.servlet.error.status_code");
 if (statuscode == null) {
 return httpstatus.internal_server_error;
 } else {
 try {
  return httpstatus.valueof(statuscode);
 } catch (exception var4) {
  return httpstatus.internal_server_error;
 }
 }
}

簡(jiǎn)單來(lái)說(shuō)就是從 request 域中獲取 javax.servlet.error.status_code 的值, 如果為 null 或不合理的值, 都返回 500. 既然如何在第一步, 重定向到 /error 之前將其配置到 request 域中即可, 如:

?
1
2
3
4
5
6
7
8
9
10
@controlleradvice
public class webexceptionhandler {
 
 @exceptionhandler
 public string methodargumentnotvalid(bindexception e, httpservletrequest request) {
 request.setattribute("javax.servlet.error.status_code", 400);
 // do something
 return "forward:/error";
 }
}

自定義錯(cuò)誤信息

也就是 geterrorattributes 方法, 默認(rèn)的代碼是這樣的:

?
1
2
3
4
5
6
7
8
public map<string, object> geterrorattributes(webrequest webrequest, boolean includestacktrace) {
 map<string, object> errorattributes = new linkedhashmap();
 errorattributes.put("timestamp", new date());
 this.addstatus(errorattributes, webrequest);
 this.adderrordetails(errorattributes, webrequest, includestacktrace);
 this.addpath(errorattributes, webrequest);
 return errorattributes;
}

他獲取了時(shí)間戳, 錯(cuò)誤狀態(tài)碼, 錯(cuò)誤信息, 錯(cuò)誤路徑等信息, 和我們之前看到默認(rèn)的返回內(nèi)容是一致的:

?
1
2
3
4
5
6
7
{
 "timestamp": "2019-01-27t07:08:30.011+0000",
 "status": 500,
 "error": "internal server error",
 "message": "/ by zero",
 "path": "/user/index"
}

同樣的思路, 我們將錯(cuò)誤信息也放到 request 域中, 然后在 geterrorattributes 中從 request 域中獲取:

?
1
2
3
4
5
6
7
8
9
10
11
12
@controlleradvice
public class webexceptionhandler {
 
 @exceptionhandler
 public string methodargumentnotvalid(bindexception e, httpservletrequest request) {
 request.setattribute("javax.servlet.error.status_code", 400);
 request.setattribute("code", 1);
 request.setattribute("message", "參數(shù)校驗(yàn)失敗, xxx");
 // do something
 return "forward:/error";
 }
}

再繼承 defaulterrorattributes 類(lèi), 重寫(xiě) geterrorattributes 方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//@component
public class mydefaulterrorattributes extends defaulterrorattributes {
 
 @override
 //重寫(xiě) geterrorattributes方法-添加自己的項(xiàng)目數(shù)據(jù)
 public map<string, object> geterrorattributes(webrequest webrequest,
       boolean includestacktrace) {
 map<string, object> map = new hashmap<>();
 // 從 request 域中獲取 code
 object code = webrequest.getattribute("code", requestattributes.scope_request);
 // 從 request 域中獲取 message
 object message = webrequest.getattribute("message", requestattributes.scope_request);
 map.put("code", code);
 map.put("message", message);
 return map;
 }
}

自定義錯(cuò)誤頁(yè)面

我們遵循 springboot 的規(guī)則, 在 /error/ 下建立 400.html, 500.html 等頁(yè)面細(xì)粒度的錯(cuò)誤, 并配置一個(gè) /error.html 用來(lái)處理細(xì)粒度未處理到的其他錯(cuò)誤.

/error/400.html

?
1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="utf-8">
 <title>400</title>
</head>
<body>
 <h1>400</h1>
 <h1 th:text="$[code]"></h1>
 <h1 th:text="${message}"></h1>
</body>
</html>

/error/500.html

?
1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="utf-8">
 <title>500</title>
</head>
<body>
 <h1>500</h1>
 <h1 th:text="$[code]"></h1>
 <h1 th:text="${message}"></h1>
</body>
</html>

/error.html

?
1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="utf-8">
 <title>系統(tǒng)出現(xiàn)了錯(cuò)誤</title>
</head>
<body>
 <h1>error page</h1>
 <h1 th:text="$[code]"></h1>
 <h1 th:text="${message}"></h1>
</body>
</html>

測(cè)試效果

到此位置, 大功告成, 然后來(lái)創(chuàng)造一個(gè)異常來(lái)測(cè)試一下效果:

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

Spring Boot統(tǒng)一異常處理最佳實(shí)踐(拓展篇)

前端 error 處理

現(xiàn)在使用了 http 狀態(tài)碼, 所以 ajax 請(qǐng)求出現(xiàn)錯(cuò)誤后, 需要在每個(gè) ajax 請(qǐng)求方法中都寫(xiě) error: function() {} 方法, 甚至麻煩. 好在 jquery 為我們提供了全局處理 ajax 的 error 結(jié)果的方法 ajaxerror() :

?
1
2
3
4
5
$(document).ajaxerror(function(event, response){
 console.log("錯(cuò)誤響應(yīng)狀態(tài)碼: ",response.status);
 console.log("錯(cuò)誤響應(yīng)結(jié)果: ",response.responsejson);
 alert("an error occurred!");
});

結(jié)語(yǔ)

回顧一下講到的這些內(nèi)容:

  • 理解 springboot 默認(rèn)提供的 basicerrorcontroller
  • 自定義 http 錯(cuò)誤狀態(tài)碼, (通過(guò) request 域的 javax.servlet.error.status_code 參數(shù))
  • 自定義錯(cuò)誤信息, (將我們自定義的錯(cuò)誤信息放到 request 域中, 并重寫(xiě) defaulterrorattributes 的 geterrorattributes 方法, 從 request 域中獲取這些信息).
  • 自定義錯(cuò)誤頁(yè)面, (根據(jù) springboot 查找錯(cuò)誤頁(yè)面的邏輯來(lái)自定義錯(cuò)誤頁(yè)面: /error/500.html, /error/400.html, /error.html)

可以自己根據(jù)文章一步一步走一遍, 或者看我寫(xiě)好的演示項(xiàng)目先看看效果, 總是動(dòng)手實(shí)踐, 而不是收藏文章并封存。

演示項(xiàng)目地址:https://github.com/zhaojun1998/exception-handler-demo

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:http://www.zhaojun.im/springboot-exception-expand/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产成人亚洲精品一区二区在线看 | 金牛网155755水心论坛黄大父母 | 日韩精品欧美激情国产一区 | 护士的小嫩嫩好紧好舒服 | 交换朋友夫妇3中文字幕 | 掰开逼操| 鬼吹灯之天星术免费观看 | 特级毛片免费视频观看 | 18未年禁止免费观看 | 四虎国产精品免费久久麻豆 | 韩国三级hd中文字幕李采潭 | 欧美精品久久久久久久影视 | yin娃sao货调教情趣用品店 | 亚洲欧美日韩天堂 | 免费精品国产在线观看 | 欧美第十页 | 国产性做久久久久久 | 九9热这里只有真品 | 婷婷伊人综合亚洲综合网 | 亚洲人成网站在线观看播放青青 | 果冻传媒天美传媒乌鸦传媒 | 久久人妻熟女中文字幕AV蜜芽 | 色播艾小青国产专区在线播放 | 99九九成人免费视频精品 | 亚洲 欧美 偷自乱 图片 | 日本一卡=卡三卡免费 | 亚洲va久久久久 | 小小水蜜桃3视频在线观看 小鸟酱喷水 | 国产馆精品推荐在线观看 | 欧美日韩一区二区三区久久 | 精品亚洲欧美中文字幕在线看 | 无颜之月全集免费观看 | 嗯啊好大视频 | 1717国产精品视频免费 | 午夜国产视频 | 九九热视频 这里有精品 | tolove第一季动画在线看 | 日本免费播放 | 日本哺乳期网站xxxx | 我的美女奴隶 | 亚洲 欧美 日韩 国产 视频 |