在Spring框架中通过注释从resourceBundle获取本地化消息

发布于 2024-11-13 09:20:23 字数 813 浏览 3 评论 0原文

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

<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 模式中对象没有初始化,这将非常有帮助

Is it possible to do this ? Currently it is done like this :

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

Is there a way for it to be like getting properties via @Value annotation ?

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

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

Because having to call the method is usually fine, but for instance when unit testing, this is pain in ... ... Well in some cases, webdriver's PageObject pattern where objects don't have no initialization, this would be really helpful

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毅然前行 2024-11-20 09:20:23

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

  • 属性文件
  • 消息资源包

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

但是消息资源包(基于看起来像属性文件的文件)是依赖于语言的。在 Spring 中,您可以通过 org.springframework.context.support.ResourceBundleMessageSource 加载它们。但不能通过@Value 注入字符串。您无法注入它们,因为每个 bean 都会执行一次 @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 Bundle 消息源(例如,在 Web 应用程序中,大多数情况下您将 ReloadableResourceBundleMessageSource 定义放在Web 应用程序上下文,但这在这种情况下不起作用,因为 MSG 对象位于“正常”应用程序上下文中。

I believe you mixed two concepts:

  • property files
  • message resource bundles

Property files contains properties (locale independent). In Spring they can be loaded for example via util:properties and can be used in @Value annotations.

But message resource bundles (which are bases on files that look like property files) are language dependend. In Spring you can load them via org.springframework.context.support.ResourceBundleMessageSource. But not inject in a String via @Value. You can not inject them because the @Value injection is done once per bean, the @Value will be evaluated once (most at start time), and the calculated value will be injected. But this is not what you normally need when you use Message Resource Bundles. Because then you need to evaluate the value every time the variable is used, depending on the language of an user.


But you can build it easely by your own!

The only things you need is this class:

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

Then you can use it in this way:

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

To get it running, you need to enable <context:spring-configured /> to turn on AspectJ @Configurable support, and (That is importent) you need to instanciate the Ressouce Bundle Message Source in the same application context (for example in web apps you put the ReloadableResourceBundleMessageSource definition in most cases in the web app context, but this does not work in this case, because the MSG object is in the "normal" application context.

深海里的那抹蓝 2024-11-20 09:20:23

关键是这仅对单元测试有用。在实际应用中,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;
    }

The point is that this is really useful only for Unit Testing. In real application, Locale is a runtime information that cannot be hardcoded in the annotation. Locale is decided based on Users locales in Runtime.

Btw you can easily implement this by yourself, something like :

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

    String value();

}

And

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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文