繁体   English   中英

使用Spring的Validator界面进行Bean验证中的自定义消息

[英]Custom Messages in Bean Validation using Spring’s Validator interface

我正在将Spring Boot 1.3.5与Rest Controllers一起使用,并且一切正常。

我还在官方文档中使用了Spring的验证示例技术(JSR-303 Bean验证API和Spring的验证器接口,我尝试了两者,并且遇到了相同的问题),并且验证工作正常,但是我无法配置自定义消息。

我已经配置了messages.properties文件,并且可以很好地访问此文件上的消息。 但是,此验证似乎无法读取或访问通过Spring Boot自动配置的我的消息源(messages.properties)。

我可以直接通过@Autowired从控制器中注入的消息源对象访问消息(代码中有注释)。 但是,Spring的验证器接口或JSR-303 Bean验证的绑定结果似乎无法访问MessageSource中加载的messages.properties。 我得到的结果是我的错误有代码,但没有默认消息。

这是我的应用程序类:

@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());
}

}

因此,此代码可以正常工作,并且由于我使用无效的Protocolo调用该方法而未调用该方法。 但是,我的angularJS客户端收到的响应中填充了错误代码,但所有默认消息为空,因为验证未看到加载的messages.properties。

有没有一种方法可以使我的Spring验证接口或JSR-303验证在Spring Boot中合并加载的message.properties(messagesource)? 我该如何纠正? 如果有必要,我也可以粘贴Spring Validation接口的代码示例。

非常感谢,

塔西奥(Tarcísio)。

测试代码:

@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());
}

}

编辑:Spring Boot 1.5.3中的已知错误请参阅https://github.com/spring-projects/spring-boot/issues/8979

1.5.3开始的 Spring Boot中 ,您需要执行此操作

@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;
    }
}

另请参阅文档

在Spring Boot中,applicaton MessageSource配置了MessageSourceAutoConfiguration,您不需要对其自动布线。 对于jsr303,请在messages.properties文件中创建正确的键值对。 对于“ protocolo”字段,属性文件中应具有以下值。

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());
    }
}

您应该在属性文件中具有以下值:

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

然后在控制器中,您可以通过从messageSource对象调用getMessage函数来获取消息

测试代码:

@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());                        
}

在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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM