Spring 異常處理之本地處理
阿新 • • 發佈:2019-02-16
承接上文Spring 異常處理之 HTTP 狀態碼,本文介紹spring異常處理的第二種方式。為什麼說這種異常處理方式叫本地處理,因為該方式是在Controller內部處理該Controller中的方法丟擲的異常。
需要注意的是,這種方式其實還可以細分為3種。具體見程式碼:
- 注意,下面的方法在同一個controller中
/** * 異常處理之 ExceptionHandler 之一 * * 這異常沒有被 ResponseStatus 標註,必須被 handler 捕捉 * * 本類的 conflict 方法捕獲了它,對比下面一對 * * @return 什麼也不返回,總是丟擲異常 */ @RequestMapping("/dataIntegrityViolation") public String throwDataIntegrityViolationException() { throw new DataIntegrityViolationException("ID 重複"); } /** * 異常處理之使用 ExceptionHandler | 這個方法什麼都不做,沒什麼實際應用價值 * * 但是它可以為前端提供豐富的異常資訊 */ @ResponseStatus(value = HttpStatus.CONFLICT, reason = "資料衝突") @ExceptionHandler(DataIntegrityViolationException.class) public void conflict() { // 什麼也不做 } /** * 異常處理之 ExceptionHandler 之二 * * 這異常沒有被 ResponseStatus 標註,必須被 handler 捕捉 * * 本類中的 databaseError 方法捕獲了它,同時,該方法指定了 view,對比上面那一對 * * @return 什麼也不返回,總是丟擲異常 * @throws SQLException 總是丟擲這個異常 */ @RequestMapping("/databaseError") public String throwSqlException() throws SQLException { throw new SQLException("SQL 異常"); } /** * 異常處理之使用 ExceptionHandler | 指定了 view * * 但是這種方式幾乎不能給前端提供有效的異常資訊 * * @param exception 異常物件 * @return 檢視名稱 */ @ExceptionHandler({SQLException.class}) public String databaseError(Exception exception) { logger.info(exception.toString()); return "database.error"; } /** * 異常處理之 ExceptionHandler 之三 * * 這異常沒有被 ResponseStatus 標註,必須被 handler 捕捉 * * 本類中的 handleError 方法捕獲了它,同時,該方法指定了 model 和 view,對比上面那兩對 * * @return 什麼也不返回,總是丟擲異常 */ @RequestMapping("/supportInfoException") public String throwCustomException() { throw new SupportInfoException("出錯了"); } /** * 完全控制 - model 、view 、有用的異常資訊 * * @param req 當前的 HTTP 請求物件. * @param exception 丟擲的異常 - 也就是 {@link SupportInfoException}. * @return 模型和檢視 * @throws Exception 異常 */ @ExceptionHandler(SupportInfoException.class) public ModelAndView handleError(HttpServletRequest req, Exception exception) throws Exception { if (AnnotationUtils.findAnnotation(exception.getClass(), ResponseStatus.class) != null) throw exception; logger.error("Request: " + req.getRequestURI() + " raised " + exception); ModelAndView mav = new ModelAndView(); // 注意這裡,這個 exception 是一個物件 | 而 DefaultErrorAttributes 中的 exception 是異常物件的完全限定名 mav.addObject("exception", exception); mav.addObject("url", req.getRequestURL()); mav.addObject("timestamp", new Date().toString()); mav.addObject("status", 500); mav.setViewName("support.error"); return mav; } // @formatter:off // // 注意:上面的三種異常處理方式的共同特點都是在 controller 內部使用 ExceptionHandler 來處理,我們可以將之稱為"本地異常處理" // // @formatter:on
解釋一下程式碼:我們在控制器的三個方法中丟擲異常三個,然後使用對應的異常處理方法進行處理,這裡的關鍵是@ExceptionHandler這個註解,正是它將異常捕獲,然後在異常處理方法中進行處理。
- 從上面的程式碼中可以看出,第一種方式沒有指定錯誤頁面(使用預設的),而第二種和第三種方式都指定了錯誤頁面,下面是三個異常頁面
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Title</title> <link th:href="@{webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet"/> </head> <body> <h2>Spring Boot </h2> <h3> 需要注意的是:在實際的開發中,絕對不應該向使用者展示 Java 異常 </h3> <!-- 下面這些關鍵字是在 org.springframework.boot.autoconfigure.web.DefaultErrorAttributes 中定義的 --> <p th:if="${exception}"> <b>異常物件的型別:</b> <span th:text="${exception}">exception type ...</span> </p> <p th:if="${timestamp}"> <b>發生時間:</b> <span th:text="${timestamp}">timestamp ...</span> </p> <p th:if="${status}"> <b>響應狀態碼:</b> <span th:text="${status}">status code ...</span> <span th:if="${error}" th:text="'('+${error}+')'">error ...</span> </p> <p th:if="${message} and ${message.length() != 0}"> <b>錯誤原因:</b> <span th:if="${message} and ${message.length() != 0}" th:text="${message}">message ...</span> </p> <p th:if="${path}"> <b>請求路徑:</b> <span th:text="${path}">path ...</span> </p> </body> </html>
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Title</title> <link th:href="@{webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet"/> </head> <body> <h2>DataBase 錯誤頁面</h2> <h3> 需要注意的是:在實際的開發中,絕對不應該向使用者展示 Java 異常 </h3> <h3> 該方式幾乎不能為前端提供有效的異常資訊 </h3> <!-- 下面這些關鍵字是在 org.springframework.boot.autoconfigure.web.DefaultErrorAttributes 中定義的 --> <p th:if="${exception}"> <b>異常物件的型別:</b> <span th:text="${exception}">exception type ...</span> </p> <p th:if="${timestamp}"> <b>發生時間:</b> <span th:text="${timestamp}">timestamp ...</span> </p> <p th:if="${status}"> <b>響應狀態碼:</b> <span th:text="${status}">status code ...</span> <span th:if="${error}" th:text="'('+${error}+')'">error ...</span> </p> <p th:if="${message} and ${message.length() != 0}"> <b>錯誤原因:</b> <span th:if="${message} and ${message.length() != 0}" th:text="${message}">message ...</span> </p> <p th:if="${path}"> <b>請求路徑:</b> <span th:text="${path}">path ...</span> </p> </body> </html>
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Title</title>
<link th:href="@{webjars/bootstrap/css/bootstrap.min.css}" rel="stylesheet"/>
</head>
<body>
<h1>Support Friendly Error Page</h1>
<!-- As we are using Thymeleaf, you might consider using
${#httpServletRequest.requestURL}. But that returns the path
to this error page. Hence we explicitly add the url to the
Model in some of the example code. -->
<p th:if="${url}">
<b>請求地址:</b> <span th:text="${url}">Page URL</span>
</p>
<!-- 自定義的,這裡的 exception 是一個物件 -->
<p th:if="${exception}">
<b>錯誤訊息:</b>
<span th:text="${exception.message}">exception message ...</span>
</p>
<p th:if="${timestamp}">
<b>發生時間:</b>
<span th:text="${timestamp}">Timestamp</span>
</p>
<p th:if="${status}">
<b>響應狀態碼:</b>
<span th:text="${status}">status-code</span>
<span th:if="${error}" th:text="'('+${error}+')'">error ...</span>
</p>
</body>
</html>
-
最後,通過瀏覽器檢視一下
-
參考