SpringBoot如何優雅的進行參數校驗
一.為什麼要進行參數校驗
在日常的開發過程中,我們常常需要對傳入的參數進行校驗,比如在web前後端分離項目中,參數校驗有兩個方面:
- 前端進行參數校驗
- 後端進行參數校驗
那這兩種有什麼差別呢?隻完成一個可不可以呢?
答案是不可以的!
- 前端校驗
- 前端校驗主要是針對使用者輸入時,一些基礎的錯誤進行提示,提升使用者體驗。比如:必填的選項,郵箱,網址的規則,如果前端校驗不通過的話就不需要将請求轉到後端。
- 但是:對于某些不走尋常路的使用者,前端校驗其實形同虛設。
- 後端校驗
- 後端校驗是針對整個系統的業務邏輯進行校驗,包含使用者的權限,請求的參數等,校驗的範圍要大于前端.如果不做後端的校驗會怎麼樣呢?比如前端向後端送出了一個隻包含郵箱的請求,然後一些心術不正的人将該請求拷貝,改變參數為任意一段字元,然後重新發送請求,那麼請求仍然能被處理,資料庫就會有一條髒資料,借助此操作,可以完成一些對系統危害性更大的操作.
- 前端校驗是輔助,後端校驗是核心。後端校驗必不可少。
二.後端參數校驗方式
傳統的參數校驗一般采用大量的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
- 說明:被注釋的元素必須是電子郵箱位址
- 适用範圍:CharSequence
- @Length
- 說明:被注釋的字元串的大小必須在指定的範圍内
- @NotEmpty
- 說明:被注釋的字元串的必須非空
- @Range
- 說明:被注釋的元素必須在合适的範圍内
具體使用
對于web服務來說,為防止非法參數對業務造成影響,在Controller層一定要做參數校驗的!大部分情況下,請求參數分為如下兩種形式:
- POST、PUT請求,使用requestBody傳遞參數;
- 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的功能是非常強大的,它還支援分組校驗,嵌套校驗,集合校驗,自定義校驗等多種校驗方式,功能非常強大.