Пользовательские сообщения при проверке компонентов с использованием интерфейса Spring Validator

Я использую Spring Boot 1.3.5 с Rest Controllers, и все работает нормально.

Я также использую примеры методов проверки Spring из официальной документации (JSR-303 Bean Validation API и интерфейс проверки Spring, я попробовал оба и столкнулся с одной и той же проблемой), и проверки работают, но я не могу настроить пользовательские сообщения.

Я настроил файл messages.properties, и я могу получить доступ к сообщениям в этом файле без проблем. Однако эта проверка, похоже, не может читать или получать доступ к моему источнику сообщений (messages.properties), настроенному автоматически через весеннюю загрузку.

Я могу получить доступ к сообщениям непосредственно из объекта источника сообщений, введенного в контроллер через @Autowired (в коде есть комментарий). Однако результат привязки интерфейса валидатора Spring или проверки бина JSR-303, по-видимому, не может получить доступ к messages.properties, загруженным в MessageSource. В результате у моих ошибок есть коды, но нет сообщений по умолчанию.

Вот мой класс приложения:

@SpringBootApplication
@ImportResource({ "classpath:security/cas-context.xml", "classpath:security/cas-integration.xml",
    "classpath:security/security.xml" })
@EnableAutoConfiguration(exclude = VelocityAutoConfiguration.class) // http://stackoverflow.com/questions/32067759/spring-boot-starter-cache-velocity-is-missing

public class Application extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(Application.class);
}

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public ServletRegistrationBean cxfServlet() {
    return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}

@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
    return new SpringBus();
}

@Bean
public Nfse nfseService() {
    return new NfseImpl();
}

@Bean
public Endpoint endpoint() {
    EndpointImpl endpoint = new EndpointImpl(springBus(), nfseService());
    endpoint.publish("/nfseSOAP");
    return endpoint;
}

}

Вот мой Бин:

public class Protocolo {

private Long id;

@NotNull
@Min(1)
@Max(1)
private String protocolo;

private StatusProtocoloEnum status;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getProtocolo() {
    return protocolo;
}

public void setProtocolo(String protocolo) {
    this.protocolo = protocolo;
}

public StatusProtocoloEnum getStatus() {
    return status;
}

public void setStatus(StatusProtocoloEnum status) {
    this.status = status;
}

}

Вот мой контроллер отдыха:

@RestController
public class ProtocoloController {

@Autowired
private MessageSource messageSource;

@Autowired
private ProtocoloDAO protocoloDAO;

@RequestMapping(value = "/prot", method = RequestMethod.POST)
public void testar(@Valid @RequestBody Protocolo p) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    System.out.println(auth.getAuthorities());
    System.out.println(messageSource.getMessage("protocolo.tamanho", null, null)); 
// IN THIS PART I'M ABLE TO PRINT THE MESSAGE IF VALIDATION IS DISABLED
    System.out.println(p.getProtocolo());
}

}

Итак, этот код работает нормально, и метод не вызывается, так как я вызываю метод с недопустимым протоколом. Однако мой клиент angularJS получает ответ с заполненными кодами ошибок, но со всеми пустыми сообщениями по умолчанию, поскольку проверка не видит мои загруженные messages.properties.

Есть ли способ заставить мои интерфейсы проверки Spring или проверку JSR-303 включать загруженные свойства message.properties (источник сообщений) в весеннюю загрузку? Как я могу это исправить? Если необходимо, я также могу вставить свой пример кода интерфейсов Spring Validation.

Большое спасибо,

Тарсизио.

ПРОВЕРОЧНЫЙ КОД:

@RestController
public class ProtocoloController {

@Autowired
private MessageSource messageSource;

@Autowired
private ProtocoloDAO protocoloDAO;

@RequestMapping(value = "/prot", method = RequestMethod.POST)
public void testar(@Valid @RequestBody Protocolo p, BindingResult bindingResult) {
    System.out.println(messageSource.getMessage("Min.protocolo.protocolo", null, null));
    if (bindingResult.hasErrors()) {
               System.out.println(bindingResult.getFieldError().getDefaultMessage());
System.out.println(bindingResult.getFieldError().getCode());
    }
    System.out.println(p.getProtocolo());
}

}


person Tarcísio Filó    schedule 15.09.2016    source источник


Ответы (4)


Изменить: известная ошибка в Spring Boot 1.5.3 см. https://github.com/spring-projects/spring-boot/issues/8979

В Spring Boot начиная с 1.5.3 вам нужно сделать это

@Configuration
public class ValidationMessageConfig {

    @Bean
    public LocalValidatorFactoryBean mvcValidator(MessageSource messageSource) {

        LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
        factory.setValidationMessageSource(messageSource);

        return factory;
    }
}

и тогда это сработает.

В версии 1.5.2 и более ранних вы можете расширить WebMVcConfigurerAdapter

@Configuration
public class ProfileMvcConfig extends WebMvcConfigurerAdapter {

    private MessageSource messageSource;

    @Autowired
    public ProfileMvcConfig(MessageSource messageSource) {

        this.messageSource = messageSource;
    }

    /**
     * This method is overridden due to use the {@link MessageSource message source} in bean validation.
     *
     * @return  A Validator using the {@link MessageSource message source} in bean validation.
     */
    @Override
    public Validator getValidator() {

        LocalValidatorFactoryBean factory = new LocalValidatorFactoryBean();
        factory.setValidationMessageSource(messageSource);

        return factory;
    }
}

также см. документация

person Tobsch    schedule 21.04.2017
comment
Это, наконец, решило мою проблему. Однако мне также пришлось расширить WebMvcConfigurationSupport, хотя я использую Spring boot 1.5.6.RELEASE - person Abdullah Khan; 04.03.2019

В приложении Spring Boot MessageSource настроен с помощью MessageSourceAutoConfiguration, и вам не нужно его автоматически связывать. Для jsr303 создайте правильную пару ключ-значение в файле messages.properties. Для поля «протокол» в файле свойств должны быть следующие значения.

NotNull.protocolo.protocolo=Field cannot be left blank
Min.protocolo.protocolo=Minimum value must be {1}

Вы также можете проверять сообщения из файла свойств, как показано ниже в вашем коде.

public void testar(@Valid @RequestBody Protocolo p,BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
    System.out.println(bindingResult.getFieldError().getDefaultMessage());
    }
}
person abaghel    schedule 16.09.2016
comment
Я уже пробовал, и это не сработало. Я сделал автосвязь только для проверки, могу ли я получить сообщение непосредственно от контроллера с источником сообщений с автосвязью, и это было возможно. Просто с проверкой, выполненной JSR303, я не мог получить сообщение. Я получаю в клиенте именно этот ключ, который вы опубликовали: Min.protocolo.protocolo. Однако сообщение имеет значение null, хотя оно указано в messages.propeties. Я думаю, что мне не хватает некоторой конфигурации, которая соединяет проверку JSR303 или интерфейс проверки весны с источником сообщений, настроенным загрузкой весны. - person Tarcísio Filó; 16.09.2016
comment
Я отредактировал свой ответ и добавил код для bindingResult. Не могли бы вы проверить, используя это? - person abaghel; 16.09.2016
comment
Большое спасибо ! Я отредактировал свой пост с кодом, который вы предложили. Я также сохранил источник сообщения с autowired только для теста. В результате сообщение, напечатанное с источником сообщения, сгенерированным Springboot и автоматически подключенным к контроллеру, было именно тем сообщением, которое я настроил в message.properties: Min.protocolo.protocolo=my test. Тем не менее, сообщение, напечатанное в результате привязки, было сообщением по умолчанию spring -JSR @Min, хотя кодовое сообщение (которое я также напечатал в тесте с сообщением по умолчанию) было тем же, что я успешно напечатал через автоматический источник сообщения. - person Tarcísio Filó; 16.09.2016
comment
@abaghel Я использую Spring Boot 1.5.2 и имею ту же проблему, то есть получаю действительные коды ошибок, но сообщение по умолчанию не переопределяется. Любая работа для этого ?? - person Yogen Rai; 18.04.2017
comment
@abaghel это не работает. Я задал этот же вопрос и попробовал все комбинации. Можете ли вы опубликовать рабочий код, чтобы доказать это? stackoverflow.com/ вопросы/49499891/ - person szxnyc; 27.03.2018

вы должны иметь следующие значения в файле свойств:

Min.protocolo.protocolo=Minimum value must be {1}

затем в контроллере вы получаете сообщение, вызывая функцию getMessage из объекта messageSource

Тестовый код:

@RequestMapping(value = "/prot", method = RequestMethod.POST)                        
public void testar(@Valid @RequestBody Protocolo p, BindingResult bindingResult) {                        

    if (bindingResult.hasErrors()) {                        
        bindingResult.getFieldErrors().forEach(fieldError ->
            System.out.println(messageSource.getMessage(fieldError, Locale.getDefault()))
        );
    }                        
    System.out.println(p.getProtocolo());                        
}
person Lê văn Huy    schedule 13.05.2018

Я решил это в пользовательском сообщении при проверке Spring, прочитайте последнюю часть моего ответа.

Проверьте это пример тоже.

Я использовал собственный валидатор с пользовательской аннотацией. Мне нужно было изменить код в моем пользовательском валидаторе.

открытый класс PersonValidator реализует ConstraintValidator {

    @Override
    public boolean isValid(final Person person, final ConstraintValidatorContext context) { 
        if (somethingIsInvalid()) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("Something is invalid.").addConstraintViolation();
            return false;
        }

        return true;
    }
}
person Yan Khonski    schedule 11.04.2019