【问题标题】:Enable internationalization for class level constraint validator with Spring使用 Spring 为类级别约束验证器启用国际化
【发布时间】:2018-03-13 00:01:12
【问题描述】:

我正在使用 Spring Boot、Spring JPA、Spring Data REST、Spring HATEOAS、Hibernate 验证器。 我创建了自己的约束验证器。

注释:

    Target({ java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { TicketBundleValidator.class })
@Documented
public @interface ValidTicketBundle {

    String message() default "{server.validators.annotations.ValidTicketBundle.message}";

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

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

验证者:

public class TicketBundleValidator implements ConstraintValidator<ValidTicketBundle, TicketBundle> {

    @Override
    public void initialize(ValidTicketBundle constraintAnnotation) {
    }

    @Override
    public boolean isValid(TicketBundle value, ConstraintValidatorContext context) {
        if (value == null)
            return true;

        // Must be at least 1 row for each ticket bundle
        if (value.getRows().size() == 0)
            return false;

        // The start/end date must be valid
        if (value.getStartDate().isAfter(value.getEndDate()))
            return false;

        // The sum of payments can't be greater than the total price of the ticket
        // bundle
        if (value.getTotalPaymentsAmount().compareTo(value.getTotalPrice()) == 1)
            return false;

        // if ( !isValid ) {
        // constraintContext.disableDefaultConstraintViolation();
        // constraintContext.buildConstraintViolationWithTemplate(
        // "{org.hibernate.validator.referenceguide.chapter06." +
        // "constraintvalidatorcontext.CheckCase.message}"
        // )
        // .addConstraintViolation();
        // }
        return true;
    }

}

我将密钥和文本都放在 resources/i18n/messages.properties 和 resources/i18n/validation.properties 中:

server.validators.annotations.ValidTicketBundle.message = I dati inseriti non sono validi. Verificare nuovamente e ripetere l'operazione.

我创建了我的测试用例来验证一切是否正常:

 @Test
    @WithMockUser(roles = "ADMIN")
    public void saveTicketBundleWithWrongDateThrowsException() {
        TicketBundle ticketBundle = new TicketBundle();
        ticketBundle.setCustomer(customer);
        ticketBundle.setStartDate(Instant.now().plus(30, ChronoUnit.DAYS));
        ticketBundle.setEndDate(Instant.now());

        Set<ConstraintViolation<TicketBundle>> constraintViolations = validator.validate(ticketBundle);
        assertEquals(1, constraintViolations.size());
        ConstraintViolation<TicketBundle> constraintViolation = constraintViolations.iterator().next();
        assertEquals("I dati inseriti non sono validi. Verificare nuovamente e ripetere l'operazione.",
                constraintViolation.getMessage());
    }

但我失败了,因为似乎验证密钥消息没有得到解决:

 org.junit.ComparisonFailure: expected:<[I dati inseriti non sono validi. Verificare nuovamente e ripetere l'operazione.]> but was:<[{server.validators.annotations.ValidTicketBundle.message}]>
    at org.junit.Assert.assertEquals(Assert.java:115)

我确定我错过了一些东西,但不是很清楚是什么。这是一个 MVC 应用程序,但我不希望 REST 端点回复带有本地化消息:我希望测试用例也收到正确的消息。

为了完成图片,我的项目中有这个配置类:

@Configuration
@EnableHypermediaSupport(type = { HypermediaType.HAL })
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
 @Bean
public LocaleResolver localeResolver() {
    return new SmartLocaleResolver();
}

public class SmartLocaleResolver extends CookieLocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String acceptLanguage = request.getHeader("Accept-Language");
        if (acceptLanguage == null || acceptLanguage.trim().isEmpty()) {
            return super.determineDefaultLocale(request);
        }
        return request.getLocale();
    }
}

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:/i18n/messages");
    // messageSource.setDefaultEncoding("UTF-8");
    messageSource.setUseCodeAsDefaultMessage(true);
    messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));
    messageSource.setFallbackToSystemLocale(false);
    return messageSource;
}

【问题讨论】:

  • 在此上下文中如何引用消息源?
  • @RomanC 我以为是 Spring Boot 自动引用的。
  • 嘿@drenda 我问你一个问题?如果你不能回答这个问题,你应该提供一个明确的问题陈述,包括能够重现问题的代码,没有明确的陈述和合格的代码问题是题外话,应该尽快删除因为不可能在不知道细节的情况下给你一个解决方案,或者只是删除你的帖子,以免打扰开发者试图争论而不是提供细节。
  • @RomanC Like 消息源在此上下文中未引用以适当回复您的问题。但是,如果要要求删除一个有据可查的问题,您可以简单地避免回复并将空间留给知道如何回复的其他用户。该问题可能对其他有相同问题的用户有用。谢谢

标签: spring spring-mvc spring-boot hibernate-validator


【解决方案1】:

我在我的代码中发现了问题。我错了,休眠验证器查找消息字符串到根文件夹validationmessages.properties (https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=6.0#section-message-interpolation)

我在那里设置了消息,一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 2015-12-29
    • 1970-01-01
    • 2013-07-25
    相关资源
    最近更新 更多