一 簡介
- 後端開發接口,經常會需要校驗接口,可以使用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,也可以通過正則表達式和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;