如何使用弹簧靴使用自定义验证器保存具有字段的对象?

时间:2019-07-11 14:25:27

标签: java spring-boot validation

谁能帮我为什么我无法在春季靴子中保存带有自定义验证器的字段的对象?

场景: 首先,我必须通过自定义验证器验证字段(工作正常),然后将实体保存到数据库中(这会中断)。 我在IntelliJ IDE上使用Spring boots框架。该代码在github上。 https://github.com/mhussainshah1/customvalidation

我有客户实体

@Entity
public class Customer {

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

    @ContactInfo //Custom Validator
    @NotNull
    private String contactInfo;

    // standard constructor, getters, setters
}

我有ContactInfoExpression实体

@Entity
public class ContactInfoExpression {

    @Id
    @Column(name="expression_type")
    private String type;

    private String pattern;

    //standard constructor, getters, setters
}

我有ContactInfoExpressionRepositoryCustomerRepository 扩展了CrudRepository<T, Id>

我在application.properties文件中使用具有以下配置的H2内存数据库。可以将contactInfoType属性设置为以下值之一:电子邮件,电话或网站

spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.show-sql=true

contactInfoType=email
#contactInfoType=phone
#contactInfoType=website

自定义验证器

@Configuration
public class ContactInfoValidator implements ConstraintValidator<ContactInfo, String> {

    private static final Logger LOG = LogManager.getLogger(ContactInfoValidator.class);

    @Value("${contactInfoType}")
    private String expressionType;

    private String pattern;

    @Autowired
    private ContactInfoExpressionRepository contactInfoExpressionRepository;

    @Override
    public void initialize(ContactInfo contactInfo) {
        if (StringUtils.isEmptyOrWhitespace(expressionType)) {
            LOG.error("Contact info type missing!");
        } else {
            pattern = contactInfoExpressionRepository.findById(expressionType)
                    .map(ContactInfoExpression::getPattern).get();
        }
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (!StringUtils.isEmptyOrWhitespace(pattern)) {
            return Pattern.matches(pattern, value);
        }
        LOG.error("Contact info pattern missing!");
        return false;
    }
}

自定义约束注释

@Constraint(validatedBy = { ContactInfoValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ContactInfo {
    String message() default "Invalid value";

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

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

我使用DataLoader类加载数据

@Component
public class DataLoader implements CommandLineRunner {

    @Autowired
    ContactInfoExpressionRepository contactInfoExpressionRepository;

    @Autowired
    CustomerRepository customerRepository;

    @Override
    public void run(String... args) throws Exception {
        String pattern = "[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
        ContactInfoExpression email = new ContactInfoExpression("email", pattern);
        contactInfoExpressionRepository.save(email);

        pattern = "^([0-9]( |-)?)?(\\(?[0-9]{3}\\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$";
        ContactInfoExpression phone = new ContactInfoExpression("phone", pattern);
        contactInfoExpressionRepository.save(phone);

        pattern = "^(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?$";
        ContactInfoExpression website = new ContactInfoExpression("website", pattern);
        contactInfoExpressionRepository.save(website);

        Customer customer1 = new Customer("mhussainshah79@gmail.com");
        customerRepository.save(customer1);// Error: can`t save
    }
}

我无法保存具有自定义验证器字段的客户对象。我在运行时遇到以下错误

java.lang.IllegalStateException: Failed to execute CommandLineRunner

Caused by: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

Caused by: javax.persistence.RollbackException: Error while committing the transaction

Caused by: javax.validation.ValidationException: HV000032: Unable to initialize com.example.customvalidation.ContactInfoValidator.

Caused by: java.lang.NullPointerException: null
    at com.example.customvalidation.ContactInfoValidator.initialize(ContactInfoValidator.java:41) ~[classes/:na]
    at com.example.customvalidation.ContactInfoValidator.initialize(ContactInfoValidator.java:18) ~[classes/:na]

1 个答案:

答案 0 :(得分:1)

该问题的解决方案是在application.properties文件中添加以下内容。

properties spring.jpa.properties.javax.persistence.validation.mode:none

参考: 如何避免在Spring Boot应用程序中进行双重验证,Sanjay Patel,2018年5月15日 https://www.naturalprogrammer.com/blog/16386/switch-off-jpa-validation-spring-boot