基于Java配置Spring @Valid无法映射国际化得解决

    相信很多小伙伴在用国际化配置文件来配置错误消息提示,但总是无法映射到自己配置的消息,楼主也折腾了一下午,因为网上的大量配置都是基于XML的,但楼主用的是基于Java的配置,其实原理是一样的,楼主走了不少弯路,接下来和大家分享下。

  首先我们通过Spring的源代码来分析下Valid的实现流程,当前端控制器器发现控制器有@Valid这个 annotation时,会去找实现这个annotion的类,定义这个annotion的接口在org.springframwork.validation这个包里,在这个包里,定义这个annotation的是 Validator这个接口,另外spring还定义了一个SmartValidator这个接口,这个接口继承了原始的Valiatoto接口,我也不明白他为什么要这样做.我们可以看到, SpringValidatorAdapter这个类实现了这个接口,看名字,我们就知道它用了适配器的模式,所以整个大逻辑就在这个类里了,如果我们自定义了 validation类,那么Spring就会用我们自定义的bean,否则就用Spring自己的校验类,具体校验逻辑我们就不看,校验完后,结果会被交给DataBinder,这个类实现了Spring的Error接口,Error类定义了对应错误信息的处理机制 ,它根据errorCode去Valid Bean 中绑定的ResourceMessgae去找信息,这样Spring就会通过key来找到对应的信息。如果我们没有自定义Valid类时,Spring会用它自己的校验类,处理逻辑是相同,只不过它自己会从类的根目录下去找ValidationMessages.propertis,这个名字是它自己定义的,如果没有找到,他就会返回defaultMessage,也就是我在校验规则时写的错误信息。

  好了,原理粗略的了解下,那么核心就是要让Spring使用我们自定义的ResourceMessage.刚开始我只是在RootConfig中定义了自己的校验类,并且配置了ResourceMessage.

@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean()
{
    LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
    localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
    localValidatorFactoryBean.setValidationMessageSource(ResourceBundleMessageSource());
    return localValidatorFactoryBean;
}

@Bean
public ResourceBundleMessageSource ResourceBundleMessageSource()
{
    ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
    resourceBundleMessageSource.setBasename("i18n/ValidationMessages");
    resourceBundleMessageSource.setCacheSeconds(60);
    resourceBundleMessageSource.setDefaultEncoding("UTF-8");
    return resourceBundleMessageSource;
}

可是无论我怎么配置都映射不到国际化信息,机智的我就想是不是Spring根本就没用我的类,于是我就在根目录下写了个properties文件,果然映射了,为什么他没有用我定义的类那,其实很简单,我只是定义这个类,并没有地方用啊。所以我们要让Spring去用这个类.SpringMvc部分的配置代码继承了 WebMvcConfigureAdapter 这个类,在这个类中我找了原因。

@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}

/**
 * {@inheritDoc}
 * <p>This implementation returns {@code null}
 */
@Override
public Validator getValidator() {
   return null;
}

/**
 * {@inheritDoc}
 * <p>This implementation is empty.
 */
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}

/**
 * {@inheritDoc}
 * <p>This implementation is empty.
 */
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}

SpringMvc会通过 getValidator来获取自定义的类,而如果我们没有覆写这个方法的时候,它直接就返回null了,那它就用自己默认的校验类了,所以我们必须将自定义的校验Bean 返回给SpringMvc,问题终于解决了,其实这个问题还是自己对Spring基于java配置不太熟悉造成的,其实基于XML的配置也一样,虽然你定义了校验Bean,但还是要告知Spring的,也就是  <mvc:annotation-driven validator="xxxxx">  这个配置,有了这个配置,springMvc才会用你自己定义的处理类。总结一句话就是,大家配置好校验Bean时,一定要让SpringMvc知道,因为Spring获取校验类是从SpringMVC中获取的,其实Valid本来就属于SpringMvc的,而我错误的理解认为在Spring中,只要定义,了校验Bean,Spring在初始化时,就自动替换了默认的校验类。好了,贴粗自己的基于Java配置SpringMvc部分代码(并不是Spring 和 Servlet的配置代码,只是针对SpringMVC的配置代码)。

@Configuration
@EnableWebMvc
@ComponentScan("org.gameloft.www")
public class RestServiceConfiguration extends WebMvcConfigurerAdapter {


    private static Logger logger = LogManager.getLogger(RestServiceConfiguration.class);

    public RestServiceConfiguration()
    {
        logger.info("Init RestService ");
    }

    /**
     * 注册拦截器
     * @param registry
     */
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestProcessingTimeInterceptor());
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public Validator getValidator() {
        logger.info("Init Validator ");
        return localValidatorFactoryBean();
    }

    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean()
    {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
        localValidatorFactoryBean.setValidationMessageSource(ResourceBundleMessageSource());
        return localValidatorFactoryBean;
    }

    @Bean
    public ResourceBundleMessageSource ResourceBundleMessageSource()
    {
        ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
        resourceBundleMessageSource.setBasename("i18n/ValidationMessages");
        resourceBundleMessageSource.setCacheSeconds(60);
        resourceBundleMessageSource.setDefaultEncoding("UTF-8");
        return resourceBundleMessageSource;
    }
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值