背景:
有下面这么一个类,要校验两字段query、image不能同时为空,应该怎么实现?已知的@NotBlank等标签都只能检验单个字段。
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.springframework.http.codec.multipart.FilePart;
@Data
public class MultiModalQARequest {
。。。。
/**
* 用户提问
*/
@NotBlank(message = "query不能为空")
private String query;
private FilePart image;
}
解决:
参考https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=8.0#section-class-level-constraints中的
我有以下实现:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = {NotBothBlankValidator.class})
@Documented
public @interface NotBothBlank {
String message() default "两个字段不能同时为空";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String firstFieldName();
String secondFieldName();
}
import com.zju.design.aiplatformdemo2.utils.StringUtil;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.function.BiFunction;
@Slf4j
public class NotBothBlankValidator
implements ConstraintValidator<NotBothBlank, Object> {
private NotBothBlank constraintAnnotation;
@Override
public void initialize(NotBothBlank constraintAnnotation) {
this.constraintAnnotation = constraintAnnotation;
}
private static BiFunction<Object, Field, Boolean> isBlank = (object, field) ->
{
log.info("NotBothBlankValidator field type {}", field.getType());
try {
field.setAccessible(true);
return (String.class.isAssignableFrom(field.getType()) ? StringUtil.isBlank((String) field.get(object)) : field.get(object) == null);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
};
@Override
public boolean isValid(Object validatedObject, ConstraintValidatorContext context) {
if (validatedObject == null) {
return true;
}
//通过反射拿到validatedObject对象的firstFieldName和secondFieldName字段的值,判断它们不能同时为空:
try {
Field firstField = validatedObject.getClass().getDeclaredField(constraintAnnotation.firstFieldName());
Field secondField = validatedObject.getClass().getDeclaredField(constraintAnnotation.secondFieldName());
return !(isBlank.apply(validatedObject, firstField) && isBlank.apply(validatedObject, secondField));
} catch (Exception e) {
log.error("NotBothBlankValidator error", e);
throw new RuntimeException(e);
}
}
}
业务代码的变更:
测试可用。
其它相关文档:
https://stackoverflow.com/questions/54638255/spring-boot-validation-one-from-two-not-null