读取托管 bean 中的资源包属性

Posted

技术标签:

【中文标题】读取托管 bean 中的资源包属性【英文标题】:Read resource bundle properties in a managed bean 【发布时间】:2012-11-19 06:47:42 【问题描述】:

使用<resource-bundle> 文件,我可以在我的JSF 页面中包含i18n 文本。

但是是否可以在我的托管 bean 中访问这些相同的属性,以便我可以使用 i18n 值设置面孔消息?

【问题讨论】:

【参考方案1】:

假设您已将其配置如下:

<resource-bundle>
    <base-name>com.example.i18n.text</base-name>
    <var>text</var>
</resource-bundle>

如果您的 bean 是请求范围内的,您可以通过 &lt;var&gt;&lt;resource-bundle&gt; 注入为 @ManagedProperty

@ManagedProperty("#text")
private ResourceBundle text;

public void someAction() 
    String someKey = text.getString("some.key");
    // ... 

或者,如果您只需要一些特定的密钥:

@ManagedProperty("#text['some.key']")
private String someKey;

public void someAction() 
    // ... 


但是,如果您的 bean 处于更广泛的范围内,则在方法本地范围内以编程方式评估 #text

public void someAction() 
    FacesContext context = FacesContext.getCurrentInstance();
    ResourceBundle text = context.getApplication().evaluateExpressionGet(context, "#text", ResourceBundle.class);
    String someKey = text.getString("some.key");
    // ... 

或者如果你只需要一些特定的键:

public void someAction() 
    FacesContext context = FacesContext.getCurrentInstance();
    String someKey = context.getApplication().evaluateExpressionGet(context, "#text['some.key']", String.class);
    // ... 


您甚至可以通过标准的ResourceBundle API 来获取它,就像 JSF 本身已经在幕后所做的那样,您只需要在代码中重复基本名称:

public void someAction() 
    FacesContext context = FacesContext.getCurrentInstance();
    ResourceBundle text = ResourceBundle.getBundle("com.example.i18n.text", context.getViewRoot().getLocale());
    String someKey = text.getString("some.key");
    // ... 


或者,如果您通过 CDI 而不是 JSF 管理 bean,那么您可以为此创建一个 @Producer

public class BundleProducer 

    @Produces
    public PropertyResourceBundle getBundle() 
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().evaluateExpressionGet(context, "#text", PropertyResourceBundle.class);
    


并注入如下:

@Inject
private PropertyResourceBundle text;

或者,如果您使用 JSF 实用程序库 OmniFaces 的 Messages 类,那么您只需设置其解析器一次,即可让所有 Message 方法使用该捆绑包。

Messages.setResolver(new Messages.Resolver() 
    public String getMessage(String message, Object... params) 
        ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", Faces.getLocale());
        if (bundle.containsKey(message)) 
            message = bundle.getString(message);
        
        return MessageFormat.format(message, params);
    
);

另请参阅javadoc 和showcase page 中的示例。

【讨论】:

If your bean is request scoped 是唯一可以访问属性文件的范围吗? @Kuriel:JSF @ManagedProperty 无法在更广的范围内注入更窄的范围。只有 CDI @Inject 是。如果您碰巧使用 CDI,请前往 ***.com/q/28045667 @BalusC 在资源包文件中写入带参数的文本时应使用哪种语法形式? @séan35:只需将捆绑值(不是键!)传递给MessageFormat#format() @ManagedProperty("#text") 也适用于 @ViewScoped@FlowScoped beans。【参考方案2】:

另一种可能性:

faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config ...>
  <application>
    <locale-config>
      <default-locale>de</default-locale>
    </locale-config>
    <resource-bundle>
      <base-name>de.fhb.resources.text.backend</base-name>
      <var>backendText</var>
    </resource-bundle>
  </application>
</faces-config>

YourBean.java

FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ResourceBundle backendText = app.getResourceBundle(context, "backendText");
backendText.getString("your.property.key");

【讨论】:

【参考方案3】:

这是我正在使用的解决方案,不是那么简单,但至少可以工作:

头等舱:

package com.spectotechnologies.website.util;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;

/**
 *
 * @author Alexandre Lavoie
 */
public class MessageInterpolator extends ResourceBundleMessageInterpolator

    public static final String LANGUAGE_TAG_PATTERN = "\\[^]*\\";

    @Override
    public String interpolate(String p_sMessage, Context p_oContext)
    
        return super.interpolate(replaceMessages(p_sMessage),p_oContext);
    

    @Override
    public String interpolate(String p_sMessage, Context p_oContext, Locale p_oLocale)
    
        StringManager.setLocale(p_oLocale);

        return super.interpolate(replaceMessages(p_sMessage),p_oContext,p_oLocale);
    

    private String replaceMessages(String p_sMessage)
    
        Matcher oMatcher;
        String sKey;
        String sReplacement;
        StringBuffer sbTemp = new StringBuffer();

        oMatcher = Pattern.compile(LANGUAGE_TAG_PATTERN).matcher(p_sMessage);
        while(oMatcher.find())
        
            sKey = oMatcher.group().substring(1,oMatcher.group().length() - 1);

            sReplacement = StringManager.getString(sKey);

            if(!sReplacement.startsWith("???"))
            
                oMatcher.appendReplacement(sbTemp,sReplacement);
            
        

        oMatcher.appendTail(sbTemp);

        return sbTemp.toString();
    

二等:

package com.spectotechnologies.website.util;

import com.spectotechnologies.util.BundleManager;
import com.spectotechnologies.util.FacesSessionManager;
import java.util.Locale;

/**
 * set-up and interface a BundleManager
 * save the bundleManager into the session
 * @author Charles Montigny
 */
public final class StringManager

    /** the session name of this class bundle manager */
    public static final String BUNDLE_MANAGER_SESSION_NAME = "StringManager_BundleManager";

    /**  List of ResourceBundle names to load.
     * Will be load in order.
     * The last ones values may overrite the first ones values. */
    private final static String[] BUNDLE_LIST = 
        "com.spectotechnologies.hibernate.validation.resources.ValidationMessages",
        "com.spectotechnologies.website.general.resources.ValidationMessages",
        "com.spectotechnologies.website.general.resources.General";

    /** bundle manager */
    private static BundleManager m_oBundleManager = null;

    private static BundleManager getBundleManager()
    
        if(m_oBundleManager == null)
        
            // get the bundle into the session
            m_oBundleManager = (BundleManager)FacesSessionManager.getObject(BUNDLE_MANAGER_SESSION_NAME);
            if(m_oBundleManager == null)
            
                // session was empty, load a new one
                m_oBundleManager = new BundleManager();
                for(int iIndex = 0; iIndex < BUNDLE_LIST.length; iIndex++)
                
                    m_oBundleManager.addBundle(BUNDLE_LIST[iIndex]);
                
                // add the bundle to the session
                FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME, m_oBundleManager);
            
        
        return m_oBundleManager;
    

    /**
     * get a string value in the bundle manager by a string key
     * @param p_sKey the string key
     * @return the value of the string key
     */
    public static String getString(String p_sKey)
    
        return getBundleManager().getStringValue(p_sKey);
    

    /**
     * set the locale
     * @param p_oLocale the locale to set
     */
    public static void setLocale(Locale p_oLocale)
    
        getBundleManager().setLocale(p_oLocale);

        // update the session
        FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME,
                getBundleManager());
    

在您需要使用属性文件覆盖 BUNDLE_LIST 之后。完成后,像这样使用它:

sMessage = StringManager.getString("website.validation.modifySystem.modified");

如果您有任何问题,请不要犹豫!

编辑:

你还需要声明MessageInterpolator

META-INF/validation.xml

<validation-config
    xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
    <message-interpolator>com.spectotechnologies.website.util.MessageInterpolator</message-interpolator>
</validation-config>

【讨论】:

以上是关于读取托管 bean 中的资源包属性的主要内容,如果未能解决你的问题,请参考以下文章

从 JSF 中的托管 bean 获取资源文件的路径

cdi bean 中的资源注入

SpringBoot系列四:SpringBoot开发(改变环境属性读取资源文件Bean 配置模版渲染profile 配置)

资源属性配置

com.sun.faces.mgbean.ManagedBeanCreationException:在托管 bean 上执行资源注入时发生错误

我需要本地托管资源中的完整性和跨域属性吗?