1. 程式人生 > >SpringBoot系列五:SpringBoot錯誤處理(資料驗證、處理錯誤頁、全域性異常)

SpringBoot系列五:SpringBoot錯誤處理(資料驗證、處理錯誤頁、全域性異常)

1、概念:

SpringBoot 錯誤處理

2、具體內容

在之前的程式裡面如果一旦出現了錯誤之後就會出現一堆的大白板,這個白板會有一些錯誤資訊(雖然這些錯誤資訊你可能 看不懂,但是這些錯誤資訊依然要告訴給使用者)。在 SpringBoot 裡面針對於錯誤的處理一共提供有三種方式:資料驗證錯誤、錯誤 頁指派以及全域性異常的處理。

2.1、資料驗證

現在假設說要進行表單資訊提交,肯定需要有一個表單,而後這個表單要將資料提交到 VO 類中,所以現在的基本實現如下:

1、 建立一個 Member.java 的 VO 類:

package cn.study.microboot.vo;

import java.io.Serializable;
import java.util.Date;

@SuppressWarnings("serial")
public class Member implements Serializable {
    private String mid ;
    private Integer age ;
    private Double salary ;
    private Date birthday ;
    public String getMid() {
        return mid;
    }
    public void setMid(String mid) {
        this.mid = mid;
    }
    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;
    }
    @Override
    public String toString() {
        return "Member [mid=" + mid + ", age=" + age + ", salary=" + salary
                + ", birthday=" + birthday + "]";
    }
}

2、 由於此時的程式之中需要進行日期的轉換處理操作,那麼就需要為其做一個轉換處理的格式配置,修改 AbstractBaseController 類,追加如下的轉換操作方法繫結:

@InitBinder
    public void initBinder(WebDataBinder binder) {    // 在本程式裡面需要針對於日期格式進行處理
        // 首先建立一個可以將字串轉換為日期的工具程式類
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
        // 明確的描述此時需要註冊一個日期格式的轉化處理程式類
        binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
    }

3、 建立一個 MemberController 程式類,負責實現 Member 的控制層處理操作。

package cn.study.microboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.study.microboot.util.controller.AbstractBaseController;
import cn.study.microboot.vo.Member;

@Controller
public class MemberController extends AbstractBaseController {
    @RequestMapping(value = "/addPre", method = RequestMethod.GET)
    public String addPre() {    // 增加前的準備操作路徑
        return "member_add" ; 
    }
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public Object add(Member vo) {    // 增加前的準備操作路徑
        return vo ; 
    }
}

4、 編寫一個頁面進行使用者的表單填寫(在 src/main/view/templates 下建立):member_add.html;

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>SpringBoot模版渲染</title>
    <link rel="icon" type="image/x-icon" href="/images/study.ico"/>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
    <form action="add" method="post">
        使用者郵箱:<input type="text" name="mid" value="[email protected]"/><br/>
        使用者年齡:<input type="text" name="age" value="18"/><br/>
        使用者工資:<input type="text" name="salary" value="1000"/><br/>
        使用者生日:<input type="text" name="birthday" value="2010-10-10"/><br/>
        <input type="submit" value="提交"/>
        <input type="reset" value="重置"/>
    </form>
</body>
</html>

5、 此時的程式碼只是一個最為普通的處理操作,但是這個時候對於該程式也是存在有如下問題的:

· 如果某些資料沒有輸入,則內容是 null,如果要進行嚴格控制,這些 null 不應該存在;

· 某些資料需要進行格式驗證,例如:使用者名稱應該是郵箱,這個的資訊應該進行郵箱驗證;

所以現在如果要想進行這些的驗證,SpringBoot 裡面有預設的支援,只不過這種支援未必是最好的,在 SpringBoot 裡面為了 方便使用者編寫驗證專門提供有一個 hibernate-validation.jar 工具包,這個工具包是由 hibernate 開發框架提供的。

6、 如果要想進行驗證,那麼首先要解決的問題就必須是錯誤的提示資訊問題,而在 SpringBoot 裡面對於錯誤資訊的儲存,都要 求其儲存在 ValidationMessages.properties 檔案,在“src/main/resources”目錄中建立此檔案;

member.mid.notnull.error=使用者名稱不允許為空!
member.mid.email.error=使用者名稱的註冊必須輸入正確的郵箱!
member.mid.length.error=使用者名稱的格式錯誤!
member.age.notnull.error=年齡不允許為空
member.age.digits.error=年齡必須是合法數字!
member.salary.notnull.error=工資不允許為空!
member.salary.digits.error=工資必須是合法數字!
member.birthday.notnull.error=生日不允許為空!

 提示:你一個表單就需要編寫這麼多的配置項,那麼如果要有幾百個表單呢?這樣的配置項太可怕了,所以最好的資料檢測還是利 用攔截器處理最合適。

 7、 修改 Member.java 程式類追加驗證的處理方式:

package cn.study.microboot.vo;

import java.io.Serializable;
import java.util.Date;

import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;


@SuppressWarnings("serial")
public class Member implements Serializable {
    @NotNull(message="{member.mid.notnull.error}")
    @Email(message="{member.mid.email.error}")
    @Length(min=6,message="{member.mid.length.error}")
    private String mid ;
    @NotNull(message="{member.age.notnull.error}")
    @Digits(integer=3,fraction=0,message="{member.age.digits.error}")
    private Integer age ;
    @NotNull(message="{member.salary.notnull.error}")
    @Digits(integer=20,fraction=2,message="{member.salary.digits.error}")
    private Double salary ;
    @NotNull(message="{member.birthday.notnull.error}")
    private Date birthday ;
    public String getMid() {
        return mid;
    }
    public void setMid(String mid) {
        this.mid = mid;
    }
    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;
    }
    @Override
    public String toString() {
        return "Member [mid=" + mid + ", age=" + age + ", salary=" + salary
                + ", birthday=" + birthday + "]";
    }
}

 8、 修改 MemberController 類中的 add()方法來觀察錯誤資訊的顯示:

package cn.study.microboot.controller;

import java.util.Iterator;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.study.microboot.util.controller.AbstractBaseController;
import cn.study.microboot.vo.Member;

@Controller
public class MemberController extends AbstractBaseController {
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public Object add(@Valid Member vo, BindingResult result) { // 增加前的準備操作路徑
        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 vo;
        }
    }
    @RequestMapping(value = "/addPre", method = RequestMethod.GET)
    public String addPre() { // 增加前的準備操作路徑
        return "member_add";
    }
}

 對於此類的驗證大家理解即可,不需要將其作為重點,但是需要清楚,預設情況下 SpringBoot 提供的資料驗證需要通過註解 以及一系列的資原始檔進行定義後才可以使用,而且所有的錯誤都必須使用者自己來處理,這一點的設計不如直接編寫具體的反射攔 截器方便。

2.2、處理錯誤頁

錯誤頁絕對是所有的 WEB 專案之中必須具有的一項資訊顯示處理,但是在傳統的 WEB 專案開發過程之中,錯誤頁都是在 web.xml 檔案之中進行配置的,不過遺憾的是 SpringBoot 之中並不存在有 web.xml 配置檔案這一項,那麼如果要想進行錯誤頁的處 理,最好的做法是需要根據每一個錯誤程式碼建立一個屬於自己的錯誤顯示頁。

 1、 所有的錯誤頁都是普通的靜態檔案,那麼建議在“src/main/view/static”目錄下建立幾個常見的錯誤頁(常見的錯誤的 HTTP 返回編碼:404、500、400)

2、 新增一個錯誤頁的配置類,在啟動類中編寫一個錯誤頁的配置項;

package cn.study.microboot.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

@Configuration
public class ErrorPageConfig {
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(
                    ConfigurableEmbeddedServletContainer container) {
                ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST,
                        "/error-400.html");
                ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND,
                        "/error-404.html");
                ErrorPage errorPage500 = new ErrorPage(
                        HttpStatus.INTERNAL_SERVER_ERROR, "/error-500.html");
                container.addErrorPages(errorPage400, errorPage404,
                        errorPage500);
            }
        };
    }
}

 那麼此時只要出現了錯誤,就會找到相應的 http 狀態碼,而後跳轉到指定的錯誤路徑上進行顯示。

 2.3、全域性異常

 下面首先來觀察一個程式程式碼,例如:現在建立一個控制器,而後這個控制器自己丟擲一個異常。

@RequestMapping(value="/get")
    @ResponseBody
    public String get() {
        System.out.println("除法計算:" + (10 / 0));
        return "hello world" ;
    }

 如果此時配置有錯誤頁,那麼這個時候錯誤會統一跳轉到 500 所在的路徑上進行錯誤的顯示,但是如果說現在希望能夠顯示 出錯誤更加詳細的內容呢?

 所以這個時候可以單獨定義一個頁面進行錯誤的資訊顯示處理,而這個頁面,可以定義在“src/main/view/templates/error.html”, 這個頁面裡面要求可以輸出一些資訊;

 1、 定義一個全域性的異常處理類:

import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice // 作為一個控制層的切面處理
public class GlobalExceptionHandler {
    public static final String DEFAULT_ERROR_VIEW = "error"; // 定義錯誤顯示頁,error.html

    @ExceptionHandler(Exception.class) // 所有的異常都是Exception子類
    public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) { // 出現異常之後會跳轉到此方法
        ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW); // 設定跳轉路徑
        mav.addObject("exception", e); // 將異常物件傳遞過去
        mav.addObject("url", request.getRequestURL()); // 獲得請求的路徑
        return mav;
    }
}

 2、 定義 error.html 頁面:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<link rel="icon" type="image/x-icon" href="/images/study.ico"/>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="${url}"/>
<p th:text="${exception.message}"/>
</body>
</html>

 對於全域性異常資訊顯示除了採用以上的跳轉處理方式之外,也可以做的簡單一些,使用 Rest 進行顯示。

範例:修改全域性異常處理類

package cn.study.microboot.advice;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//@ControllerAdvice// 作為一個控制層的切面處理
@RestControllerAdvice
public class GlobalExceptionHandler {
    public static final String DEFAULT_ERROR_VIEW = "error"; // 定義錯誤顯示頁,error.html
    @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);     // 標記一個錯誤資訊型別
        info.setMessage(e.getMessage());
        info.setUrl(request.getRequestURL().toString());
        return info ;
    }
//    public ModelAndView defaultErrorHandler(HttpServletRequest request,
//            Exception e) { // 出現異常之後會跳轉到此方法
//        ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW); // 設定跳轉路徑
//        mav.addObject("exception", e); // 將異常物件傳遞過去
//        mav.addObject("url", request.getRequestURL()); // 獲得請求的路徑
//        return mav;
//    }
}

 如果現在要想把異常的資訊顯示的更加華麗一些(不是面對所有使用者),那麼最好的做法就是使用全域性異常處理的方式完成。

相關推薦

SpringBoot系列SpringBoot錯誤處理數據驗證處理錯誤全局異常

lin container sub exce asn valid 程序 validator iterator 1、概念: SpringBoot 錯誤處理 2、具體內容 在之前的程序裏面如果一旦出現了錯誤之後就會出現一堆的大白板,這個白板會有一些錯誤信息(雖然這些錯誤信息你可

SpringBoot系列SpringBoot錯誤處理資料驗證處理錯誤全域性異常

1、概念: SpringBoot 錯誤處理 2、具體內容 在之前的程式裡面如果一旦出現了錯誤之後就會出現一堆的大白板,這個白板會有一些錯誤資訊(雖然這些錯誤資訊你可能 看不懂,但是這些錯誤資訊依然要告訴給使用者)。在 SpringBoot 裡面針對於錯誤的處理一共提供有

SpringBoot系列SpringBoot開發改變環境屬性讀取資源文件Bean 配置模版渲染profile 配置

pat row 開發 ima set his 改變 端口配置 import 1、概念 SpringBoot 開發深入 2、具體內容 在之前已經基本上了解了整個 SpringBoot 運行機制,但是也需要清楚的認識到以下的問題,在實際的項目開發之中,尤其是 Java

springboot(十)springboot+jpa+thymeleaf增刪改查示例

pen 其中 底層原理 protect roo back styles ttr 喜歡 這篇文章介紹如何使用jpa和thymeleaf做一個增刪改查的示例。 先和大家聊聊我為什麽喜歡寫這種腳手架的項目,在我學習一門新技術的時候,總是想快速的搭建起一個demo來試試它的效果,越

SpringCloud系列Ribbon 負載均衡Ribbon 基本使用Ribbon 負載均衡自定義 Ribbon 配置禁用 Eureka 實現 Ribbon 調用

control context .mm 別名 void 用戶 size ali ram 1、概念:Ribbon 負載均衡 2、具體內容 現在所有的服務已經通過了 Eureka 進行了註冊,那麽使用 Eureka 註冊的目的是希望所有的服務都統一歸屬到 Eureka 之中進

3. ARMv8 中斷及異常處理包括系統呼叫,系統呼叫即同步異常

ARMv8 64bits相對於之前的 32bits 有較大變動,所有中斷及異常的處理總入口都在entry.S 原始檔中。 1.1.       異常介紹(中斷即稱為 非同步異常) 分為同步和非同步 兩種型別異常,中斷劃入非同步異常型別: Synchronous(同步異常)

訊息中介軟體系列RabbitMQ的使用場景非同步處理應用解耦

一、非同步處理 場景: 使用者註冊,寫入資料庫成功以後,傳送郵件和簡訊。 準備工作: 1)安裝RabbitMQ,參考前面的文章 2)新建一個名為RabbitMQAsyncProc的maven web工程,在pom.xml檔案裡面引入如下依賴 <project xmlns="http://maven.a

SpringBoot框架搭建系列()整合Redis

本次我們整合Redis 1、首先引入依賴 <!--redis--> <dependency> <groupId>org.springframework.boot</groupId>

SpringBoot系列搭建自己的第一個SpringBoot程序

快速 oot local 程序 源代碼 參考 xmlns 技術 don 一、根據官網手工搭建(http://projects.spring.io/spring-boot/#quick-start) 1、新建一個maven工程springbootfirst 2、 如果要想開

搜索引擎系列Lucene索引詳解IndexWriter詳解Document詳解索引更新

let integer 自己 textfield app tdi AS query rect 一、IndexWriter詳解 問題1:索引創建過程完成什麽事?     分詞、存儲到反向索引中 1. 回顧Lucene架構圖: 介紹我們編寫的應用程序要完成數據的收集,再將數據

SpringBoot(十)MockMVC-web單元測試

版權宣告 本文作者:低調小熊貓 本文連結:https://aodeng.cc/archives/springbootshi-wu 版權宣告:本文采用知識共享署名 4.0 國際許可協議進行許可。轉載請註明出處! 單純的廣告 個人部落格

SpringBoot2.X (二十)SpringBoot整合 Mybatis + MySQL CURD 示例

話不多數,直接開始擼程式碼… 工程結構圖 開始之前先放張工程結構圖 1、maven 依賴: <!-- Web 依賴--> <dependency>

一起學習Springboot()Springboot整合redis

引入依賴 <dependency> <groupId>org.springframework.boot</groupId> <artifact

Java B2B2C多使用者商城 springboot架構()熔斷監控Hystrix Dashboard和Turbine

Hystrix Dashboard 我們在熔斷示例專案spring-cloud-consumer-hystrix的基礎上更改,重新命名為:spring-cloud-consumer-hystrix-dashboard。 1、新增依賴 <dependency> <group

SpringBoot學習11springboot異常處理方式1(自定義異常頁面)

發生 title temp boot public main pan 頁面 exce SpringBoot 默認的處理異常的機制:SpringBoot 默認的已經提供了一套處理異常的機制。一旦程序中出現了異常 SpringBoot 會向/error 的 url 發送請求。在

SpringBoot學習14springboot異常處理方式4(使用SimpleMappingExceptionResolver處理異常)

mapping oot 方法 lan lob admin reat framework fig 修改異常處理方法3中的全局異常處理Controller即可 package bjsxt.exception; import org.springframework.conte

SpringBoot(十四)springboot整合shiro-登錄認證和權限管理

sets man throws 將不 匹配 跳轉 ida 管理員 領域 原文出處: 純潔的微笑 這篇文章我們來學習如何使用Spring Boot集成Apache Shiro。安全應該是互聯網公司的一道生命線,幾乎任何的公司都會涉及到這方面的需求。在Java領域一般有Spri

Ansible系列()playbook應用和roles自動化批量安裝示例

獲取 agg 真的 deb vhd under ice ddl ssh連接 html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,

springboot(十二)springboot如何測試打包部署

都是 添加 -- 堆內存 req lib 支持 參數 nohup 開發階段 單元測試 在開發階段的時候最重要的是單元測試了,springboot對單元測試的支持已經很完善了。 1、在pom包中添加spring-boot-starter-test包引用 <depend

Redis系列redis鍵管理和redis數據庫管理

切換數據庫 eight eid 鍵值對 ren 遷移 mage try hset 一、redis鍵管理 1 鍵重命名 rename oldKey newkey //格式rename oldKey newKey //若oldKey之前存在則被覆蓋set name ja