Spring 中数据库驱动的资源捆绑
我在使“数据库驱动的资源包”工作时遇到问题。在下面的示例中,TextDAO
在应用程序启动期间正确注入,但是当访问 messageSource
时,会创建一个新的 Messages
对象 - 这就是重点。如何使这项工作有效?
<!-- message source -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="someapp.bundle.Messages" />
</bean>
Messages.java
@Component
public class Messages extends ListResourceBundle {
@Autowired
private TextDAO textDAO;
public Messages() {
log.debug("CONSTRUCTOR");
}
@Override
protected Object[][] getContents() {
// loading messages from DB
List<Text> texts = textDAO.findAll(); // textDAO is null
...
}
}
重新打开
正如 Bozho
所建议的,我按如下方式完成了我的资源包,但动态重新加载它时遇到问题。我认为 ReloadableResourceBundleMessageSource 用于属性文件,但也许也可以实现此目的。
public class DatabaseDrivenMessageSource extends ReloadableResourceBundleMessageSource {
private Logger log = LoggerFactory.getLogger(getClass());
private final Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
private TextDAO textDAO;
@Autowired
public DatabaseDrivenMessageSource(TextDAO textDAO) {
this.textDAO = textDAO;
reload();
}
@Override
protected MessageFormat resolveCode(String code, Locale locale) {
String msg = getText(code, locale);
MessageFormat result = createMessageFormat(msg, locale);
return result;
}
@Override
protected String resolveCodeWithoutArguments(String code, Locale locale) {
return getText(code, locale);
}
private String getText(String code, Locale locale) {
Map<String, String> localized = properties.get(code);
String textForCurrentLanguage = null;
if (localized != null) {
textForCurrentLanguage = localized.get(locale.getLanguage());
if (textForCurrentLanguage == null) {
textForCurrentLanguage = localized.get(Locale.ENGLISH.getLanguage());
}
}
return textForCurrentLanguage != null ? textForCurrentLanguage : code;
}
public void reload() {
properties.clear();
properties.putAll(loadTexts());
}
protected Map<String, Map<String, String>> loadTexts() {
log.debug("loadTexts");
Map<String, Map<String, String>> m = new HashMap<String, Map<String, String>>();
List<Text> texts = textDAO.findAll();
for(Text text: texts) {
Map<String, String> v = new HashMap<String, String>();
v.put("en", text.getEn());
v.put("de", text.getDe());
m.put(text.getKey(), v);
}
return m;
}
}
I have problem to make "database-driven resource bundle" work. In example below TextDAO
is properly injected during application start, but when messageSource
is accessed, a new Messages
object is created - that's the point. How to make this work ?
<!-- message source -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="someapp.bundle.Messages" />
</bean>
Messages.java
@Component
public class Messages extends ListResourceBundle {
@Autowired
private TextDAO textDAO;
public Messages() {
log.debug("CONSTRUCTOR");
}
@Override
protected Object[][] getContents() {
// loading messages from DB
List<Text> texts = textDAO.findAll(); // textDAO is null
...
}
}
RE-OPEN
As Bozho
suggest i did my resource bundle as below, but have problem to dynamically reload it. I suppose that ReloadableResourceBundleMessageSource is for properties files, but maybe it is possible to work this, too.
public class DatabaseDrivenMessageSource extends ReloadableResourceBundleMessageSource {
private Logger log = LoggerFactory.getLogger(getClass());
private final Map<String, Map<String, String>> properties = new HashMap<String, Map<String, String>>();
private TextDAO textDAO;
@Autowired
public DatabaseDrivenMessageSource(TextDAO textDAO) {
this.textDAO = textDAO;
reload();
}
@Override
protected MessageFormat resolveCode(String code, Locale locale) {
String msg = getText(code, locale);
MessageFormat result = createMessageFormat(msg, locale);
return result;
}
@Override
protected String resolveCodeWithoutArguments(String code, Locale locale) {
return getText(code, locale);
}
private String getText(String code, Locale locale) {
Map<String, String> localized = properties.get(code);
String textForCurrentLanguage = null;
if (localized != null) {
textForCurrentLanguage = localized.get(locale.getLanguage());
if (textForCurrentLanguage == null) {
textForCurrentLanguage = localized.get(Locale.ENGLISH.getLanguage());
}
}
return textForCurrentLanguage != null ? textForCurrentLanguage : code;
}
public void reload() {
properties.clear();
properties.putAll(loadTexts());
}
protected Map<String, Map<String, String>> loadTexts() {
log.debug("loadTexts");
Map<String, Map<String, String>> m = new HashMap<String, Map<String, String>>();
List<Text> texts = textDAO.findAll();
for(Text text: texts) {
Map<String, String> v = new HashMap<String, String>();
v.put("en", text.getEn());
v.put("de", text.getDe());
m.put(text.getKey(), v);
}
return m;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
basename
是一个字符串,因此它不是 spring bean,因此没有注入。您可以尝试做的是子类化
ReloadableResourceBundleMessageSource
并重写其中的一些方法(例如 -getMessage(..)
)。 DAO 应该被注入到子类中。basename
is a string, so it is not a spring bean, and hence no injection there.What you can try to do is to subclass
ReloadableResourceBundleMessageSource
and override some methods there (for example -getMessage(..)
). The DAO should be injected in the subclass.ReloadableResourceBundleMessageSource
创建由basename
属性命名的类的实例。该实例不会有 Spring 注入的任何依赖项。这就是Messages
对象中的textDAO
字段为 null 的原因。此 Spring 问题以附件形式提供了 JDBC 支持的 MessageSource 示例的源代码,其中您可以使用
ReloadableResourceBundleMessageSource
来代替。ReloadableResourceBundleMessageSource
creates an instance of the class named by thebasename
property. This instance will not have any of its dependencies injected by Spring. That's why thetextDAO
field in yourMessages
object is null.This Spring issue has the source code for an example JDBC backed MessageSource, as an attachment, which you can use instead of
ReloadableResourceBundleMessageSource
.有点老了,但仍然有意义......
我将带有JDBC后端的Spring Cloud Config Server用作I18N的资源捆绑包。
零代码。效果棒极了!
A bit old, but still relevant...
I am using Spring Cloud Config server with JDBC backend as resource bundle for i18n.
Zero code. Works awesome!