Получение локализованного сообщения из resourceBundle с помощью аннотаций в Spring Framework - PullRequest
15 голосов
/ 06 июня 2011

Возможно ли это сделать? В настоящее время это делается так:

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

Поскольку вызывать метод обычно нормально, но, например, при модульном тестировании это вызывает боль ... ... Ну, в некоторых случаях шаблон PageObject веб-драйвера, где объекты не имеют инициализации, это будет действительно полезно

Ответы [ 2 ]

28 голосов
/ 06 июня 2011

Я полагаю, вы смешали две концепции:

  • файлы свойств
  • пакеты ресурсов сообщений

Файлы свойств содержат свойства (не зависят от локали),В Spring они могут быть загружены, например, через util:properties и могут использоваться в аннотациях @Value.

Но пакеты ресурсов сообщений (которые основаны на файлах, которые выглядят как файлы свойств) зависят от языка.Весной вы можете загрузить их через 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);
    }    
}

Чтобы запустить его, вам нужно включить <context:spring-configured />, чтобы включить AspectJПоддержка @Configurable, и (это важно) вам нужно создать экземпляр сообщения Ressouce Bundle в том же контексте приложения (например, в веб-приложениях вы в большинстве случаев определяете определение ReloadableResourceBundleMessageSource в контексте веб-приложения, но это не такработать в этом случае, потому что объект MSG находится в «нормальном» контексте приложения.

4 голосов
/ 06 июня 2011

Дело в том, что это действительно полезно только для модульного тестирования.В реальном приложении 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;
    }
...