问题说明
对接银行接口的时候经常有平台订单号和银行订单号二选一即可,普通的验证注解满足不了,需要自己实现
解决方案
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;
@Constraint(validatedBy = AtLeastOneNotEmptyValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface AtLeastOneNotEmpty {
String message() default "At least one of the fields must be not empty";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] fieldNames();
}
创建验证器类
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
public class AtLeastOneNotEmptyValidator implements ConstraintValidator<AtLeastOneNotEmpty, Object> {
private String[] fieldNames;
@Override
public void initialize(AtLeastOneNotEmpty constraintAnnotation) {
this.fieldNames = constraintAnnotation.fieldNames();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
for (String fieldName : fieldNames) {
Field field = value.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object fieldValue = field.get(value);
if (fieldValue != null && !fieldValue.toString().trim().isEmpty()) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
使用
/**
*
* 支付入参基类,新增需要继承
* @author zsp
* @date 2024/05/07
*/
@Data
@AtLeastOneNotEmpty(
fieldNames = {"orderId", "bankDeductionOrderId"},
message = "订单号或者银商订单号不能为空",
groups = {Pay.class, Query.class, Refund.class}
)
public class PayBo {
使用@Validated
注解即可触发
2. 一个非空另一个必须为空
创建自定义注解
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;
@Constraint(validatedBy = OneNotEmptyOneEmptyValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface OneNotEmptyOneEmpty {
String message() default "One field must be not empty and the other must be empty";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String firstField();
String secondField();
}
创建验证器类
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
public class OneNotEmptyOneEmptyValidator implements ConstraintValidator<OneNotEmptyOneEmpty, Object> {
private static final Logger LOGGER = Logger.getLogger(OneNotEmptyOneEmptyValidator.class.getName());
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(OneNotEmptyOneEmpty constraintAnnotation) {
this.firstFieldName = constraintAnnotation.firstField();
this.secondFieldName = constraintAnnotation.secondField();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
Field firstField = value.getClass().getDeclaredField(firstFieldName);
Field secondField = value.getClass().getDeclaredField(secondFieldName);
firstField.setAccessible(true);
secondField.setAccessible(true);
Object firstFieldValue = firstField.get(value);
Object secondFieldValue = secondField.get(value);
boolean isFirstFieldNotEmpty = firstFieldValue != null && !firstFieldValue.toString().trim().isEmpty();
boolean isSecondFieldNotEmpty = secondFieldValue != null && !secondFieldValue.toString().trim().isEmpty();
return (isFirstFieldNotEmpty && !isSecondFieldNotEmpty) || (!isFirstFieldNotEmpty && isSecondFieldNotEmpty);
} catch (NoSuchFieldException | IllegalAccessException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
return false;
}
}
}
使用
@OneNotEmptyOneEmpty(firstField = "field1", secondField = "field2", message = "field1 and field2 cannot both be empty or both be filled")
public class MyEntity {
private String field1;
private String field2;
使用@Validated
注解即可触发
注意
异常捕获的时候要注意,跟原有异常信息不太一致,需要修改为如下
/**
* 自定义验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public JgResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage());
if(e.getBindingResult().getFieldError() == null){
//两个中的一个不为空的情况,e.getBindingResult().getFieldError()为null会报错
return JgResponse.fail(StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", "));
}else {
return JgResponse.fail(e.getBindingResult().getFieldError().getDefaultMessage());
}
}