天天看點

SpringBoot如何優雅的進行參數校驗(一)

作者:京東雲開發者

SpringBoot如何優雅的進行參數校驗

一.為什麼要進行參數校驗

在日常的開發過程中,我們常常需要對傳入的參數進行校驗,比如在web前後端分離項目中,參數校驗有兩個方面:

  • 前端進行參數校驗
  • 後端進行參數校驗

那這兩種有什麼差別呢?隻完成一個可不可以呢?

答案是不可以的!

  1. 前端校驗
  2. 前端校驗主要是針對使用者輸入時,一些基礎的錯誤進行提示,提升使用者體驗。比如:必填的選項,郵箱,網址的規則,如果前端校驗不通過的話就不需要将請求轉到後端。
  3. 但是:對于某些不走尋常路的使用者,前端校驗其實形同虛設。
  4. 後端校驗
  5. 後端校驗是針對整個系統的業務邏輯進行校驗,包含使用者的權限,請求的參數等,校驗的範圍要大于前端.如果不做後端的校驗會怎麼樣呢?比如前端向後端送出了一個隻包含郵箱的請求,然後一些心術不正的人将該請求拷貝,改變參數為任意一段字元,然後重新發送請求,那麼請求仍然能被處理,資料庫就會有一條髒資料,借助此操作,可以完成一些對系統危害性更大的操作.
  6. 前端校驗是輔助,後端校驗是核心。後端校驗必不可少。

二.後端參數校驗方式

傳統的參數校驗一般采用大量的if else代碼對參數進行一個一個的校驗

傳統的參數校驗方式:

public String checkUserDTO(UserDTO user) {

     if (StringUtils.isEmpty(user.getName())) {
         return "使用者名不能為空";
     }
     if(StringUtils.isEmpty(user.getEmail())) {
     	return "郵箱不能為空";
     }
     if(StringUtils.isEmpty(user.getAccount())) {
     	return "賬号不能為空";
     }
    
     if (user.getAccount().length() < 6 || user.getAccount().length() > 11) {
         return "賬号長度必須是6-11個字元";
     }
     if (!Pattern.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+#34;, user.getEmail())) {
         return "郵箱格式不正确";
     }
     return "success";
 }
           

這樣的方式的話,如果參數多了那光參數校驗就是一大堆,給人的感覺就是:不優雅,不專業,代碼可讀性也很差.

那麼怎麼能簡單快捷的進行參數校驗呢?

其實在SpringBoot項目中我們可以引入spring-boot-starter-validation來簡單的進行參數校驗.

三.spring-validation使用

引入依賴

粘貼請去除其中多餘空格

< !--參數校驗 -- >
 < dependency >
         < groupId>org.springframework.boot < /groupId>
         < artifactId>spring-boot-starter-validation< /artifactId>
   < /dependency>
           

參數注解清單

spring-validation是以注解的方式完成參數的校驗的,而根據springboot官網的介紹,隻要有JSR-303實作,例如Hibernate驗證器,那麼就能進行參數的校驗.

這裡列一下常用的注解:

  • @Null
    • 說明:被注釋的元素必須為 null
    • 适用範圍:Object
  • @NotNull
    • 說明:被注釋的元素必須不為 null
    • 适用範圍:Object
  • @AssertTrue
    • 說明:被注釋的元素必須為 true
    • 适用範圍:boolean、Boolean
  • @AssertFalse
    • 說明:被注釋的元素必須為 false
    • 适用範圍:boolean、Boolean
  • @Min(value)
    • 說明:被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
    • 适用範圍:BigDecimal、BigInteger、byte、Byte、short、Short、int、Integer、long、Long
  • @Max(value)
    • 說明:被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
    • 适用範圍:BigDecimal、BigInteger、byte、Byte、short、Short、int、Integer、long、Long
  • @DecimalMin(value)
    • 說明:被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
    • 适用範圍:BigDecimal、BigInteger、CharSequence、byte、Byte、short、Short、int、Integer、long、Long
  • @DecimalMax(value)
    • 說明:被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
    • 适用範圍:BigDecimal、BigInteger、CharSequence、byte、Byte、short、Short、int、Integer、long、Long
  • @Size(max, min)
    • 說明:被注釋的元素的大小必須在指定的範圍内
    • 适用範圍:CharSequence、Collection、Map、Array
  • @Digits (integer, fraction)
    • 說明:被注釋的元素必須是一個數字,其值必須在可接受的範圍内
    • 适用範圍:BigDecimal、BigInteger、CharSequence、byte Byte、short Short、int Integer、long Long
  • @Past
    • 說明:被注釋的元素必須是一個過去的日期
    • 适用範圍:Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate
  • @Future
    • 說明:被注釋的元素必須是一個将來的日期
    • 适用範圍:Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate
  • @Pattern(value)
    • 說明:被注釋的元素必須符合指定的正規表達式
    • 适用範圍:CharSequence、null
  • @Email
    • 說明:被注釋的元素必須是電子郵箱位址
    • 适用範圍:CharSequence
  • @Length
    • 說明:被注釋的字元串的大小必須在指定的範圍内
  • @NotEmpty
    • 說明:被注釋的字元串的必須非空
  • @Range
    • 說明:被注釋的元素必須在合适的範圍内

具體使用

對于web服務來說,為防止非法參數對業務造成影響,在Controller層一定要做參數校驗的!大部分情況下,請求參數分為如下兩種形式:

  1. POST、PUT請求,使用requestBody傳遞參數;
  2. GET請求,使用requestParam/PathVariable傳遞參數。

下面我們簡單介紹下requestBody和requestParam/PathVariable的參數校驗

requestBody參數校驗

POST、PUT請求一般會使用requestBody傳遞參數,這種情況下,後端使用DTO對象進行接收。隻要給DTO對象加上@Validated注解就能實作自動參數校驗。

requestBody參數校驗需要兩個步驟:

  • 在DTO字段上聲明限制注解
  • public class UserDTO { private Long Id; @NotNull @Length(min = 2, max = 10) private String name; @NotNull @Length(min = 6, max = 20) private String account; @NotNull @Email private String email; }
  • 在方法參數上聲明校驗注解
public Result addUser(@RequestBody @Validated UserDTO userDTO) {
    // 校驗通過,才會執行業務邏輯處理
    return Result.ok();
}

           

requestParam/PathVariable參數校驗

GET請求一般會使用requestParam/PathVariable傳參

将一個個參數平鋪到方法入參中。在這種情況下,必須在Controller類上标注@Validated注解,并在入參上聲明限制注解(如@Min等)。

@Validated
@RestController
public class UserController {
    // 路徑變量
    @GetMapping("{userId}")
    public Result detail(@PathVariable("userId") @Min(10000000000000000L) Long userId) {
        // 校驗通過,才會執行業務邏輯處理
        UserDTO userDTO = new UserDTO();
        userDTO.setId(userId);
        return Bizmessage.success(userDTO);
    }

    // 查詢參數
    @GetMapping("getByAccount")
    public BizMessage getByAccount(@Length(min = 6, max = 11) @NotNull String  account) {
        // 校驗通過,才會執行業務邏輯處理
        UserDTO userDTO = new UserDTO();
        userDTO.setAccount(account);
        return Bizmessage.success(userDTO);
    }
}
           
如果校驗失敗,則會抛出異常,通常會有統一異常處理

Hibernate Validator的功能是非常強大的,它還支援分組校驗,嵌套校驗,集合校驗,自定義校驗等多種校驗方式,功能非常強大.