SpringBoot錯誤處理

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


SpringBoot出現(xiàn)錯誤時默認(rèn)顯示的頁面

錯誤處理

在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項目的指定錯誤頁。

  1. 在“src/main/view/static”目錄下創(chuàng)建常見的HTTP錯誤碼對應(yīng)的靜態(tài)頁面,用于在發(fā)生相應(yīng)錯誤時的頁面展示。
    自定義錯誤頁
  2. 添加一個錯誤頁的配置類

@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)頁面。

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

相關(guān)閱讀更多精彩內(nèi)容

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