Validation


beanvalidation是一種規范,hibernate-validator是它的最佳實現。

常用注解

beanvalidation 所有注解在 javax.validation.constraints 包下:

img

hibernate-validator 所有注解在 org.hibernate.validator.constraints 包下:

img

常用注解解釋

約束注解 詳細信息
@Null 被注釋的元素必須為 null
@NotNull 被注釋的元素必須不為 null
@AssertTrue 被注釋的元素必須為 true
@AssertFalse 被注釋的元素必須為 false
@Min(value) 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax(value) 被注釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Size(max, min) 被注釋的元素的大小必須在指定的范圍內
@Digits (integer, fraction) 被注釋的元素必須是一個數字,其值必須在可接受的范圍內
@Past 被注釋的元素必須是一個過去的日期
@Future 被注釋的元素必須是一個將來的日期
@Pattern(value) 被注釋的元素必須符合指定的正則表達式
@Email 被注釋的元素必須是電子郵箱地址
@Length 被注釋的字符串的大小必須在指定的范圍內
@NotEmpty 被注釋的字符串的必須非空
@Range 被注釋的元素必須在合適的范圍內

約束與校驗器類的綁定原理

org.hibernate.validator.internal.metadata.core.ConstraintHelper 類下:

img

img

  • 從上述兩幅圖中可以看出,NotEmpty注解可以校驗字符串,集合,Map,數組類型的屬性,而為了滿足一個注解可以校驗多種類型的數據,所有需要為這個注解適配多個對應的校驗器。
  • 注解名稱是xxx,那么校驗器的名稱就是xxxValidator。

自定義消息模板

消息模板中可以使用 el 表達式。

public class User {
    @NotNull(groups = {Update.class})
    private Integer id;
    @NotBlank(message = "名字不能為空")
    private String name;
    @Min(value = 18, message = "年齡小於{value},不得進入")
    private int age;
}

分組校驗

注解上不區分組的話,會使用默認的組:javax.validation.groups.Default

public class User {
    @NotNull(groups = {Update.class})
    private Integer id;
    @NotBlank(message = "名字不能為空")
    private String name;
    @Min(value = 18, message = "年齡小於{value},不得進入")
    private int age;

    public interface Insert {
    }

    public interface Update {
    }
}

特別注意的地方如果使用了某個組進行校驗的話,那么默認的組就不會進行校驗****。就比如校驗 Update 組,那么就算 name 名字為空也不會再校驗。如果想在對某個組進行校驗,默認的組同時被校驗的話,可以讓 分組接口繼承 Default 接口即可****。

public class User {
    @NotNull(groups = {Update.class})
    private Integer id;
    @NotBlank(message = "名字不能為空")
    private String name;
    @Min(value = 18, message = "年齡小於{value},不得進入")
    private int age;

    public interface Insert {
    }

    public interface Update extends Default {
    }
}

級聯校驗

public class Grade {
    @NotBlank
    private String no;
}
public class User {
    @NotNull(groups = {Update.class})
    private Integer id;
    @NotBlank(message = "名字不能為空")
    private String name;
    @Min(value = 18, message = "年齡小於{value},不得進入")
    private int age;
    @NotNull(message = "年級不能為空")
    @Valid
    private Grade grade;

    public interface Insert {
    }

    public interface Update extends Default {
    }
}

被引用對象加上 @valid 注解才能完成級聯校驗。也就是說在校驗 User 對象里的屬性的時候,能一起校驗 Grade 對象。

自定義校驗規則

public class User {
    @NotNull(groups = {Update.class})
    private Integer id;
    @NotBlank(message = "名字不能為空")
    private String name;
    @Min(value = 18, message = "年齡小於{value},不得進入")
    private int age;
    @NotNull(message = "年級不能為空")
    @Valid
    private Grade grade;
    @UserStatus
    private Integer userStatus;

    public interface Insert {
    }

    public interface Update extends Default {
    }
}
@Constraint(validatedBy = {UserStatusValidator.class})
@Target({FIELD})
@Retention(RUNTIME)
public @interface UserStatus {
    String message() default "用戶狀態不正確,值必須在1001或者1002或者1003中";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
public class UserStatusValidator implements ConstraintValidator<UserStatus, Integer> {
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        return Arrays.asList(1001, 1002, 1003).contains(value);
    }
}

當現有的約束注解不滿足實際項目需要時,可以仿照現有的 NotEmpty 注解和 NotEmptyValidatorForArray 校驗器進行改造以下,就可以實現自己的校驗規則。

@Validated自動校驗

在 springboot 中可以使用在控制器中給每個需要進行校驗的方法的參數前加上 @Validated 注解,在參數校驗不通過的時候會自動拋出 BindException 異常。

@PutMapping
public String update(@Validated({User.Update.class}) User user) {
    return "更新成功!";
}

統一異常處理

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = BindException.class)
    public RespBean entityException(BindException e) {
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return  RespBean.error(HttpStatus.BAD_REQUEST.value(), msg);
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM