JSF 2.2嵌套自定义复合组件中#{cc.attrs}引用问题咨询
这个问题我之前也碰到过,本质是JSF复合组件的上下文作用域规则导致的:当你在父复合组件y:parent的实现里嵌套另一个复合组件<y:child>时,嵌套组件内部的#{cc}会指向自身的复合组件实例,而不是外层的父组件,所以两处#{cc.attrs}才会指向不同的属性。
下面给你几个实用的解决办法,按需选择就行:
方法1:提前把父组件属性存为页面变量
这是最直接省心的方式,在父组件实现的开头,用<c:set>把父组件的#{cc.attrs}存成一个页面级变量,之后在嵌套的<y:child>里直接引用这个变量就好:
<!-- y:parent 的实现代码 --> <cc:implementation> <!-- 把父组件的属性集合存为页面变量,避免被嵌套组件的上下文覆盖 --> <c:set var="parentAttrs" value="#{cc.attrs}" /> <a id="#{cc.attrs.myAttribute.myProperty}" /> <y:child> <!-- 直接用提前存好的变量,不再依赖#{cc.attrs} --> <a id="#{parentAttrs.myAttribute.myProperty}" /> </y:child> </cc:implementation>
这里要注意用<c:set>而不是<ui:param>,因为<ui:param>的作用域容易被嵌套组件的上下文干扰,<c:set>默认是页面作用域,稳定性更强。
方法2:给子组件显式传递父组件属性
如果想让代码更规范、耦合度更低,可以给<y:child>的组件接口加一个专门的属性,用来接收父组件需要传递的值:
首先修改<y:child>的标签定义(比如y:child.taglib.xml):
<cc:interface> <!-- 新增属性,专门接收父组件的myAttribute --> <cc:attribute name="parentMyAttribute" /> <!-- 你原有的其他属性... --> </cc:interface>
然后在父组件里把值传递过去:
<!-- y:parent 的实现代码 --> <cc:implementation> <a id="#{cc.attrs.myAttribute.myProperty}" /> <!-- 把父组件的myAttribute传给子组件的parentMyAttribute --> <y:child parentMyAttribute="#{cc.attrs.myAttribute}"> <a id="#{cc.attrs.parentMyAttribute.myProperty}" /> </y:child> </cc:implementation>
这种方式的好处是子组件的职责更清晰,不需要依赖父组件的内部结构,后续维护起来更方便。
方法3:通过组件绑定访问父组件实例
如果需要更灵活地访问父组件的其他方法或属性,可以给父组件绑定一个自身实例,然后在子组件里通过这个实例来获取属性:
先在父组件的接口里加一个绑定属性:
<!-- y:parent.taglib.xml --> <cc:interface> <cc:attribute name="myAttribute" required="true" /> <!-- 新增绑定属性,用来存储父组件自身实例 --> <cc:attribute name="parentComponent" type="javax.faces.component.UIComponent" /> </cc:interface>
然后在父组件实现里把自身绑定到这个属性:
<!-- y:parent 的实现代码 --> <cc:implementation> <!-- 将当前父组件实例绑定到属性上 --> <f:attribute name="parentComponent" value="#{cc}" /> <a id="#{cc.attrs.myAttribute.myProperty}" /> <y:child> <!-- 通过父组件实例访问它的属性 --> <a id="#{cc.attrs.parentComponent.attrs.myAttribute.myProperty}" /> </y:child> </cc:implementation>
不过这种方式耦合度稍高,除非你需要频繁访问父组件的其他功能,否则前两种方法更合适。
小提示
尽量避免在嵌套复合组件里直接依赖外层的#{cc}上下文,因为JSF的复合组件上下文是“就近绑定”的,嵌套组件会覆盖外层的#{cc}指向。如果是多层嵌套,逐层用#{cc.parent}向上找也容易出错,不如提前存变量或者显式传递属性来得可靠。
内容的提问来源于stack exchange,提问作者Xavier Portebois

