Spring 中数据库驱动的资源捆绑

发布于 2024-10-29 18:37:54 字数 2965 浏览 1 评论 0原文

我在使“数据库驱动的资源包”工作时遇到问题。在下面的示例中,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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暮倦 2024-11-05 18:37:54

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.

甜味拾荒者 2024-11-05 18:37:54

ReloadableResourceBundleMessageSource 创建由 basename 属性命名的类的实例。该实例不会有 Spring 注入的任何依赖项。这就是 Messages 对象中的 textDAO 字段为 null 的原因。

此 Spring 问题以附件形式提供了 JDBC 支持的 MessageSource 示例的源代码,其中您可以使用 ReloadableResourceBundleMessageSource 来代替。

ReloadableResourceBundleMessageSource creates an instance of the class named by the basename property. This instance will not have any of its dependencies injected by Spring. That's why the textDAO field in your Messages 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.

冬天旳寂寞 2024-11-05 18:37:54

有点老了,但仍然有意义......
我将带有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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文