Spring Boot 與 Kotlin Web應用的統(tǒng)一異常處理

做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)注

全科龍婷
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容