最近寫業務代碼,由於頁面複雜,致使對應的Bean屬性很是多,而產品大佬又提出各類校驗要求。html
emmmmmm......若是寫if條件來校驗,那簡直是又臭又長。java
因此就有今天的話題——利用註解對Bean進行校驗。git
利用註解對Bean進行校驗,主要是利用hibernate-validator框架,hibernate-validator實現了validation-api的接口關於Bean校驗的接口,直接使用hibernate-validator很是方便,省時省力。web
此hibernate-validator+SpringMVC能夠實現如下功能:正則表達式
優點:spring
實現要求:apache
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.1.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b08</version> </dependency>
hibernate validator使用的註解定義在hibernate-validator-6.0.1.Final.jar、validation-api-1.1.0.Final.jar兩個包中,bootstrap
@AssertFalse 驗證註解的元素值是false @AssertTrue 驗證註解的元素值是true @DecimalMax(value=x) 驗證註解的元素值小於等於@ DecimalMax指定的value值 @DecimalMin(value=x) 驗證註解的元素值小於等於@ DecimalMin指定的value值 @Digits(integer=整數位數, fraction=小數位數) 驗證註解的元素值的整數位數和小數位數上限 @Future 驗證註解的元素值(日期類型)比當前時間晚 @Max(value=x) 驗證註解的元素值小於等於@Max指定的value值 @Min(value=x) 驗證註解的元素值大於等於@Min指定的value值 @NotNull 驗證註解的元素值不是null @Null 驗證註解的元素值是null @Past 驗證註解的元素值(日期類型)比當前時間早 @Pattern(regex=正則表達式, flag=) 驗證註解的元素值與指定的正則表達式匹配 @Size(min=最小值, max=最大值) 驗證註解的元素值的在min和max(包含)指定區間以內,如字符長度、集合大小 @Valid 驗證關聯的對象,如帳戶對象裏有一個訂單對象,指定驗證訂單對象 @NotEmpty 驗證註解的元素值不爲null且不爲空(字符串長度不爲0、集合大小不爲0) @Range(min=最小值, max=最大值) 驗證註解的元素值在最小值和最大值之間 @NotBlank 驗證註解的元素值不爲空(不爲null、去除首位空格後長度爲0),不一樣於@NotEmpty,@NotBlank只應用於字符串且在比較時會去除字符串的空格 @Length(min=下限, max=上限) 驗證註解的元素值長度在min和max區間內 @Email 驗證註解的元素值是Email,也能夠經過正則表達式和flag指定自定義的email格式
利用hibernate validator實現Bean校驗,通常有兩種作法:api
Bean對象:
import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class Car { @NotNull private String manufacturer; @NotNull @Size(min = 2, max = 14) private String licensePlate; @Min(2) private int seatCount; public Car(String manufacturer, String licencePlate, int seatCount) { this.manufacturer = manufacturer; this.licensePlate = licencePlate; this.seatCount = seatCount; } //getters and setters ... }
驗證器
import org.apache.commons.collections4.CollectionUtils; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; public class ValidateTest { /** * 驗證器 */ private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); public static void main(String[] args) { Car car = new Car(null, "12", 1); //執行驗證 Set<ConstraintViolation<Car>> constraintViolations = validator.validate(car); //打印校驗信息 if (CollectionUtils.isNotEmpty(constraintViolations)) { for (ConstraintViolation<Car> constraintViolation : constraintViolations) { System.out.println(constraintViolation.getPropertyPath().toString() + ": " + constraintViolation.getMessage()); } } } }
輸出結果:
seatCount: 最小不能小於2 manufacturer: 不能爲null
校驗demo
import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; @Controller("/Validate") public class ValidateTestController { @RequestMapping("/demo1") public void validateDemo(@Valid @ModelAttribute("car") Car car, BindingResult result) { if(result.hasErrors()){ for (ObjectError error : result.getAllErrors()) { System.out.println(error.getDefaultMessage()); } } } }
測試數據:
{ "manufacturer": null, "licensePlate": "", "seatCount": 1 }
結果:
不能爲null 個數必須在2和14之間 最小不能小於2
注意,須要加上@ModelAttribute註解,不然會報錯: An Error/BindingResult argument is
expected to be declared immediately after the model attribute
校驗demo
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; @Controller @RequestMapping("/validate") public class ValidateTestController { @RequestMapping("/demo1") public void validateDemo(@Valid Car car) { } }
測試數據:
{ "manufacturer": null, "licensePlate": "", "seatCount": 1 }
統一異常處理類:
@Component public class ExceptionResolver implements HandlerExceptionResolver { /** * 日誌 */ private static final Logger LOG = LoggerFactory.getLogger(AuditCommonExceptionResolver.class); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { if (ex instanceof BindException) { BindException exs = (BindException) ex; for (ObjectError o : exs.getAllErrors()) { System.out.println(o.getDefaultMessage()); } } else if (ex instanceof ConstraintViolationException) { ConstraintViolationException exs = (ConstraintViolationException) ex; Set<ConstraintViolation<?>> violations = exs.getConstraintViolations(); for (ConstraintViolation<?> item : violations) { System.out.println(item.getMessage()); } } else { LOG.error("捕獲未處理異常,異常信息:{}", ex.getMessage()); } return new ModelAndView("/sys/errorPage.jsp"); } }
結果:
不能爲null 個數必須在2和14之間 最小不能小於2
注意:我本身測試的時候,捕獲的是BindException異常,可是看網上好多文章寫的都是捕獲ConstraintViolationException異常,
比較以上三種校驗方式(準確的說應該是三種hibernate validator的使用方式),能夠發現二、3大同小異,使用@Valid能夠不用再本身寫校驗的處理方法,可是方式1能夠更加靈活,能夠按照本身需求處理和組織校驗的返回信息。服務器
hibernate validator的更詳細的使用說明,能夠參考官方文檔,之前沒關注,此次認真的看了一下,發現hibernate validator的功能仍是很強大的,最新的5.0、6.0版本只有英文文檔,4.0版本有中文文檔。地址以下:https://docs.jboss.org/hibern...
使用方式1,在我本身電腦註解沒有添加message信息時,默認返回的是中文,如@NotNull:不能爲null,@NotEmpty:不能爲空
等等,可是,當部署到服務器之後,就變成英文,如@NotNull:may not be null,@NotEmpty:may not be empty
等等,非常詭異。後來研讀源碼發現,hibernate validator經過messageInterpolator
字段來實現國際化的,messageInterpolator
字段中存放着當前操做系統的語言環境參數,而後根據語言環境參數去對應的配置文檔中讀取默認提示信息,而messageInterpolator
則會在項目啓動時初始化,由於我本身的電腦是中文環境,而公司的系統環境是英文的,因此致使這個問題。