首页 > 解决方案 > 对于不完全为 4 位数的年份,JPA 年份验证抛出异常

问题描述

我想使用 JPA 在 Spring 应用程序中验证表单,但我在现场生产年份遇到问题。当我使用正好 4 位数字的年份时,验证成功,例如 2010。但是,当我输入小于 1000 或大于 9999 的表单值(非 4 位数字)时,我得到了这个异常:

Failed to convert property value of type java.lang.String to 
required type java.time.Year for property productionYear; 
nested exception is org.springframework.core.convert.ConversionFailedException: 
Failed to convert from type [java.lang.String] to 
type [@javax.persistence.Convert @javax.persistence.Column 
@javax.validation.constraints.NotNull @com.kucharek.motorcycleshop.data.ProductionYearConstraint 
java.time.Year] for value 12345; 
nested exception is java.lang.IllegalArgumentException: 
Parse attempt failed for value [12345]

该字段的 SQL 声明:

production_year year not null
check (production_year between
  year("1885-01-01") and year(current_date())
)

实体类中的Java声明:

@Convert(converter = YearAttributeConverter.class)
@Column(name = "production_year")
@NotNull(message = "Production year is obligatory")
@ProductionYearConstraint(message = "Production year should be between 1885 and current year")
private Year productionYear;

转换器类:

@Converter(autoApply = true)
public class YearAttributeConverter
        implements AttributeConverter<Year, Short> {

    @Override
    public Short convertToDatabaseColumn(Year attribute) {
        return (short) attribute.getValue();
    }

    @Override
    public Year convertToEntityAttribute(Short dbData) {
        return Year.of(dbData);
    }
}

验证注释:

@Constraint(validatedBy = ProductionYearValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProductionYearConstraint {
    String message() default "Invalid production year";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

验证器类:

public class ProductionYearValidator
    implements ConstraintValidator<ProductionYearConstraint, Year> {

    @Override
    public boolean isValid(Year year, ConstraintValidatorContext context) {
        return year != null && year.getValue() >= 1885 &&
                year.getValue() < Year.now().getValue() ;
    }
}

我做错了什么?我应该更改数据库或模型中的数据类型吗?如何处理异常并打印给用户我的自定义错误消息而不是打印堆栈跟踪?

标签: javaspringjpabean-validation

解决方案


我已经用自定义消息文件解决了这个问题。

配置自定义消息文件messages.yml的配置类:

@Configuration
    public class MessageSourceConfiguration {

    @Bean
    public MessageSource messageSource() throws IOException {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setCommonMessages(yamlProperties());
        return messageSource;
   }

    @Bean
    public Properties yamlProperties() throws IOException {
        YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
        bean.setResources(new ClassPathResource("messages.yml"));
        return bean.getObject();
    }
}

文件资源/messages.yml:

typeMismatch:
  motorcycle:
    productionYear: Production year should be number between 1885 and current year

推荐阅读