Получение локализованного сообщения из 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;

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

Ответы

Ответ 1

Дело в том, что это действительно полезно только для Unit Testing. В реальном приложении Locale - это информация о времени выполнения, которая не может быть жестко указана в аннотации. Локаль определяется на основе локальных пользователей во время выполнения.

Btw вы можете легко реализовать это самостоятельно, что-то вроде:

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

Ответ 2

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

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

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

Но пакеты ресурсов сообщений (которые основаны на файлах, которые выглядят как файлы свойств) зависят от языка. В Spring вы можете загрузить их через org.springframework.context.support.ResourceBundleMessageSource. Но не вводить в String через @Value. Вы не можете вводить их, потому что инъекция @Value выполняется один раз за bean, @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 Message Source в том же контексте приложения (например, в веб-приложениях, которые вы используете поместите определение ReloadableResourceBundleMessageSource в большинстве случаев в контексте веб-приложения, но в этом случае это не работает, потому что объект MSG находится в "нормальном" контексте приложения.