SpringBoot項目中自定義404頁面

1html

錯誤處理有原理分析git

使用SpringBoot建立的web項目中,當咱們請求的頁面不存在(http狀態碼爲404),或者服務器發生異常(http狀態碼通常爲500)時,SpringBoot就會給咱們返回錯誤信息。web

也就是說,在SpringBoot的web項目中,會自動建立一個/error的錯誤接口,來返回錯誤信息。可是針對不一樣的訪問方式,會有如下兩種不一樣的返回信息。這主要取決於你訪問時的http頭部信息的Accept這個值來指定你能夠接收的類型有哪些json

  • 使用瀏覽器訪問時的頭信息及其返回結果後端

Accept: text/html

  • 使用其餘設備,如手機客戶端等訪問時頭部信息及其返回結果(通常是在先後端分離的架構中)設計模式

Accept: */*


2瀏覽器

進行錯誤處理服務器

處理異常主要有兩種方式:微信

1數據結構

使用SpringBoot的自動配置原理

    SpringBoot自動配置了一個類ErrorMvcAutoConfiguration來處理處理異常,有興趣的能夠去看一下,而後在這個類中定義一個錯誤的BasicErrorController類,主要代碼有以下:

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {

/**
 * 錯誤的頁面響應
 */

   @RequestMapping(produces = {"text/html"})
   public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
       HttpStatus status = this.getStatus(request);
       Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
       response.setStatus(status.value());
    // 獲得一個modelAndView對象
       ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
       return modelAndView != null ? modelAndView : new ModelAndView("error", model);
  }

 /**
  * 錯誤的json響應
  */

   @RequestMapping
   public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
       HttpStatus status = this.getStatus(request);
       if (status == HttpStatus.NO_CONTENT) {
         return new ResponseEntity(status);
      } else {
         Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
         return new ResponseEntity(body, status);
      }
  }
}


多的代碼就不深究了,感興趣的能夠去看一下。上邊的代碼也就是說,針對不一樣的請求方式,會返回不一樣的結果,其關鍵在於@RequestMapping註解的produces = {"text/html"}屬性上

定製錯誤頁面,如40四、500等。
  • 有模板引擎的狀況(能夠用於渲染頁面)

項目中使用的了模板引擎,如:thymeleaf 、freemarker等做爲頁面的渲染時。在templates建立/error文件夾並添加錯誤的狀態碼對應的.html文件,以下圖:

這裏的404和500就是肯定的錯誤狀態碼,而4xx表示其餘的4開頭的錯誤,如400,401等。固然能夠爲每個狀態碼都設置對應的錯誤頁面,可是這樣作,並無什麼好處,因此就直接使用4xx.html這樣的泛指代替了。

能夠在咱們錯誤頁面中獲取到以下信息(就是ModelAndView對象中的內容):

細心的小夥伴會發現,這個其實就是當你用手機請求時返回的json內容

好比:在代碼中加入上邊信息,而後在在後端寫一個錯誤代碼:

@RequestMapping("haserror")
@ResponseBody 
public Object myError(){
 int i =10/0;
 return "something is error";
}


這是一個錯誤頁面:
<ul> 
   <li>錯誤狀態碼:[[${status}]]</li> 
   <li>錯誤消息:[[${error}]]</li> 
   <li>異常對象:[[${exception}]]</li> 
   <li>異常消息:[[${message}]]</li> 
   <li>當前時間:[[${timestamp}]]</li> 
</ul>

  • 沒有模板引擎的狀況

當項目中沒有使用模板引擎的時候,就將整個error文件夾移到static文件夾下就能夠了。

不過此時並不能獲取上邊的那些信息了,由於這本就是靜態資源,沒有模板引擎進行渲染

直接返回對應的json串
這個並無什麼好說的,返回的就是一個json字符串。 格式以下:
{
"timestamp": "2020-04-22T16:13:37.506+0000",
"status": 500,
"error": "Internal Server Error",
"message": "/ by zero",
"path": "/hello/haserror",
"reason": "完了,你寫的代碼又產生了一次線上事故" 
}
自定義頁面錯誤信息和返回的JSON

這纔是最重要的內容,由於這個信息不只是作爲json返回的,也是能夠在上邊的錯誤頁面中拿到,也能夠直接返回一個json。其實也很簡單,就是在Spring容器中添加一個ErrorAttributes對象就能夠了,這裏我選擇繼承它的一個子類。

@Component 
public class MyErrorAttributes extends DefaultErrorAttributes {
   @Override 
   public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
     //調用父類的方法,會自動獲取內置的那些屬性,若是你不想要,能夠不調用這個
     Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);

     //添加自定義的屬性
     errorAttributes.put("reason","完了,你寫的代碼又產生了一次線上事故");
     // 你能夠看一下這個方法的參數webRequest這個對象,我相信你確定能發現好東西

     return errorAttributes;
  }
}

這就能夠了,用兩種請求方式分別測試一個咱們的這個自定義屬性是否可用:

2

使用AOP的異常通知進行處理(推薦)

    它的原理就是獲取一個全局的異常通知,而後進行處理。咱們只須要在項目中寫下邊代碼就能夠了(其實上邊也只是寫了一個自定義異常信息的類)

若是對AOP有問題的小夥伴能夠在後臺回覆Spring在教程中查看SpringAOP全系列文章

@ControllerAdvice
public class ErrroAcvice {

   /**
    * 全局捕獲異常的切面類
    * @param request 請求對象,可不傳
    * @param response 響應對象,可不傳
    * @param e 異常類(這個要和你當前捕獲的異常類是同一個)
    */

   @ExceptionHandler(Exception.class) //也能夠只對一個類進行捕獲
   public void errorHandler(HttpServletRequest request,         HttpServletResponse response,Exception e){
    /*
     * You can do everything you want to do
        * 這裏你拿到了request和response對象,你能夠作任何你想作的事
        * 好比:
        *1.用request從頭信息中拿到Accept來判斷是請求方可接收的類型從而進行第一個方法的判斷
        *2.若是你也想返回一個頁面,使用response對象進行重定向到本身的錯誤頁面就能夠了
        * 3.你甚至還拿到了異常對象
     */

     
      String accept = request.getHeader("Accept");
      // 根據這個字符串來判斷作出什麼響應
     
      try {
           response.setStatus(500);
         response.getWriter().write("hello");
      } catch (IOException ex) {
         ex.printStackTrace();
      } 
  }
}


總結與對比

    第一種方法,就是在當前項目中放置一些錯誤狀態碼的頁面讓SpringBoot去查找。也支持自定義返回的錯誤信息

    第二種方法,就是直接使用AOP的思想,進行異常通知處理,自由性很大。

    我我的建議使用第二種方法,由於自由度很高,能夠根據本身的業務邏輯進行隨時改變,並且還有一個很大的用處。下一篇文章會有個很好的例子

    使用了第二種方式後,經過第一種方式放置的錯誤頁面和自定義錯誤信息所有失效


沒代碼,說什麼都是瞎扯


關注公衆號後臺回覆 2000 獲取 


10分鐘入門SpringSecurity的使用

2020-04-16

Gateway與SpringSecuriy結合進行

2020-04-14


微服務

設計模式

數據結構

關注我 有好貨

本文分享自微信公衆號 - 小魚與Java(Fish_Java)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索