【问题标题】:Private/scoped variable in JSF2/Facelets <ui:component>?JSF2/Facelets <ui:component> 中的私有/范围变量?
【发布时间】:2011-09-15 03:50:18
【问题描述】:

我可能在 JSF 中的可视化组件方面没有正确思考,但我想这是我的问题的一部分。我的问题是围绕 JSF 实现中声明的变量似乎缺乏范围。

所以,假设我有 /resources/comp/myPanel.xhtml:

<?xml version="1.0" encoding="UTF-8" ?>
<ui:component xmlns="http://www.w3.org/1999/xhtml"
              xmlns:h="http://java.sun.com/jsf/html"
              xmlns:f="http://java.sun.com/jsf/core" 
              xmlns:ui="http://java.sun.com/jsf/facelets"
              xmlns:c="http://java.sun.com/jsp/jstl/core"      
              xmlns:cc="http://java.sun.com/jsf/composite">
    <cc:interface>
    </cc:interface>
    <cc:implementation>
        <f:loadBundle var="bundle" basename="panelOnly.bundle" />

        <h:outputText value="#{bundle.myText}" />
    </cc:implementation>
</ui:component>

并且有一个资源包被加载到该组件中,panelOnly/bundle.properties:

myText = This is a panel resource

然后我有一个放置 myPanel 组件的页面,mainPage.xhtml:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core" 
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:comp="http://java.sun.com/jsf/composite/comp">
    <h:body>
        <f:view>
            <f:loadBundle basename="mainPage.bundle" var="bundle" />

            <comp:myPanel />

            <h:outputText value="#{bundle.myText}" />
        </f:view>
    </h:body>
</html>

并且有一个资源包被加载到主页中,mainPage/bundle.properties:

myText = This is a main page resource

现在,我假设我的页面应该呈现为:

This is a panel resource
This is a main page resource

但是,相反,我得到:

This is a panel resource
This is a panel resource

我认为这是因为我破坏了组件中“bundle”符号所指的内容,因此当 mainPage.xhtml 尝试解析该值时,它会查看组件的“bundle”对象而不是原始 mainPage 的对象。

迄今为止,我的解决方法是在我的组件中使用唯一的命名变量,这些变量永远不会与我的主页上的变量发生冲突。但是如果有一种方法可以让 JSF 将我的组件中声明的任何内容识别为本地范围的变量,而不是破坏调用者的符号,我更愿意这样做。

我认为在#{cc.attrs...} 下可以使用其他标签来制作局部范围的变量。如果您可以在答案中列举我的本地范围选项,那将非常有帮助。我怀疑我的 是一种特殊情况,并且可能没有针对该情况的解决方法,因为它不是在设计时考虑到 的。

谢谢!

附:我正在运行 Mojarra 2.1.1 (FCS 20110408)

(针对格式化和复制粘贴错误进行了编辑,2011 年 6 月 15 日)

【问题讨论】:

    标签: jsf jsf-2 resourcebundle scoping composite-component


    【解决方案1】:

    不幸的是,&lt;f:loadBundle&gt; 就是这样工作的。这是整个视图的一次性设置。并且同一视图中的任何后续 &lt;f:loadBundle&gt; 调用都将覆盖前一个。

    最好的办法是通过支持组件来管理它。

    <cc:interface componentType="myPanel">
    

    @FacesComponent(value="myPanel")
    public class MyPanel extends UIComponentBase implements NamingContainer {
    
        private ResourceBundle bundle;
    
        public MyPanel() {
            bundle = ResourceBundle.getBundle("panelOnly.bundle", 
                FacesContext.getCurrentInstance().getViewRoot().getLocale());
        }
    
        @Override
        public String getFamily() {
            return "javax.faces.NamingContainer";
        }
    
        public ResourceBundle getBundle() {
            return bundle;
        }
    
    }
    

    可以用作

    <cc:implementation>
        <h:outputText value="#{cc.bundle.myText}" />
    </cc:implementation>
    

    【讨论】:

    • 哇,你对 JSF 的掌握总是让我印象深刻! StackExchange 上有很多像这样的好答案。我将尝试使用 FacesComponent。我从您的使用示例中看到,我可以使用 NamingContainer 通过 getter 将其他符号挂在 cc 对象上。我想我可以通过&lt;cc:attribute&gt;'s 将初始化程序参数传递给我的 NamingContainer?
    • 不完全是这样。 需要复合组件的支持 UIComponent 来实现 NamingContainer 并将其作为家庭返回。另请参阅标签文档中componentType 属性的描述:download.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/… NamingContainer 只是负责生成正确的客户端 ID。感谢componentType#{cc} 现在指的是MyPanel 类的一个实例,您可以使用更多方法对其进行扩展。您可以通过“通常”的 EL 方式访问它的 getter 和操作。
    • 再举个例子,另见我对这个问题的回答stackoverflow.com/questions/6358066
    • 你说的有道理。我有你在我的书签中引用的 oracle javadocs 链接,但直到我阅读了这样的讨论,我才真正理解 JSF 的体系结构。迄今为止,我一直认为&lt;ui:component&gt; 将内容放在一块,但状态和操作将保留给单独的视图/会话/请求范围的bean。我现在从您的示例中看到,通过 componentType,我可以将状态和行为添加到我的 &lt;ui:component&gt;。很有启发性,再次感谢!
    猜你喜欢
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 2017-02-25
    • 2013-10-02
    相关资源
    最近更新 更多