国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

2021-06-15 11:07流煙默 Java教程

這篇文章主要介紹了SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

【1】springboot的默認錯誤處理

① 瀏覽器訪問

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

請求頭如下:

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

② 使用“postman”訪問

?
1
2
3
4
5
6
7
{
  "timestamp": 1529479254647,
  "status": 404,
  "error": "not found",
  "message": "no message available",
  "path": "/aaa1"
}

請求頭如下:

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

總結:如果是瀏覽器訪問,則springboot默認返回錯誤頁面;如果是其他客戶端訪問,則默認返回json數據。

【2】默認錯誤處理原理

springboot默認配置了許多xxxautoconfiguration,這里我們找errormvcautoconfiguration。

其注冊部分組件如下:

① defaulterrorattributes

?
1
2
3
4
5
@bean
@conditionalonmissingbean(value = errorattributes.class, search = searchstrategy.current)
public defaulterrorattributes errorattributes() {
  return new defaulterrorattributes();
}

跟蹤其源碼如下:

?
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
public class defaulterrorattributes
    implements errorattributes, handlerexceptionresolver, ordered {
 
  private static final string error_attribute = defaulterrorattributes.class.getname()
      + ".error";
 
  @override
  public int getorder() {
    return ordered.highest_precedence;
  }
 
  @override
  public modelandview resolveexception(httpservletrequest request,
      httpservletresponse response, object handler, exception ex) {
    storeerrorattributes(request, ex);
    return null;
  }
 
  private void storeerrorattributes(httpservletrequest request, exception ex) {
    request.setattribute(error_attribute, ex);
  }
 
  @override
  public map<string, object> geterrorattributes(requestattributes requestattributes,
      boolean includestacktrace) {
    map<string, object> errorattributes = new linkedhashmap<string, object>();
    errorattributes.put("timestamp", new date());
    addstatus(errorattributes, requestattributes);
    adderrordetails(errorattributes, requestattributes, includestacktrace);
    addpath(errorattributes, requestattributes);
    return errorattributes;
  }
 
  private void addstatus(map<string, object> errorattributes,
      requestattributes requestattributes) {
    integer status = getattribute(requestattributes,
        "javax.servlet.error.status_code");
    if (status == null) {
      errorattributes.put("status", 999);
      errorattributes.put("error", "none");
      return;
    }
    errorattributes.put("status", status);
    try {
      errorattributes.put("error", httpstatus.valueof(status).getreasonphrase());
    }
    catch (exception ex) {
      // unable to obtain a reason
      errorattributes.put("error", "http status " + status);
    }
  }
 
  private void adderrordetails(map<string, object> errorattributes,
      requestattributes requestattributes, boolean includestacktrace) {
    throwable error = geterror(requestattributes);
    if (error != null) {
      while (error instanceof servletexception && error.getcause() != null) {
        error = ((servletexception) error).getcause();
      }
      errorattributes.put("exception", error.getclass().getname());
      adderrormessage(errorattributes, error);
      if (includestacktrace) {
        addstacktrace(errorattributes, error);
      }
    }
    object message = getattribute(requestattributes, "javax.servlet.error.message");
    if ((!stringutils.isempty(message) || errorattributes.get("message") == null)
        && !(error instanceof bindingresult)) {
      errorattributes.put("message",
          stringutils.isempty(message) ? "no message available" : message);
    }
  }
 
  private void adderrormessage(map<string, object> errorattributes, throwable error) {
    bindingresult result = extractbindingresult(error);
    if (result == null) {
      errorattributes.put("message", error.getmessage());
      return;
    }
    if (result.geterrorcount() > 0) {
      errorattributes.put("errors", result.getallerrors());
      errorattributes.put("message",
          "validation failed for object='" + result.getobjectname()
              + "'. error count: " + result.geterrorcount());
    }
    else {
      errorattributes.put("message", "no errors");
    }
  }
 
  private bindingresult extractbindingresult(throwable error) {
    if (error instanceof bindingresult) {
      return (bindingresult) error;
    }
    if (error instanceof methodargumentnotvalidexception) {
      return ((methodargumentnotvalidexception) error).getbindingresult();
    }
    return null;
  }
 
  private void addstacktrace(map<string, object> errorattributes, throwable error) {
    stringwriter stacktrace = new stringwriter();
    error.printstacktrace(new printwriter(stacktrace));
    stacktrace.flush();
    errorattributes.put("trace", stacktrace.tostring());
  }
 
  private void addpath(map<string, object> errorattributes,
      requestattributes requestattributes) {
    string path = getattribute(requestattributes, "javax.servlet.error.request_uri");
    if (path != null) {
      errorattributes.put("path", path);
    }
  }
 
  @override
  public throwable geterror(requestattributes requestattributes) {
    throwable exception = getattribute(requestattributes, error_attribute);
    if (exception == null) {
      exception = getattribute(requestattributes, "javax.servlet.error.exception");
    }
    return exception;
  }
 
  @suppresswarnings("unchecked")
  private <t> t getattribute(requestattributes requestattributes, string name) {
    return (t) requestattributes.getattribute(name, requestattributes.scope_request);
  }
 
}

即,填充錯誤數據!

② basicerrorcontroller

?
1
2
3
4
5
6
@bean
@conditionalonmissingbean(value = errorcontroller.class, search = searchstrategy.current)
public basicerrorcontroller basicerrorcontroller(errorattributes errorattributes) {
  return new basicerrorcontroller(errorattributes, this.serverproperties.geterror(),
      this.errorviewresolvers);
}

跟蹤其源碼:

?
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
@controller
@requestmapping("${server.error.path:${error.path:/error}}")
public class basicerrorcontroller extends abstracterrorcontroller {
  //產生html類型的數據;瀏覽器發送的請求來到這個方法處理
  @requestmapping(produces = "text/html")
  public modelandview errorhtml(httpservletrequest request,
      httpservletresponse response) {
    httpstatus status = getstatus(request);
    map<string, object> model = collections.unmodifiablemap(geterrorattributes(
        request, isincludestacktrace(request, mediatype.text_html)));
    response.setstatus(status.value());
    //去哪個頁面作為錯誤頁面;包含頁面地址和頁面內容
    modelandview modelandview = resolveerrorview(request, response, status, model);
    return (modelandview == null ? new modelandview("error", model) : modelandview);
  }
  //產生json數據,其他客戶端來到這個方法處理;
  @requestmapping
  @responsebody
  public responseentity<map<string, object>> error(httpservletrequest request) {
    map<string, object> body = geterrorattributes(request,
        isincludestacktrace(request, mediatype.all));
    httpstatus status = getstatus(request);
    return new responseentity<map<string, object>>(body, status);
  }
  //...
}

其中 resolveerrorview(request, response, status, model);方法跟蹤如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class abstracterrorcontroller implements errorcontroller {
protected modelandview resolveerrorview(httpservletrequest request,
      httpservletresponse response, httpstatus status, map<string, object> model) {
      //拿到所有的錯誤視圖解析器
    for (errorviewresolver resolver : this.errorviewresolvers) {
      modelandview modelandview = resolver.resolveerrorview(request, status, model);
      if (modelandview != null) {
        return modelandview;
      }
    }
    return null;
  }
//...
}

③ errorpagecustomizer

?
1
2
3
4
@bean
public errorpagecustomizer errorpagecustomizer() {
  return new errorpagecustomizer(this.serverproperties);
}

跟蹤其源碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
@override
public void registererrorpages(errorpageregistry errorpageregistry) {
  errorpage errorpage = new errorpage(this.properties.getservletprefix()
      + this.properties.geterror().getpath());
  errorpageregistry.adderrorpages(errorpage);
}
//getpath()->go on
  /**
   * path of the error controller.
   */
  @value("${error.path:/error}")
  private string path = "/error";

即,系統出現錯誤以后來到error請求進行處理(web.xml注冊的錯誤頁面規則)。

④ defaulterrorviewresolver

?
1
2
3
4
5
6
7
@bean
@conditionalonbean(dispatcherservlet.class)
@conditionalonmissingbean
public defaulterrorviewresolver conventionerrorviewresolver() {
  return new defaulterrorviewresolver(this.applicationcontext,
      this.resourceproperties);
}

跟蹤其源碼:

?
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class defaulterrorviewresolver implements errorviewresolver, ordered {
 
  private static final map<series, string> series_views;
  //錯誤狀態碼
  static {
    map<series, string> views = new hashmap<series, string>();
    views.put(series.client_error, "4xx");
    views.put(series.server_error, "5xx");
    series_views = collections.unmodifiablemap(views);
  }
  //...
  @override
  public modelandview resolveerrorview(httpservletrequest request, httpstatus status,
      map<string, object> model) {
  // 這里如果沒有拿到精確狀態碼(如404)的視圖,則嘗試拿4xx(或5xx)的視圖
    modelandview modelandview = resolve(string.valueof(status), model);
    if (modelandview == null && series_views.containskey(status.series())) {
      modelandview = resolve(series_views.get(status.series()), model);
    }
    return modelandview;
  }
 
  private modelandview resolve(string viewname, map<string, object> model) {
    //默認springboot可以去找到一個頁面? error/404||error/4xx
    string errorviewname = "error/" + viewname;
    //模板引擎可以解析這個頁面地址就用模板引擎解析
    templateavailabilityprovider provider = this.templateavailabilityproviders
        .getprovider(errorviewname, this.applicationcontext);
    if (provider != null) {
      //模板引擎可用的情況下返回到errorviewname指定的視圖地址
      return new modelandview(errorviewname, model);
    }
    //模板引擎不可用,就在靜態資源文件夾下找errorviewname對應的頁面 error/404.html
    return resolveresource(errorviewname, model);
  }
 
  private modelandview resolveresource(string viewname, map<string, object> model) {
    //從靜態資源文件夾下面找錯誤頁面
    for (string location : this.resourceproperties.getstaticlocations()) {
      try {
        resource resource = this.applicationcontext.getresource(location);
        resource = resource.createrelative(viewname + ".html");
        if (resource.exists()) {
          return new modelandview(new htmlresourceview(resource), model);
        }
      }
      catch (exception ex) {
      }
    }
    return null;
  }

總結如下:

一但系統出現4xx或者5xx之類的錯誤,errorpagecustomizer就會生效(定制錯誤的響應規則),就會來到/error請求,然后被basicerrorcontroller處理返回modelandview或者json。

【3】定制錯誤響應

① 定制錯誤響應頁面

1)有模板引擎的情況下

error/狀態碼–將錯誤頁面命名為 錯誤狀態碼.html 放在模板引擎文件夾里面的error文件夾下,發生此狀態碼的錯誤就會來到 對應的頁面。

我們可以使用4xx和5xx作為錯誤頁面的文件名來匹配這種類型的所有錯誤,精確優先(優先尋找精確的狀態碼.html)。

如下圖所示:

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

頁面能獲取的信息;

timestamp:時間戳
status:狀態碼
error:錯誤提示
exception:異常對象
message:異常消息
errors:jsr303數據校驗的錯誤都在這里

2)沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態資源文件夾下找。

3)以上都沒有錯誤頁面,就是默認來到springboot默認的錯誤提示頁面。

webmvcautoconfiguration源碼如下:

?
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
27
28
29
@configuration
@conditionalonproperty(prefix = "server.error.whitelabel", name = "enabled", matchifmissing = true)
@conditional(errortemplatemissingcondition.class)
protected static class whitelabelerrorviewconfiguration {
 
  private final spelview defaulterrorview = new spelview(
      "<html><body><h1>whitelabel error page</h1>"
          + "<p>this application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
          + "<div id='created'>${timestamp}</div>"
          + "<div>there was an unexpected error (type=${error}, status=${status}).</div>"
          + "<div>${message}</div></body></html>");
 
  @bean(name = "error")
  @conditionalonmissingbean(name = "error")
  public view defaulterrorview() {
    return this.defaulterrorview;
  }
 
  // if the user adds @enablewebmvc then the bean name view resolver from
  // webmvcautoconfiguration disappears, so add it back in to avoid disappointment.
  @bean
  @conditionalonmissingbean(beannameviewresolver.class)
  public beannameviewresolver beannameviewresolver() {
    beannameviewresolver resolver = new beannameviewresolver();
    resolver.setorder(ordered.lowest_precedence - 10);
    return resolver;
  }
 
}

② 定制錯誤響應數據

第一種,使用springmvc的異常處理器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@controlleradvice
public class myexceptionhandler {
 
  //瀏覽器客戶端返回的都是json
  @responsebody
  @exceptionhandler(usernotexistexception.class)
  public map<string,object> handleexception(exception e){
    map<string,object> map = new hashmap<>();
    map.put("code","user.notexist");
    map.put("message",e.getmessage());
    return map;
  }
}

這樣無論瀏覽器還是postman返回的都是json!

第二種,轉發到/error請求進行自適應效果處理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@exceptionhandler(usernotexistexception.class)
public string handleexception(exception e, httpservletrequest request){
   map<string,object> map = new hashmap<>();
   //傳入我們自己的錯誤狀態碼 4xx 5xx
   /**
   * integer statuscode = (integer) request
   .getattribute("javax.servlet.error.status_code");
   */
   request.setattribute("javax.servlet.error.status_code",500);
   map.put("code","user.notexist");
   map.put("message","用戶出錯啦");
   //轉發到/error
   return "forward:/error";
 }

但是此時沒有將自定義 code message傳過去!

第三種,注冊myerrorattributes繼承自defaulterrorattributes(推薦)

從第【2】部分(默認錯誤處理原理)中知道錯誤數據都是通過defaulterrorattributes.geterrorattributes()方法獲取,如下所示:

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

我們可以編寫一個myerrorattributes繼承自defaulterrorattributes重寫其geterrorattributes方法將我們的錯誤數據添加進去。

示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//給容器中加入我們自己定義的errorattributes
@component
public class myerrorattributes extends defaulterrorattributes {
 
  //返回值的map就是頁面和json能獲取的所有字段
  @override
  public map<string, object> geterrorattributes(requestattributes requestattributes, boolean includestacktrace) {
    //defaulterrorattributes的錯誤數據
    map<string, object> map = super.geterrorattributes(requestattributes, includestacktrace);
    map.put("company","springboot");
    //我們的異常處理器攜帶的數據
    map<string,object> ext = (map<string, object>) requestattributes.getattribute("ext", 0);
    map.put("ext",ext);
    return map;
  }
}

異常處理器修改如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@exceptionhandler(usernotexistexception.class)
public string handleexception(exception e, httpservletrequest request){
   map<string,object> map = new hashmap<>();
   //傳入我們自己的錯誤狀態碼 4xx 5xx
   /**
   * integer statuscode = (integer) request
   .getattribute("javax.servlet.error.status_code");
   */
   request.setattribute("javax.servlet.error.status_code",500);
   map.put("code","user.notexist");
   map.put("message","用戶出錯啦");
  //將自定義錯誤數據放入request中
   request.setattribute("ext",map);
   //轉發到/error
   return "forward:/error";
 }

5xx.html頁面代碼如下:

?
1
2
3
4
5
6
7
8
9
10
//...
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
  <h1>status:[[${status}]]</h1>
  <h2>timestamp:[[${timestamp}]]</h2>
  <h2>exception:[[${exception}]]</h2>
  <h2>message:[[${message}]]</h2>
  <h2>ext:[[${ext.code}]]</h2>
  <h2>ext:[[${ext.message}]]</h2>
</main>
//...

瀏覽器測試效果如下:

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

postman測試效果如下:

SpringBoot 錯誤處理機制與自定義錯誤處理實現詳解

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/j080624/article/details/80747669

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 欧美一区二区三区久久久久久桃花 | 久久午夜视频 | 久久精品成人 | 精品少妇一区二区三区在线播放 | 亚洲一区视频在线 | 少妇黄色一级片 | 欧美日韩在线一区二区三区 | 欧美a在线 | 久草热在线 | 精品一区二区三区免费 | 一级黄色免费网站 | 精品第一页| 亚洲精品第一 | 国产在线播放91 | 毛片免费看电影 | 亚洲天天在线观看 | 免费欧美一级 | 国产精品三级久久久久久电影 | 精品成人一区 | 日韩视频一区 | 精品九九 | 中文字幕一区二区三区不卡 | 在线观看成人高清 | 久久免费视频9 | 日韩精品三区 | 天堂中文在线视频 | 日韩黄网 | 激情久久久久 | 日日视频 | 亚洲欧美中文字幕 | 亚洲aⅴ网站 | 国产美女视频自拍 | 日本一区不卡 | 色网站视频| 精品久久久久久久久久久久久久 | 午夜精品一区二区三区在线观看 | 夜夜av| 亚洲视频一区 | 欧美一区二区三区在线播放 | 国产精品久久久久久久久久久久久 | 亚州精品国产 |