Получение локализованного сообщения из resourceBundle через аннотации в Spring Framework

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

<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 веб-драйвера, где объекты не имеют инициализации, это было бы действительно полезно


person lisak    schedule 05.06.2011    source источник
comment
Я также задаюсь вопросом, почему этой функции не существует, в 3.1 и, возможно, 3.2 нет признаков того, что это нужно реализовать.   -  person lisak    schedule 06.06.2011
comment
Является ли: support.lang.codes парой ключ-значение файла свойств, или это должно быть программное вычисление значения всех поддерживаемых языков?   -  person Ralph    schedule 06.06.2011
comment
Это просто ключ-значение файла свойств. На самом деле это очень удобный способ получения свойств. Я ожидаю от Spring чего-то подобного в отношении локализации... например, @Localize(#{langCode['some.error.message]})   -  person lisak    schedule 06.06.2011


Ответы (2)


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

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

Файлы свойств содержат свойства (независимые от локали). В 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 находится в «обычном» контексте приложения.

person Ralph    schedule 06.06.2011
comment
Ральф, ничего не перепутал, пользуюсь обоими уже 3 года. Я просто сказал, что было бы удобно для Unit-тестирования, если бы Spring был. Я сделал это, как сказал Эдгар, я использую BeanPostProcessor для заполнения аннотированных полей из ResourceBundle. Я думаю, что это более приятное решение, чем использование аннотации @Value для этого случая. Но большое спасибо за показ этого варианта использования аннотации @Value, я не знал, что смогу это сделать. - person lisak; 06.06.2011
comment
Я вижу, вас смутила аннотация @Value. Я не хотел использовать аннотации @Value как таковые, я имел в виду аннотации - person lisak; 06.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;
    }
person lisak    schedule 06.06.2011