利用註解對Bean進行校驗

最近寫業務代碼,由於頁面複雜,致使對應的Bean屬性很是多,而產品大佬又提出各類校驗要求。html

emmmmmm......若是寫if條件來校驗,那簡直是又臭又長。java

因此就有今天的話題——利用註解對Bean進行校驗。git

利用註解對Bean進行校驗,主要是利用hibernate-validator框架,hibernate-validator實現了validation-api的接口關於Bean校驗的接口,直接使用hibernate-validator很是方便,省時省力。web


1.hibernate-validato簡介

此hibernate-validator+SpringMVC能夠實現如下功能:正則表達式

  • 註解java bean聲明校驗規則;
  • 添加message錯誤信息源實現國際化配置;
  • 結合spring form中的errors標籤展示錯誤信息。

優點:spring

  • 代碼簡潔、處理校驗能夠更加優雅。

實現要求:apache

  • 使用hibernate validator至少要引入兩個jar包:
<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>
  • java bean中使用註解添加檢驗規則。

2.註解及用法

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格式

3.校驗demo

利用hibernate validator實現Bean校驗,通常有兩種作法:api

  • 利用@ModelAttribute和@Valid註解;
  • 利用validate()、validateValue()、validateProperty()等方法在須要之處直接調用。
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 ...
}

3.1.利用Validator的validate()方法

驗證器
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

3.2.利用@ModelAttribute和@Valid註解和BindingResult對象

校驗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

3.3.利用@Valid註解和統一異常處理

校驗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能夠更加靈活,能夠按照本身需求處理和組織校驗的返回信息。服務器

4.hibernate validator更詳細的使用文檔

hibernate validator的更詳細的使用說明,能夠參考官方文檔,之前沒關注,此次認真的看了一下,發現hibernate validator的功能仍是很強大的,最新的5.0、6.0版本只有英文文檔,4.0版本有中文文檔。地址以下:https://docs.jboss.org/hibern...

5.使用過程當中遇到的問題

使用方式1,在我本身電腦註解沒有添加message信息時,默認返回的是中文,如@NotNull:不能爲null,@NotEmpty:不能爲空等等,可是,當部署到服務器之後,就變成英文,如@NotNull:may not be null,@NotEmpty:may not be empty等等,非常詭異。後來研讀源碼發現,hibernate validator經過messageInterpolator字段來實現國際化的,messageInterpolator字段中存放着當前操做系統的語言環境參數,而後根據語言環境參數去對應的配置文檔中讀取默認提示信息,而messageInterpolator則會在項目啓動時初始化,由於我本身的電腦是中文環境,而公司的系統環境是英文的,因此致使這個問題。

相關文章
相關標籤/搜索