1.33G 雨晨 Win10 企业版 x64 22H2 极简 19045.6693
2025/12/25 23:58:07
@RequestBody @Valid List<PlatProjectItemAndVerionVo> itemAndVersionVoList@NotBlank(message = "dataType参数不能为空") private String dataType;import javax.validation.Valid;但是根本就不生效,于是同事心生一计,采用自定义注解
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy=CustomFieldValidator.class) public @interface CustomVaildator { String message() default "字段校验失败"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; // 自定义参数 String pattern() default ""; int maxLength() default -1; boolean required() default false; }public class CustomFieldValidator implements ConstraintValidator<CustomVaildator, Object> { private CustomVaildator annotation; @Override public void initialize(CustomVaildator customVaildator) { // 未使用 } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { // 如果字段不是必需的且值为null,则通过校验 if (value == null && !annotation.required()) { return true; } // 如果是必需字段但值为null,则不通过校验 if (value == null && annotation.required()) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("字段不能为空") .addConstraintViolation(); return false; } String stringValue = value.toString(); // 长度校验 if (annotation.maxLength() > 0 && stringValue.length() > annotation.maxLength()) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("字段长度不能超过" + annotation.maxLength()) .addConstraintViolation(); return false; } // 正则表达式校验 if (!annotation.pattern().isEmpty()) { Pattern pattern = Pattern.compile(annotation.pattern()); if (!pattern.matcher(stringValue).matches()) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("字段格式不正确") .addConstraintViolation(); return false; } } return true; } }@CustomVaildator(required = true) private String dataType;依然不生效,于是同事尝试了以下方法
@Component public class AnnotationBasedValidator { // 缓存正则表达式以提高性能 private final Map<String, Pattern> patternCache = new ConcurrentHashMap<>(); /** * 通过反射扫描对象中带有指定注解的字段并进行校验 */ public <T> List<String> validateByAnnotation(T object) { List<String> errors = new ArrayList<>(); if (object == null) { errors.add("对象不能为空"); return errors; } Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { // 检查是否有自定义注解 if (field.isAnnotationPresent(CustomVaildator.class)) { try { field.setAccessible(true); Object value = field.get(object); CustomVaildator annotation = field.getAnnotation(CustomVaildator.class); String error = validateField(value, annotation, field.getName()); if (error != null) { errors.add(field.getName() + ": " + error); } } catch (IllegalAccessException e) { errors.add("校验字段" + field.getName() + "时发生错误: " + e.getMessage()); } } } return errors; } private String validateField(Object value, CustomVaildator annotation, String fieldName) { // 必填校验 if (annotation.required() && (value == null || (value instanceof String && StringUtils.isBlank((String) value)) || (value instanceof List && ((List<?>) value).isEmpty()))) { if (value instanceof List) { return "列表字段不能为空"; } return "字段不能为空"; } if (value == null) { return null; // 非必填字段为null时直接通过 } // List类型特殊处理 if (value instanceof List) { List<?> listValue = (List<?>) value; if (annotation.required() && listValue.isEmpty()) { return "列表字段不能为空"; } // 可以在这里添加对List元素的进一步校验逻辑 return null; } String stringValue = value.toString(); // 正则表达式校验 if (!annotation.pattern().isEmpty()) { // 使用缓存避免重复编译正则表达式 Pattern pattern = patternCache.computeIfAbsent(annotation.pattern(), Pattern::compile); if (!pattern.matcher(stringValue).matches()) { return "格式不符合要求"; } } return null; } /** * 校验列表中的所有对象 */ public <T> void validateListByAnnotation(List<T> list, String exceptionPrefix) { if (CollectionUtils.isEmpty(list)) { throw new IllegalArgumentException("列表不能为空"); } for (int i = 0; i < list.size(); i++) { T item = list.get(i); List<String> errors = validateByAnnotation(item); if (!errors.isEmpty()) { throw new IllegalArgumentException( String.format("%s列表中第%d个元素校验失败: %s", exceptionPrefix, i + 1, String.join(", ", errors))); } } } }annotationBasedValidator.validateListByAnnotation(platVersionAndItemVoList, "总成学科");这次终于可以,但是更加的不通用
根据同事的解释是,如果参数是单个对象,可以通过框架触发校验,但是如果是数组对象,无法通过框架触发校验。排查后发现同事引入的@valid注解是javax.validation.Valid,更换引入的@valid注解,这次数组对象也可以触发参数校验。
@RequestBody @Valid List<PlatProjectItemAndVerionVo> itemAndVersionVoListimport jakarta.validation.Valid;@NotBlank(message = "dataType参数不能为空") private String dataType;