做Web應用,請求處理過程中發(fā)生錯誤是非常常見的。Spring Boot提供了一個默認的映射:/error,當處理中拋出異常之后,會轉(zhuǎn)到該請求中處理,并且該請求有一個全局的錯誤頁面用來展示異常內(nèi)容。
選擇一個之前實現(xiàn)過的Web應用(chapter11-5-1 )為基礎(chǔ),啟動該應用,訪問一個不存在的URL,或是修改處理內(nèi)容,直接拋出異常,如:
@RequestMapping("/hello")
@Throws(Exception::class)
fun hello() {
throw Exception("發(fā)生錯誤")
}
注意版本實例修改默認端口,現(xiàn)在為8083,如果想修改為默認的,請修改application.yml文件
server:
port: 8080
此時,可以看到類似下面的報錯頁面,該頁面就是Spring Boot提供的默認error映射頁面。
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Jan 19 10:01:32 CST 2018
There was an unexpected error (type=Internal Server Error, status=500).
????
統(tǒng)一異常處理
雖然,Spring Boot中實現(xiàn)了默認的error映射,但是在實際應用中,上面你的錯誤頁面對用戶來說并不夠友好,我們通常需要去實現(xiàn)我們自己的異常提示。
下面我們以之前的Web應用例子為基礎(chǔ)(chapter11-5-1 ),進行統(tǒng)一異常處理的改造。
創(chuàng)建全局異常處理類:通過使用@ControllerAdvice定義統(tǒng)一的異常處理類,而不是在每個Controller中逐個定義。@ExceptionHandler用來定義函數(shù)針對的異常類型,最后將Exception對象和請求URL映射到error.html中
@ControllerAdvice 注解的類需要增加 @RestController //springboot1.5.7版本,如果不加 這個會報錯 jsonErrorHandler
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.ModelAndView
import javax.servlet.http.HttpServletRequest
/**
* Created by http://quanke.name on 2018/1/10.
*/
@ControllerAdvice
@RestController //springboot1.5.7版本,如果不加 這個會報錯 jsonErrorHandler
class GlobalExceptionHandler {
@ExceptionHandler(value = Exception::class)
@Throws(Exception::class)
fun defaultErrorHandler(req: HttpServletRequest, e: Exception): ModelAndView {
val mav = ModelAndView()
mav.addObject("exception", e)
mav.addObject("url", req.requestURL)
mav.viewName = "error"
return mav
}
}
實現(xiàn)error.html頁面展示:在templates目錄下創(chuàng)建error.html,將請求的URL和Exception對象的message輸出。
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head lang="en">
<meta charset="UTF-8" />
<title>統(tǒng)一異常處理</title>
</head>
<body>
<h1>http://quanke.name Error Handler</h1>
<div th:text="${url}"></div>
<div th:text="${exception.message}"></div>
</body>
</html>
啟動該應用,訪問:http://localhost:8083/hello,可以看到如下錯誤提示頁面。
http://quanke.name Error Handler
http://127.0.0.1:8083/hello
發(fā)生錯誤
通過實現(xiàn)上述內(nèi)容之后,我們只需要在Controller中拋出Exception,當然我們可能會有多種不同的Exception。然后在@ControllerAdvice類中,根據(jù)拋出的具體Exception類型匹配@ExceptionHandler中配置的異常類型來匹配錯誤映射和處理。
返回JSON格式
在上述例子中,通過@ControllerAdvice統(tǒng)一定義不同Exception映射到不同錯誤處理頁面。而當我們要實現(xiàn)RESTful API時,返回的錯誤是JSON格式的數(shù)據(jù),而不是HTML頁面,這時候我們也能輕松支持。
本質(zhì)上,只需在@ExceptionHandler之后加入@ResponseBody,就能讓處理函數(shù)return的內(nèi)容轉(zhuǎn)換為JSON格式。
下面以一個具體示例來實現(xiàn)返回JSON格式的異常處理。
創(chuàng)建統(tǒng)一的JSON返回對象,code:消息類型,message:消息內(nèi)容,url:請求的url,data:請求返回的數(shù)據(jù)
data class ErrorInfo<T>(var code: Int? = null,
var message: String? = "",
var url: String? = "",
var data: T? = null
)
創(chuàng)建一個自定義異常,用來實驗捕獲該異常,并返回json
/**
* Created by http://quanke.name on 2018/1/11.
*/
class QkException(message: String) : Exception(message)
Controller中增加json映射,拋出QkException異常
import name.quanke.kotlin.chaper11_5_3.exception.QkException
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
/**
* Created by http://quanke.name on 2018/1/10.
*/
@Controller
class UserController {
@RequestMapping("/json")
@Throws(QkException::class)
fun json(): String {
throw QkException("發(fā)生錯誤 json")
}
}
為QkException異常創(chuàng)建對應的處理
import name.quanke.kotlin.chaper11_5_3.entity.ErrorInfo
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestController
import javax.servlet.http.HttpServletRequest
/**
* Created by http://quanke.name on 2018/1/10.
*/
@ControllerAdvice
@RestController //springboot1.5.7版本,如果不加 這個會報錯 jsonErrorHandler
class GlobalExceptionHandler {
@ExceptionHandler(value = QkException::class)
@Throws(QkException::class)
fun jsonErrorHandler(req: HttpServletRequest, e: QkException): ErrorInfo<String> {
val r = ErrorInfo<String>()
r.message = e.message
r.code = 1
r.data = "Some Data"
r.url = req.requestURL.toString()
return r
}
啟動應用,訪問:http://localhost:8083/json,可以得到如下返回內(nèi)容:
{
"code": 1,
"message": "發(fā)生錯誤 json",
"url": "http://127.0.0.1:8083/json",
"data": "Some Data"
}
至此,已完成在Spring Boot中創(chuàng)建統(tǒng)一的異常處理,實際實現(xiàn)還是依靠Spring MVC的注解,更多更深入的使用可參考[Spring MVC]的文檔。
參考
源碼
《Spring Boot 與 kotlin 實戰(zhàn)》 專題歡迎關(guān)注