優雅的參數校驗


添加依賴

如果使用的是Springboot就不需要手動添加依賴了。Springboot已經依賴了。

<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
</dependency>

參數檢驗的使用

注解名 含義
AssertFalse 帶注釋的元素必須為false
AssertTrue 帶注釋的元素必須為true
DecimalMax 帶注釋的元素必須是一個數字,其值必須小於或等於指定的最大值
DecimalMin 帶注釋的元素必須是一個數字,其值必須大於或等於指定的最小值
Digits 字段必須為數值,且正數部分不能超過 i 位,小數部分不能超過 j 位,null 元素被視為有效。
Email 所注解的元素需滿足Email格式
Future 帶注釋的元素必須是將來的日期
FutureOrPresent 字段必須為未來的時間或當前的時間
Past 所注解的元素必須是某個過去的日期
PastOrPresent 字段必須為過去的時間或當前的時間從
Max 帶注釋的元素必須是一個數字,其值必須小於或等於指定的最大值
Min 帶注釋的元素必須是一個數字,其值必須大於或等於指定的最小值
NotBlank 所注解的元素值有內容
NotEmpty 字段不能為 null 且不能為空,可以作用於字符串,其長度不能為 0,可作用於 Array、Collection、Map,其大小不能為 0
NotNull 所注解的元素值不能為null
Null 所注解的元素值為null
Pattern 所注解的元素必須滿足給定的正則表達式
Positive 字段必須為正數,即數值大於 0
PositiveOrZero 字段必須為正數或 0,即數值大於等於 0
Negative 字段必須為負數,即數值小於 0
NegativeOrZero 字段必須為負數或 0,即數值小於等於 0
Size 所注解的元素必須是String、集合或數組,且長度大小需保證在給定范圍之內
  • 實體類增加屬性注解
    @Size(max= 64, message = "長度不能超過64")
    private String orderNo;
    @NotBlank(message = "類型不能為空")
    private String orderType;
    @Past(message = "創建時間在當前時間之前才可成功")
    private Date createDate;
    @Future(message = "更新時間在當前時間之后才可成功")
    private Date updateDate;
    @Email
    private String email;
    @Pattern(regexp = "^(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9]|X)$",message = "身份證格式不正確")
    private String idNum;
  • 方法使用實體類入參的時候增加校驗注解
    public Rs save(@RequestBody @Validated MiTestEntity miTest) {
        return Rs.ok();
    }
    public Rs update(@RequestBody @Valid MiTestEntity miTest) {
        return Rs.ok();
    }
  • 使用全局異常攔截錯誤的字段校驗
@RestControllerAdvice
public class BindExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Rs handleException(Exception e) {
        Rs r = new Rs();
        r.put("code" , 500);
        r.put("msg" , e.getMessage());
        return r;
    }
    /**
     * 方法參數校驗
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Rs handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        return Rs.error(e.getBindingResult().getFieldError().getDefaultMessage());
    }
}

@NotNull, @NotEmpty和@NotBlank之間的區別是什么?

  • @NotEmpty

    • 不能是null
    • 不能是空字符
    • 集合框架中的元素不能為空
  • @NotNull

    • 被修飾元素不能為null,可用在基本類型上
  • @NotBlank

    • String不能是null,且去除兩端空白字符后的長度0
  • @NotEmpty或者@NotBlank不可以用在基本數據類型上,會報錯

    • rg.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.Long'. Check configuration for 'offset'

@validated和@valid的區別

  • @Valid:標准JSR-303規范的標記型注解,用來標記驗證屬性和方法返回值,進行級聯和遞歸校驗。
  • @Validated:Spring的注解,是標准JSR-303的一個變種(補充),提供了一個分組功能,可以在入參驗證時,根據不同的分組采用不同的驗證機制
  • 在Controller中校驗方法參數時,使用@Valid和@Validated並無特殊差異,但是@Validated不可以嵌套校驗,
public class A{
    @NotNull(message = "id不能為空")
    @Min(value = 1, message = "id必須為正整數")
    private Long id;
    @NotNull(message = "B不能為空")
    @Size(min = 1, message = "至少要有一個屬性")
    private List<B> bList;
}
public class B{
    @NotNull(message = "id不能為空")
    @Min(value = 1, message = "id必須為正整數")
    private Long id;
    @NotBlank(message = "name不能為空")
    private String name;
}

//這樣的情況下如果使用@Validated校驗A的參數,那么bList泛型里面的屬性則不會校驗成功
//需要在private List<B> bList;上面加上@Valid來支持嵌套驗證
  • @Validated注解可以用於類級別,用於支持Spring進行方法級別的參數校驗。@Valid可以用在屬性級別約束,用來表示級聯校驗
  • @Validated只能用在類、方法和參數上,而@Valid可用於方法、字段、構造器和參數上

自定義注解驗證

某些業務場景下,上面的注解未必可以提供很好的校驗,validation也為我們提供了自定義注解參數校驗。

  • 注解
@Documented
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {StringLengthValidImpl.class})
public @interface StringLength {
    /**
     * 在注解沒有顯示申明,則min值默認是 0
     */
    int min() default 0;
    /**
     * 在注解沒有顯示申明,則max值默認是18
     *
     * @return
     */
    int max() default 18;
    /**
     * 錯誤信息
     */
    String message() default "";

    /**
     * 分組
     */
    Class<?>[] groups() default {};

     //TODO 暫時不知道是干嘛的 看接口的注釋是約束注解的負載(可用來保存一些數據)
    Class<? extends Payload>[] payload() default {};

    /**
     * 定義驗證集合,可以為屬性配置多套的驗證規則
     */
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        StringLength[] value();
    }
}
  • 校驗實現類
//<注解類,注解作用的參數類型(泛型)>
public class StringLengthValidImpl implements ConstraintValidator<StringLength, String> {

    private int min;
    private int max;
    private String message;
    /**
     * @Description: 初始化參數
     * @param: integerValid
     */
    @Override
    public void initialize(StringLength integerValid) {
        max = integerValid.max();
        min = integerValid.min();
        message = integerValid.message();
    }
    
    /**
     * @param: value 參數
     * @param: constraintValidatorContext 在應用給定的約束驗證器時提供上下文數據和操作
     * @return: boolean
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        //禁止默認消息返回
        context.disableDefaultConstraintViolation();
        if (null == value) {
            context.buildConstraintViolationWithTemplate(message + ":參數值為空").addConstraintViolation();
            return false;
        } else if (value.length() > max) {
            context.buildConstraintViolationWithTemplate(message + ":不能超過" + max).addConstraintViolation();
            return false;
        } else if (value.length() <= min) {
            context.buildConstraintViolationWithTemplate(message + ":不能小於" + min).addConstraintViolation();
            return false;
        }
        return true;
    }
}
  • 分組校驗
//用於新增校驗
public interface save {
}
//用於修改校驗
public interface update {
}
  • 參數校驗
@Data
public class TestEntity {
    @StringLength.List({
            @StringLength(groups = {save.class}, message = "name",max = 10),
            @StringLength(groups = {update.class}, message = "name",max = 5)
    })
    private String name;
}
//不可以超過10個字符
    @PostMapping("add")
    public String add(@RequestBody @Validated({save.class}) TestEntity testEntity) {
        return JSON.toJSONString(testEntity);
    }
    //不可以超過5個字符
    @PostMapping("update")
    public String update(@RequestBody @Validated({update.class}) TestEntity testEntity) {
        return JSON.toJSONString(testEntity);
    }
    //沒有限制
    @PostMapping("save")
    public String save(@RequestBody @Validated TestEntity testEntity) {
        return JSON.toJSONString(testEntity);
    }


免責聲明!

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



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