Spring validation 用法說明

一 簡介

  • 後端開發接口,經常會需要校驗接口,可以使用spring提供的validation框架,使用註解進行校驗,很方便。
  • 如果提供的註解滿足不了業務需求,可以自己定義,也很方便;
  • 本文也提供針對List裏面嵌套對象的校驗方式,有些文章說解決不了,還是姿勢不對。

 

二 常用

2.1 maven依賴

 TODO

2.2 註解說明

註解 作用
@Null 限制只能爲null
@NotNull 限制必須不爲null
@NotEmpty 只作用於字符串類型,字符串不爲空,並且長度不爲0
@NotBlank 只作用於字符串類型,字符串不爲空,並且trim()後不爲空串
@AssertFalse 限制必須爲false
@AssertTrue 限制必須爲true
@DecimalMax(value) 限制必須爲一個不大於指定值的數字
@DecimalMin(value) 限制必須爲一個不小於指定值的數字
@Digits(integer,fraction) 限制必須爲一個小數,且整數部分的位數不能超過integer,小數部分的位數不能超過fraction
@Future 限制必須是一個將來的日期
@Past 驗證註解的元素值(日期類型)比當前時間早
@Max(value) 限制必須爲一個不大於指定值的數字
@Min(value) 限制必須爲一個不小於指定值的數字
@Pattern(value) 限制必須符合指定的正則表達式
@Size(max,min) 限制字符長度必須在min到max之間
@Email 驗證註解的元素值是Email,也可以通過正則表達式和flag指定自定義的email格式
   
   

 

2.3 用法說明

2.3.1 在接口字段參數上直接使用

  • 在方法字段參數上直接用對應的註解即可
  • 
    @RestController
    @RequestMapping("/tracemain")
    public class TraceMainController {
    
        @PostMapping("/save")
        public ResponseEntity<TraceMainSaveOutVo> saveTraceMain(
            @NotNull(message = "type字段不能爲空") Integer type) {
            // xxxx
            return ResponseEntity.success(traceMainSaveOutVo);
        }
    
    }
    
    

     

 

2.3.2 在對象上使用

  • Controller方法中對象前面添加 @Validated 註解,VO對象裏面字段上面添加對應註解即可 
  • 如下代碼

@RestController
@RequestMapping("/tracemain")
public class TraceMainController {

    @PostMapping("/save")
    public ResponseEntity<TraceMainSaveOutVo> saveTraceMain(@RequestBody @Validated TraceMainSaveInVo traceMainSaveInVo) {
        // xxxx
        return ResponseEntity.success(traceMainSaveOutVo);
    }

}


@JsonInclude(JsonInclude.Include.NON_NULL)
public class TraceMainSaveInVo extends SysModel {

    private static final long serialVersionUID = -1826896482893289340L;

    @ApiModelProperty("物流唯一單號")
    @NotBlank(message = "物流唯一單號不能爲空")
    private String logisticsUniqueNo;

    @ApiModelProperty("HQ跟蹤單號,格式爲:HQ1+19位數字")
    @Pattern(regexp = "^HQ1+\\d{19}", message = "HQ跟蹤單號格式有誤,格式爲:HQ1+19位數字")
    @Size(min = 22, max = 22, message = "HQ跟蹤單號格式有誤, 格式爲:HQ1+19位數字")
    private String hqTraceNo;


    @ApiModelProperty("預報來源: 1-WMS,2-LMS, 3-1track")
    @NotNull(message = "預報來源不能爲空")
    @Min(value = 1, message = "預報來源的值只能爲1,2,3")
    @Max(value = 3, message = "預報來源的值只能爲1,2,3")
    private Integer predictSource;

}

 

2.3.3 在嵌套對象使用

  • Controller類上添加 @Validated 註解,方法參數上添加 @Valid 註解,VO對象裏面字段上面添加對應註解即可 ;
  • 代碼如下:

@RestController
@RequestMapping("/xxx")
@Validated
public class PredictController {

    @PostMapping("/save")
    public ResponseEntity<List<PredictOutVo>> saveOrUpdatePredict(@RequestBody @Valid List<PredictInVo> predictInVoList) {
        // xxx
        return ResponseEntity.success(predictOutVoList);
    }

}

public class PredictInVo extends SysModel {

    @NotBlank(message = "OMS訂單編號oms_order_no不能爲空")
    private String omsOrderNo;

}

 

三  自定義

3.0 場景

  • 目前我需要校驗一個Integer類型的參數,是不連續的,如: 只能是1,2,3,6。目前提供的都解決不了,則需要自定義。

3.1 自定義註解


import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IntegerEnumValidator.class)
public @interface IntegerEnum {

    String message();

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

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

    int[] intValues();


}

 

3.2 自定義校驗器

  • value就是實際參數傳遞過來的值, intValues數組是我們定義的合法的參數範圍數組;
  • 關於怎麼找到的變量獲取方法,不斷debug即可知道如何獲取;


import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.metadata.ConstraintDescriptor;
import java.util.Map;

public class IntegerEnumValidator implements ConstraintValidator<IntegerEnum, Object> {

    private final String intVaules = "intValues";

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if(null == value) {
            return true;
        }
        ConstraintDescriptor<?> constraintDescriptor = ((ConstraintValidatorContextImpl) context).getConstraintDescriptor();
        Map<String, Object> attributes = constraintDescriptor.getAttributes();
        int[] intValues = (int[]) attributes.get(intVaules);
        boolean hasFlag = false;
        for (int intValue : intValues) {
            if (intValue == ((int) value)) {
                hasFlag = true;
                break;
            }
        }
        return hasFlag;
    }
}

3.3 全局異常處理(可忽略)

  • 有些時候需要全局異常處理,顯示異常信息,可以根據自己內部定義的異常處理進行獲取。本文是使用的springboot,就直接寫在了啓動類中,如下:


@SpringBootApplication
public class TssAcquireApplication  {


    /**
     * spring validation校驗異常處理
     */
    @ControllerAdvice
    class TssApiExceptionHandler {
        @ExceptionHandler(ConstraintViolationException.class)
        public void replayException(ConstraintViolationException replayException) {
            Set<ConstraintViolation<?>> constraintViolations = replayException.getConstraintViolations();
            if (!CollectionUtils.isEmpty(constraintViolations)) {
                StringBuilder errorInfo = new StringBuilder();
                constraintViolations.forEach(eachConstraintViolation -> {
                    errorInfo.append(eachConstraintViolation.getMessageTemplate()).append(";");
                });
                ResponseEntity<Object> responseEntity = ResponseEntity.fail(errorInfo.toString());
                HttpOutJson.out(responseEntity, HttpStatus.BAD_REQUEST.value());
            }
        }
    }


}

3.4 使用

  • 和2裏面的使用方式一樣,只不過字段上註解使用我們自定義的註解即可;
    @Valid
    @NotNull(message = "貨運類型不能爲空")
    @IntegerEnum(intValues = {0, 1, 2, 3, 4, 5, 6, 7, 9}, message = "貨運類型transport_type只能是0,1,2,3,4,5,6,7,9之一")
    private Integer transportType;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章