天天看點

使用@Constraint配合自定義注解開發

前言

通常我們在開發的過程中,需要對前端傳入的資料進行校驗,盡管這一步已經在前端進行了一次校驗,雖然現在已經有了很多校驗的注解,@NotNull、@NotBlank、@URL等一系列注解幫助我們進行校驗,但是在實際的業務開發過程中,這些可能不足以滿足我們的需求,這時候我們就需要自己來定義注解了。

可能需要用到的依賴按需導入:

<dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.3.0.Final</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml</groupId>
            <artifactId>classmate</artifactId>
            <version>1.3.3</version>
        </dependency>
           

@Constraint

這個注解的主要作用就是幫助我們來處理驗證邏輯的,根據根據自己的業務需求來完成這一塊驗證的邏輯。下面我們就來簡單測試一下。

**場景 **:假設我們一個實體類的屬性如下解釋,我們需要對前端傳入的數字是不是0或1。

/**
     * 顯示狀态[0-不顯示;1-顯示]
     */
    private Integer showStatus;
           

定義注解

@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER,ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
   
    String message() default "{com.atguigu.common.valid.ListValue.message}";

    Class<?>[] groups() default {};
    
	int[] vals() default {};
	
    Class<? extends Payload>[] payload() default {};

    
}
           

message():錯誤資訊,如果我們沒有在注解中定義錯誤資訊的話,他會預設去尋找com.atguigu.common.valid.ListValue.message為key的錯誤資訊

groups():這個主要是來進行分組驗證的。

** vals() ** :自行定義的值

我們可以看到@Constraint中

@Constraint(validatedBy = {ListValueConstraintValidator.class})

這段意思是我們将此注解的驗證邏輯交給ListValueConstraintValidator來處理,這裡是一個數組,我們可以傳入多個處理邏輯。

ConstraintValidator接口,它有兩個泛型,第一個是自定義的注解類,第二個就是要驗證的資料的類型,這兩個類裡面都有兩個方法,initialize和isValid,第一個是初始化方法,第二個是驗證的邏輯方法,傳回true,則驗證通過,否則則不通過。

ListValueConstraintValidator自定義驗證邏輯

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {

    private Set<Integer> set = new HashSet<>();
    /**
     * 初始化 加載注解的資訊。也就是帶有此注解Bean上的vals值
     * @param constraintAnnotation
     */
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    /**
     * 判斷是否校驗成功
     * @param value 需要校驗的值 實際傳入的值
     * @param context 上下文資訊
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {

        return set.contains(value);
    }
}
           

** ValidationMessages.properties **

規範(JSR303)說,我必須将ValidationMessages.properties放到我的類路徑根目錄中,我希望它應該是MyDeploymentUnit.war / WEB-INF / classes / ValidationMessages.properties,這就是我的應用程式的建構和部署方式。出于調試原因,我将此代碼添加到了自定義驗證器中,以確定檔案存在并正确設定。

使用@Constraint配合自定義注解開發

key就是我們在注解定義的預設 message的值。

測試

在Controller中需要進行校驗的Bean加上 ** @Validated ** 注解

使用@Constraint配合自定義注解開發

需要驗證的 屬性

使用@Constraint配合自定義注解開發

這裡的如果校驗不通過的話,他會抛出一個異常,我們隻需要捕獲到這個錯誤資訊即可。

使用@Constraint配合自定義注解開發

如果我們去掉屬性聲明的message資訊 他會去尋找預設的ValidationMessages.properties下的資訊。

使用@Constraint配合自定義注解開發

分組校驗

可能大家會注意到我在Controller中使用 @Validated 注解時會帶有一個value值,他的作用是對操作進行分組。比如請看如下

@NotNull(message = "修改商品時請傳入商品id",groups = {UpdateGroup.class})
    @Null(groups = {AddGroup.class},message = "不能指定id")
    @TableId
    private Long brandId;
           

商品的資料表的對應的ID,我們可能在進行新增操作時無需我們來指定對應的ID,因為我們一般設定都會預設自增的。而我們在查詢或者更新的時候可能會根據ID來查出這一條記錄。總的來說的就是在進行更新時需要ID,新增不需要。每一個注解都會帶有groups這個屬性來聲明自己的組。

如何使用呢?

很簡單:

定義對應的接口或者類。

public interface AddGroup {
}
// ------------------------------
public interface UpdateGroup {
}
//---------------------------------
public interface UpdateStatusGroup {
}
           

我們隻需要定義三個接口來聲明組,無需任何操作。

在Controller中的@Validated 注解中聲明對那個組進行驗證。

@RequestMapping("/save")
    public R save(@Validated(value = {AddGroup.class}) @RequestBody BrandEntity brand) {
        brandService.save(brand);
        return R.ok();
    }
           

實體類進行分組邏輯

@NotNull(message = "修改商品時請傳入商品id",groups = {UpdateGroup.class})
    @Null(groups = {AddGroup.class},message = "不能指定id")
    @TableId
    private Long brandId;
           

驗證: 新增時:傳入ID會失敗

使用@Constraint配合自定義注解開發

更新時:不傳ID 會失敗

使用@Constraint配合自定義注解開發