完善的異常處理可以讓客戶端有一個良好的體驗,並且有利於定位出錯原因,幫助更好的解決問題。
SpringBoot 內置了一個 /error 處理,當拋出異常之後,會被轉到這個映射進行處理, 就是常見的 Whitelable Error Page
另外一種就是使用ajax請求,SpringBoot會返回如下的Json格式字符串信息‘’
原理很簡單,SpringBoot默認提供了程序出錯的結果映射路徑/error。這個/error請求是會在BasicErrorController中進行處理,其內部是通過判斷請求頭中的Accept的內容是否是text/html來區分是客戶端瀏覽器(瀏覽器通常默認自動發送請求頭內容Accept:text/html)還是客戶端接口的調用,以此來決定返回視圖還是JSON消息的內容,如下圖是BasicErrorController的底層源碼(在idea中三次按shift鍵將進入底層源碼)
定義一個簡單的error.html頁面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8"/>
<title>error</title>
</head>
<body>
server error
<p th:text="${errorMessage}"/>
</body>
</html>
定義一個全局的GlobalRestExceptionHandler類來進行處理ajax響應和頁面請求響應
/**
* @Description: 全局異常處理,針對ajax響應和頁面請求響應
*/
@RestControllerAdvice
public class GlobalRestExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@ExceptionHandler(Exception.class)
public Object exception(HttpServletRequest reqest, HttpServletResponse response,HandlerMethod handlerMethod, Exception exception) {
Method m = handlerMethod.getMethod();
Class<?> clazz = handlerMethod.getBeanType();
//判斷訪問的url是否爲rest接口請求
boolean isRestReq = (m.getAnnotation(ResponseBody.class)!=null
||clazz.getAnnotation(ResponseBody.class)!=null
||clazz.getAnnotation(RestController.class)!=null);
//判斷訪問的url是否爲ajax請求
boolean isAjax = isAjax(reqest);
if (isAjax||isRestReq) {
logger.error("global exception", exception);
if (exception instanceof VeException) {
return ResultInfo.fail(VeErrorCode.UNKNOWN_EXCEPTION, exception.getMessage());
}
return ResultInfo.fail(VeErrorCode.UNKNOWN_EXCEPTION);
} else {
logger.error("界面請求異常", exception);
ModelAndView mv = new ModelAndView();
if (exception instanceof VeException) {
mv.addObject("errorMessage", exception.getMessage());
mv.setViewName("error");
return mv;
}
mv.addObject("errorMessage", "");
mv.setViewName("error");
return mv;
}
}
/**
* 判斷網絡請求是否爲ajax
*
* @param req
* @return
*/
private boolean isAjax(HttpServletRequest req) {
String contentTypeHeader = req.getHeader("Content-Type");
String acceptHeader = req.getHeader("Accept");
String xRequestedWith = req.getHeader("X-Requested-With");
return (contentTypeHeader != null && contentTypeHeader.contains("application/json"))
|| (acceptHeader != null && acceptHeader.contains("application/json"))
|| "XMLHttpRequest".equalsIgnoreCase(xRequestedWith);
}
}
VeException 中的內容
**
* 全局異常
*/
public class VeException extends RuntimeException {
private String code;
private String message;
public VeException(VeErrorCode errorCode) {
super(errorCode.getCode());
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
VeErrorCode中的內容
public enum VeErrorCode {
UNKNOWN_EXCEPTION("unknown_exception","系統內部錯誤");
private String code;
private String message;
private VeErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
測試:將會出現兩種
ajax請求響應
頁面請求響應
測試成功
版權聲明:轉載請標明博客地址,謝謝!