我們在做Web應用的時候胞谈,請求處理過程中發(fā)生錯誤是非常常見的情況薇宠。Spring Boot提供了一個默認的映射:/error
填具,當處理中拋出異常之后统舀,會轉到該請求中處理,并且該請求有一個全局的錯誤頁面用來展示異常內(nèi)容劳景。
統(tǒng)一異常處理
雖然绑咱,Spring Boot中實現(xiàn)了默認的error
映射,但是在實際應用中枢泰,上面你的錯誤頁面對用戶來說并不夠友好,我們通常需要去實現(xiàn)我們自己的異常提示铝噩。
下面我們以之前的Web應用例子為基礎衡蚂,進行統(tǒng)一異常處理的改造。
創(chuàng)建全局異常處理類
通過使用@ControllerAdvice
定義統(tǒng)一的異常處理類尸昧,而不是在每個Controller中逐個定義档址。@ExceptionHandler
用來定義函數(shù)針對的異常類型宛畦,最后將Exception對象和請求URL映射到error.html中。
package com.pingkeke.rdf.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 全局異常處理類.
*
* 通過使用@ControllerAdvice定義統(tǒng)一的異常處理類玻募,而不是在每個Controller中逐個定義。
* @ExceptionHandler用來定義函數(shù)針對的異常類型一姿,最后將Exception對象和請求URL映射到error.html中
*
*/
@ControllerAdvice
public class GlobalExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
實現(xiàn)error.html頁面展示
在templates目錄下創(chuàng)建error.html七咧,將請求的URL和Exception對象的message輸出。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>統(tǒng)一異常處理</title>
</head>
<body>
<h1>Error Handler</h1>
<div th:text="${url}"></div>
<div th:text="${exception.message}"></div>
</body>
</html>
啟動該應用叮叹,訪問:http://localhost:8080/exception
艾栋,可以看到如下錯誤提示頁面。
Error Handler
http://localhost:8080/exception
發(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頁面睁蕾,這時候我們也能輕松支持苞笨。
本質上债朵,只需在@ExceptionHandler
之后加入@ResponseBody
,就能讓處理函數(shù)return的內(nèi)容轉換為JSON格式瀑凝。
下面以一個具體示例來實現(xiàn)返回JSON格式的異常處理序芦。
創(chuàng)建統(tǒng)一的JSON返回對象
code:消息類型,message:消息內(nèi)容粤咪,url:請求的url谚中,data:請求返回的數(shù)據(jù)
package com.pingkeke.rdf.dto;
/**
* 創(chuàng)建統(tǒng)一的JSON返回對象.
*
* code:消息類型;
* message:消息內(nèi)容;
* url:請求的url;
* data:請求返回的數(shù)據(jù).
*/
public class ErrorInfo<T> {
public static final Integer OK = 0;
public static final Integer ERROR = 100;
private Integer code;
private String message;
private String url;
private T data;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public static Integer getOK() {
return OK;
}
public static Integer getERROR() {
return ERROR;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
創(chuàng)建一個自定義異常,用來實驗捕獲該異常寥枝,并返回json
package com.pingkeke.rdf.exception;
/**
* 自定義異常.
*/
public class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
Controller中增加json映射宪塔,拋出MyException異常
@RequestMapping("/json")
public String json() throws MyException {
throw new MyException("發(fā)生錯誤2");
}
為MyException異常創(chuàng)建對應的處理
@ExceptionHandler(value = MyException.class)
@ResponseBody
public ErrorInfo<String> jsonErrorHandler(HttpServletRequest req, MyException e) throws Exception {
ErrorInfo<String> r = new ErrorInfo<>();
r.setMessage(e.getMessage());
r.setCode(ErrorInfo.ERROR);
r.setData("Some Data");
r.setUrl(req.getRequestURL().toString());
return r;
}
啟動應用,訪問:http://localhost:8080/json囊拜,可以得到如下返回內(nèi)容:
{
"code": 100,
"message": "發(fā)生錯誤2",
"url": "http://localhost:8080/json",
"data": "Some Data"
}
至此某筐,已完成在Spring Boot中創(chuàng)建統(tǒng)一的異常處理,實際實現(xiàn)還是依靠Spring MVC的注解冠跷,更多更深入的使用可參考Spring MVC的文檔南誊。