java - spring boot 中的自定义 jpa 验证

标签 java spring validation bean-validation

我有这样一个实体:

@Entity
@Table(name = "transaction_receiver")
public class TransactionReceiver implements Serializable, Addressable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotNull
    @Column(name = "contact_id", nullable = false)
    private String contactId;

    @Column(name = "datev_number")
    private String datevNumber;

    @NotNull
    @Column(name = "receiver", nullable = false)
    private String receiver;

    @NotNull
    @Size(min = 22, max = 34)
    @Column(name = "iban", length = 34, nullable = false)
    private String iban;

    @Size(min = 8, max = 11)
    @Column(name = "bic", length = 11, nullable = false)
    private String bic;

    @NotNull
    @Column(name = "institute")
    private String institute;

    @Column(name = "company")
    private String company;

我需要编写一个自定义验证“你可以提供一个空的 iban、bic 和 institute,没关系。但如果任何字段不为空,则必须满足上述约束条件”

我正在寻找实现此目的的最优雅的方法。

我目前的解决方案是 - 我认为有点脏,但有效 - 使用 @PrePersist 语句并从那里抛出异常

    @PrePersist
    public void checkBankData() {
        boolean ibanEmpty = iban == null || iban.isEmpty();
        boolean ibanValid = !ibanEmpty && iban.length() >= 22 && iban.length() <= 34;
        boolean bicEmpty = bic == null || bic.isEmpty();
        boolean bicValid = !bicEmpty && bic.length() >= 8 && bic.length() <= 11;
        boolean instituteEmpty = institute == null || institute.isEmpty();

        boolean validState = (ibanEmpty && bicEmpty && instituteEmpty) || ibanValid && bicValid;

        if (!validState) {
            throw new IllegalStateException(
                String.format(
                    "bank data is not empty and %s%s%s%s%s",
                    !ibanValid ? "iban has to be from 22 to 34 chars long" : "",
                    !ibanValid && !bicValid ? "and" : "",
                    !bicValid ? "bic has to be from 8 to 11 chars long" : "",
                    !ibanValid && !bicValid && instituteEmpty ? "and" : "",
                    instituteEmpty ? "institue must not be empty" : ""
                )
            );
        }
    }

它不受 @Valid 注释的约束。另一种方法是定义自定义 validator ,如下所述:http://docs.jboss.org/hibernate/validator/4.1/reference/en-US/html/validator-customconstraints.html

但这对我的约束来说真的看起来有点矫枉过正。

就没有其他优雅的方式吗?

最佳答案

使用 Hibernate Validation API 并不像看起来那么复杂,并且对于您的约束来说是一个不错的解决方案。 但是,您可以使用 Hibernate Validator 获得一种更简单的方法来定义约束,就像我们在一个项目中添加几个类所做的那样。您的约束将如下所示:

@Validate(method = "checkBankData", message = "{BankData.invalid.message}")
@Entity
@Table(name = "transaction_receiver")
public class TransactionReceiver implements Serializable, Addressable {

为此,您需要定义@Validate 注释和一个CustomValidator 类。

@Target({ ElementType.TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CustomValidator.class)
@Documented
/**
 * Annotation to allow custom validation against model classes
 */
public @interface Validate {

  /**
   * Validation message
   */
  String message();

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

  /**
   * Validation method name
   */
  String method() default "";
}


public class CustomValidator implements ConstraintValidator<Validate, BusinessObject> {

  private static Log log = LogFactory.getLog(CustomValidator.class);
  private String validator;


  @Override
  public void initialize(Validate constraintAnnotation) {
    validator = constraintAnnotation.method();
  }

  @Override
  public boolean isValid(BusinessObject bo, ConstraintValidatorContext constraintContext) {
    try {
      return isValidForMethod(bo);
    } catch (Exception e) {
      /* Error durante la ejecución de la condición o del validador */
      log.error("Error validating "+bo, e);
      return false;
    }
  }


  private boolean isValidForMethod(BusinessObject bo) throws Exception {
    Method validatorMethod =  ReflectionUtils.findMethod(bo.getClass(), validator, new Class[] {});
    if (validatorMethod != null) {
      /* Validator call */
      Boolean valid = (Boolean) validatorMethod.invoke(bo);
      return valid != null && valid;
    } else {
      /* Method not found */
      log.error("Validator method not found.");
      return false;
    }
  }

}

如果您计划定义更多约束,这种方法会很好。您可以使用更多功能扩展它,例如验证条件或添加多个验证等。

题外话:

  • 验证与 Spring Boot 无关,因此无需在您的问题中提及。

  • serialVersionUID = 1L;是一个非常糟糕的主意。使用您的 IDE serialVersionUID 生成器为该字段填充一个与 1L 不同的值。

关于java - spring boot 中的自定义 jpa 验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37878992/

相关文章:

java - 无法运行简单的 hello world

spring - 无法注入(inject) LoadBalanced 注释的 OAuth2RestTemplate

javascript - 如何在更改 ngPattern 使用的正则表达式时立即重新验证

java - Spring Bean 和 Hibernate 表

spring - 使用@Configurable域对象属性根据数据分配特定行为

javascript - 用于验证输入文本字段的单个 JavaScript 函数

html - 您如何使用 W3C 服务或类似服务验证包含 AJAX 内容的页面

java - 如何在 macOS Sierra 上卸载 Java 9

具有数据库可执行文件的 JavaFx 应用程序

java - 否定整个单词的正则表达式