默認(rèn)情況下,SpringBoot應(yīng)用出現(xiàn)錯誤時,無論是404請求資源不存在還是500程序內(nèi)部錯誤,都將給用戶顯示一個白板頁面,顯然這是不太友好的。

錯誤處理
在SpringBoot中,錯誤的處理需要關(guān)注下面三點
- 指定錯誤頁
- 數(shù)據(jù)驗證錯誤
- 全局異常
指定錯誤頁
默認(rèn)情況下的錯誤頁是無法滿足實際項目需求的,所以通常會通過自定義錯誤頁面來覆蓋“Whitelabel Error Page”默認(rèn)錯誤頁。在傳統(tǒng)的JavaWeb項目當(dāng)中也可以設(shè)置自己的錯誤頁面,具體方式請參考JavaWeb設(shè)置錯誤頁面。
SpringBoot項目當(dāng)中是沒有web.xml文件的,如果要自定義錯誤頁,最好的做法是對于常見的Http錯誤碼都定義相應(yīng)的錯誤頁。只要兩步就能完成SpringBoot項目的指定錯誤頁。
-
在“src/main/view/static”目錄下創(chuàng)建常見的HTTP錯誤碼對應(yīng)的靜態(tài)頁面,用于在發(fā)生相應(yīng)錯誤時的頁面展示。自定義錯誤頁
添加一個錯誤頁的配置類
@Configuration
public class ErrorPageConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new EmbeddedServletContainerCustomizer(){
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage errorPage_400 = new ErrorPage(HttpStatus.BAD_REQUEST,"/error-400.html");
ErrorPage errorPage_404 = new ErrorPage(HttpStatus.NOT_FOUND,"/error-404.html");
ErrorPage errorPage_500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error-500.html");
container.addErrorPages(errorPage_400,errorPage_404,errorPage_500);
}
};
}
}
數(shù)據(jù)驗證錯誤
WEB應(yīng)用下很多場景需要對請求到后臺的數(shù)據(jù)進行校驗,只要涉及到數(shù)據(jù)交互都要假設(shè)用戶的輸入都是惡意的,不能單純的通過前端來對數(shù)據(jù)數(shù)據(jù)校驗而后臺不做校驗,因為前端的數(shù)據(jù)校驗是很容易被繞過的。
SpringBoot程序中可以借助Hibernate Validator對前端參數(shù)進行校驗。假設(shè)我們有個用戶注冊功能,需要對輸入的用戶參數(shù)進行校驗,UserBean定義如下
public class User implements Serializable{
@NotNull(message = "用戶ID不能為空")
@Size(min = 6, max = 12, message = "用戶ID長度為6-12位")
private String uid;
@NotNull(message = "年齡不能為空")
@Digits(integer = 3, message = "年齡必須是合法數(shù)字", fraction = 0)
private Integer age;
@NotNull(message = "薪水不能為空")
@Digits(integer = 10, fraction = 2, message = "薪水格式不對")
private Double salary;
private Date birthday;
@Email(message = "郵箱格式不對")
private String email;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
前端form表單addUser.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>新增用戶</title>
</head>
<body>
<form action="addUser" method="post">
用戶郵箱:<input type="text" name="uid" value="aaa163.com"/><br/>
用戶年齡:<input type="text" name="age" value="16"/><br/>
用戶工資:<input type="text" name="salary" value="92389239.23"/><br/>
用戶生日:<input type="text" name="birthday" value="2010-10-10"/><br/>
<input type="submit" value="提交"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
我們的UserController類實現(xiàn)如下
@Controller
public class UserController {
@RequestMapping(value = "/addUser",method = RequestMethod.GET)
public String addUser(){
return "addUser";
}
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
@ResponseBody
public Object addUser(@Valid User user, BindingResult result){
// 現(xiàn)在表示執(zhí)行的驗證出現(xiàn)錯誤
if (result.hasErrors()) {
// 獲取全部錯誤信息
Iterator<ObjectError> iterator = result.getAllErrors().iterator();
while (iterator.hasNext()) {
// 取出每一個錯誤
ObjectError error = iterator.next();
System.out.println("【錯誤信息】code = " + error.getCode() + ",message = " +
error.getDefaultMessage());
}
return result.getAllErrors();
}else {
return user;
}
}
@InitBinder
public void initBinder(WebDataBinder binder) { // 在本程序里面需要針對于日期格式進行處理
// 首先建立一個可以將字符串轉(zhuǎn)換為日期的工具程序類
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
// 明確的描述此時需要注冊一個日期格式的轉(zhuǎn)化處理程序類
binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
}
}
全局異常
在“指定錯誤頁”中,我們配置了如果應(yīng)用出現(xiàn)內(nèi)部異常的話,程序會跳轉(zhuǎn)到error-500.html頁面,如果我們想在這個頁面中輸出一些錯誤信息的話要怎么辦?這個時候可以單獨定義一個頁面進行錯誤的信息顯示處理,而這個頁面,可以定義在“src/main/view/templates/error.html”,這個頁面里面要求可以輸出一些信息
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>對不起,出現(xiàn)了500錯誤!</h1>
<p th:text="${url}"/>
<p th:text="${exception.message}"/>
<img src="images/timg.jpg"/>
</body>
</html>
那上面定義的${url}和${exception.message}是從哪里將參數(shù)傳遞進來的呢?這需要我們定義一個全局的異常處理類,該類的代碼如下
@ControllerAdvice// 作為一個控制層的切面處理
//@RestControllerAdvice
public class GlobalExceptionHandler {
/*@ExceptionHandler(Exception.class) // 所有的異常都是Exception子類
public Object defaultErrorHandler(HttpServletRequest request,Exception e) {
class ErrorInfo {
private Integer code ;
private String message ;
private String url ;
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 String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
ErrorInfo info = new ErrorInfo() ;
info.setCode(100); // 標(biāo)記一個錯誤信息類型
info.setMessage(e.getMessage());
info.setUrl(request.getRequestURL().toString());
return info ;
}*/
public static final String DEFAULT_ERROR_VIEW = "error"; // 定義錯誤顯示頁,error.html
@ExceptionHandler(Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest request,
Exception e) { // 出現(xiàn)異常之后會跳轉(zhuǎn)到此方法
ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW); // 設(shè)置跳轉(zhuǎn)路徑
mav.addObject("exception", e); // 將異常對象傳遞過去
mav.addObject("url", request.getRequestURL()); // 獲得請求的路徑
return mav;
}
}
全局的異常處理類有兩種寫法:使用@ControllerAdvice或@RestControllerAdvice。它們都是通過AOP代理的方式,捕捉到異常就跳轉(zhuǎn)到自定義的頁面中,并將需要的參數(shù)傳遞到頁面中。示例中注釋的代碼是使用@RestControllerAdvice的寫法,它使用的還是SpringBoot提供的默認(rèn)頁面。
