曾經參數的驗證是這樣的:java
public String test(User user){ if(user == null){ throw new NullPointerException("user 不能爲空"); } if(user.getUserName() == null){ throw new NullPointerException("userName 不能爲空"); } if(user.getUserName().length() < 4 || user.getUserName().length()>10){ throw new RuntimeException("userName 長度小於4位或大於10位"); } return "success"; }
隨着參數的增長,格式的變化,校驗數據有效性的代碼愈發繁瑣。git
經過Spring boot來完成參數數據校驗。web
JSR-303註解介紹正則表達式
這裏只列舉了javax.validation包下的註解,同理在spring-boot-starter-web包種也存在hibernate-validator驗證包,裏面包含了一些javax.validation沒有的註解。spring
註解 | 說明 |
---|---|
@NotNull |
限制必須不爲null |
@NotEmpty |
驗證註解的元素值不爲 null 且不爲空(字符串長度不爲0、集合大小不爲0) |
@NotBlank |
驗證註解的元素值不爲空(不爲null、去除首位空格後長度爲0),不一樣於@NotEmpty,@NotBlank只應用於字符串且在比較時會去除字符串的空格 |
@Pattern(value) |
限制必須符合指定的正則表達式 |
@Size(max,min) |
限制字符長度必須在 min 到 max 之間(也能夠用在集合上) |
@Email |
驗證註解的元素值是Email,也能夠經過正則表達式和flag指定自定義的email格式 |
@Max(value) |
限制必須爲一個不大於指定值的數字 |
@Min(value) |
限制必須爲一個不小於指定值的數字 |
@DecimalMax(value) |
限制必須爲一個不大於指定值的數字 |
@DecimalMin(value) |
限制必須爲一個不小於指定值的數字 |
@Null |
限制只能爲null(不多用) |
@AssertFalse |
限制必須爲false (不多用) |
@AssertTrue |
限制必須爲true (不多用) |
@Past |
限制必須是一個過去的日期 |
@Future |
限制必須是一個未來的日期 |
@Digits(integer,fraction) |
限制必須爲一個小數,且整數部分的位數不能超過 integer,小數部分的位數不能超過 fraction (不多用) |
實體類瀏覽器
public class Book implements Serializable { private Integer id; @NotBlank(message = "name 不能爲空") @Length(min = 2, max = 10, message = "name 長度必須在{min}-{max}之間") private String name; @NotNull(message = "price 不能爲空") @DecimalMin(value = "0.1", message = "價格不能低於 {value}") private BigDecimal price; ... }
控制層app
這些驗證註解不單單能夠放在controller上,也能夠加在service層上。ide
//todo 開啓數據有效性校驗,添加在類上即爲驗證方法,添加在方法參數中即爲驗證參數對象。(添加在方法上無效) @Validated @RequestMapping("/books")
@RestController public class BookController { @GetMapping("/test1") public String test1(@NotBlank(message = "name不能爲空") @Length(min = 2, max = 10 , message="name 長度必須在{min}-{max}之間") String name){ return "test1"; } @GetMapping("test2") public String test2(@Validated Book book){ return "test2"; } }
這樣就能夠了,在瀏覽器中輸入 /books/test1/ 不輸入參數會拋異常 /books/test1?name=sdf 則能夠經過驗證spring-boot
/books/test2/ 異常 /books/test2?name=sdf&price=0.5就ok了測試
Spring Boot 還容許咱們自定義Validatior
自定義註解
package com.spring.boot.utils; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //@Target定義範圍 在字段 參數上使用 @Target({ElementType.FIELD, ElementType.PARAMETER}) //定義可見範圍 RUNTIME整個運行階段均可見 @Retention(RetentionPolicy.RUNTIME) //Constraint指定具體校驗器類 @Constraint(validatedBy = DateTimeValidator.class) //@interface 定義註解 public @interface DateTime { String message() default "格式錯誤"; String format() default "yyyy-MM-dd"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
具體的校驗器
package com.spring.boot.utils; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.text.ParseException; import java.text.SimpleDateFormat; /** * 日期格式驗證 */ public class DateTimeValidator implements ConstraintValidator<DateTime, String> { private DateTime dateTime; @Override //初始化,它能夠得到當前註解的全部屬性 public void initialize(DateTime constraintAnnotation) { this.dateTime = constraintAnnotation; } @Override //約束驗證的主體方法,其中s就是驗證參數的具體事例,context表明約束執行的上下文 public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { //若是爲空不用驗證, 爲空驗證能夠用@NotBlank、@NotNull等參數進行控制 if (s == null) { return true; } String format = dateTime.format(); if (s.length() != format.length()) { return false; } SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); try { simpleDateFormat.parse(s); } catch (ParseException e) { return false; } return true; } }
而後在控制層使用他
@GetMapping("/test3") public String test3(@NotBlank(message = "date 不能爲空") @DateTime(message = "您如的格式錯誤,正確的格式爲:{format}",format = "yyyy-MM-dd HH:mm") String date){ return "test3"; }
測試
分組驗證
有時候咱們須要對一個實體類有多種驗證方式,在不一樣的狀況下使用不一樣的驗證方式,好比id,新增的時候是不須要的,更新時是必須的。
定義一個驗證組,裏面寫上不一樣的空接口類便可
public class Groups { public interface Update{ } public interface Default{ } }
實體類
groups屬性的做用就讓@Validated註解只驗證與自身value屬性想匹配的字段,可多個,只要知足就會去歸入驗證範圍。
public class Book { @NotNull(message = "id 不能爲空" , groups = Groups.Update.class) private Integer id; @NotBlank(message = "name 不能爲空" , groups = Groups.Default.class) private String name; @NotNull(message = "price 不能爲空" , groups = Groups.Default.class) private BigDecimal price;
控制層
建立一個ValidateControoler類,而後定義好insert、update兩個方法,因爲insert方法並不關心id字段,因此這裏的@Validate的value屬性寫成Groups.Default.class就能夠了,而update方法須要Id,因此此處@Validated註解的value屬性值就要寫成Groups.Default.class,Groups.Update.Class。表明只要是這分組下的數據都須要進行數據有效性校驗操做
@RestController public class ValidateController { //default中沒有id @GetMapping("/insert") public String insert(@Validated(value=Groups.Default.class) Book book){ return "insert"; } //update中有id校驗 @GetMapping("update") public String update(@Validated(value={Groups.Default.class,Groups.Update.class}) Book book){ return "update"; } }