背景:请求参数个数多,类型多,校验的场景多
1.自定义属性校验注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ConditionalValidation {
String[] value();
}
2.创建请求实体,该例子中包含了类中属性是集合的场景
class MyObject {
@ConditionalValidation({"scenario1", "scenario3"})
private String property1;
@ConditionalValidation({"scenario1"})
private Integer property2;
@ConditionalValidation({"scenario1", "scenario2"})
private BigDecimal property3;
@ConditionalValidation({"scenario1", "scenario3"})
private List<MySubObject> property4;
// ... other properties
// Getters and setters
class MySubObject {
@ConditionalValidation({"scenario1", "scenario3"})
private String subProperty;
// ... other properties
// Getters and setters
}
}
3.编写校验方法,该例子中包含了几种类型:String、Integer、List
public static List<String> validateProperties(Object object, String[] validationScenarios) {
List<String> validationErrors = new ArrayList<>();
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
ConditionalValidation conditionalValidation = field.getAnnotation(ConditionalValidation.class);
if (conditionalValidation != null && Arrays.stream(conditionalValidation.value())
.anyMatch(value -> Arrays.asList(validationScenarios).contains(value))) {
try {
field.setAccessible(true);
Object fieldValue = field.get(object);
if (fieldValue == null) {
validationErrors.add("Property '" + field.getName() + "' cannot be null");
} else if (fieldValue instanceof String && ((String) fieldValue).isEmpty()) {
validationErrors.add("Property '" + field.getName() + "' cannot be empty");
} else if (fieldValue instanceof Integer && (Integer) fieldValue == 0) {
validationErrors.add("Property '" + field.getName() + "' cannot be zero");
} else if (fieldValue instanceof BigDecimal && ((BigDecimal) fieldValue).compareTo(BigDecimal.ZERO) == 0) {
validationErrors.add("Property '" + field.getName() + "' cannot be zero");
} else if (fieldValue instanceof List) {
List<?> listValue = (List<?>) fieldValue;
for (Object listItem : listValue) {
validationErrors.addAll(validateProperties(listItem, validationScenarios));
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return validationErrors;
}
4.编写测试例子,调用该校验方法
public static void main(String[] args) {
MyObject myObject = new MyObject();
myObject.setProperty1("value");
myObject.setProperty2(0); // Invalid value for testing
myObject.setProperty3(new BigDecimal("10.5"));
myObject.setProperty4(new ArrayList<>()); // Empty List for testing
List<String> validationErrors = validateProperties(myObject, new String[]{"scenario1", "scenario3"});
if (validationErrors.isEmpty()) {
System.out.println("No validation errors.");
} else {
System.out.println("Validation errors:");
for (String error : validationErrors) {
System.out.println("- " + error);
}
}
}
在上边这个例子中,我们通过传入的场景参数,来控制校验的属性。特别适合在拥有大批量属性的实体类进行校验的场景使用,避免过多的if判断,如果要调整校验逻辑,简单可控。