Получение локализованного сообщения из 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 находится в "нормальном" контексте приложения.