通过Spring Framework中的注释从资源Bundle获取本地化消息

可以做到这一点吗?目前它是这样完成的:

<bean id="resource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>content.Language</value> 
        </list>
    </property>
</bean>

@Autowired
protected MessageSource resource;

protected String getMessage(String code, Object[] object, Locale locale) {
    return resource.getMessage(code, object, locale);
}

有没有办法让它像通过@Value注释获取属性一样?

<util:properties id="generals" location="classpath:portlet.properties" />

    @Value("#{generals['supported.lang.codes']}")
    public String langCodes;

因为必须调用该方法通常很好,但是例如在单元测试时,这是痛苦的......好吧,在某些情况下,Webdriver的PageObject模式,其中对象没有初始化,这将非常有帮助


答案 1

我相信你混合了两个概念:

  • 属性文件
  • 消息资源包

属性文件包含属性(与区域设置无关)。在Spring中,它们可以通过例如加载,并且可以在注释中使用。util:properties@Value

但是消息资源包(基于看起来像属性文件的文件)依赖于语言。在春季,您可以通过加载它们。但不要通过 注入字符串。您不能注入它们,因为每个bean的注入完成一次,将评估一次(大多数在开始时间),并且将注入计算的值。但这不是您在使用消息资源包时通常需要的。因为每次使用变量时都需要计算值,具体取决于用户的语言。org.springframework.context.support.ResourceBundleMessageSource@Value@Value@Value


但是您可以自己轻松构建它!

您唯一需要的就是此类:

import java.util.Locale;    
import javax.annotation.Resource;    
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

@Configurable
public class MSG {

    private String key;

    @Resource(name = "messageSource")
    private MessageSource messageSource;

    public MSG(String key) {
        super();
        this.key = key;        
    }

    public String value() {
        Locale locale = LocaleContextHolder.getLocale();                        
        return messageSource.getMessage(key, new Object[0], locale);
    }

    @Override
    public String toString() {
        return value();
    }
}

然后,您可以通过以下方式使用它:

@Service
public class Demo {

    @Value("demo.output.hallo")
    private MSG hallo;

    @Value("demo.output.world")
    private MSG world;

    public void demo(){
        System.out.println("demo: " + hello + " " + world);
    }    
}

要让它运行,您需要启用AspectJ@Configurable支持,并且(这很重要)您需要在相同的应用程序上下文中实例化Ressouce捆绑包消息源(例如,在Web应用程序中,您在大多数情况下将定义放在Web应用程序上下文中,但在这种情况下这不起作用, 因为 MSG 对象位于“正常”应用程序上下文中。<context:spring-configured />ReloadableResourceBundleMessageSource


答案 2

关键是,这只对单元测试有用。在实际应用程序中,Locale 是无法在批注中硬编码的运行时信息。区域设置是根据运行时中的用户区域设置确定的。

顺便说一句,您可以自己轻松实现这一点,例如:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Localize {

    String value();

}

public class CustomAnnotationBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        Class clazz = bean.getClass();
        do {
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Localize.class)) {
                    // get message from ResourceBundle and populate the field with it
                }
            }
            clazz = clazz.getSuperclass();
        } while (clazz != null);
        return bean;
    }

推荐