JSF2.0 - 具有可选方法表达式的复合组件

Posted

技术标签:

【中文标题】JSF2.0 - 具有可选方法表达式的复合组件【英文标题】:JSF2.0 - Composite component with optional method expression 【发布时间】:2013-03-03 10:33:41 【问题描述】:

我正在实现一个复合组件,但我发现了一个我没有找到解决方案的问题。

我指定了页面作者可以或不可以传递的属性,但是我无法指定方法属性(Action 的方法表达式),如果未传递,则复合组件不会使用Composite:implementation 标签中的方法属性。

这是我的代码:

<composite:interface>
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#cc.attrs.actionMethod"
                      rendered="#cc.attrs.showComponent"
                      >
            <h:outputText value="#cc.attrs.namePrompt"/>    
       </p:commandLink>
    </div>
</composite:implementation>

在使用的时候,我没有指定“actionMethod”属性。像这样:

<util:foo namePrompt="SomeName" showComponent="true"/>

但我收到错误消息:

javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#cc.attrs.actionMethod'

有没有办法做到这一点?

【问题讨论】:

您可以将可选属性传递给actionListener。你是什​​么用例,当actionListener 没有被解析并且commandLink 被渲染时,你认为应该发生什么? 是的,链接组件已呈现,但是当链接组件中发生单击操作时,它抱怨我没有为属性 actionMethod 定义方法。但这是我的意图,有时我不想为 actionMethod 属性定义一个动作方法。这可能吗?我认为把'required = false'解决问题。 【参考方案1】:

您必须创建两个p:commandLink 元素并根据参数定义有条件地渲染它们:

<p:commandLink actionListener="#cc.attrs.actionMethod" rendered="#!empty cc.getValueExpression('actionMethod') and cc.attrs.showComponent">
  <h:outputText value="#cc.attrs.namePrompt"/>
</p:commandLink>
<p:commandLink rendered="#empty cc.getValueExpression('actionMethod')">
  <h:outputText value="#cc.attrs.namePrompt"/>
</p:commandLink>

【讨论】:

【参考方案2】:

将方法签名返回类型更改为java.lang.Object,并添加“null”作为默认值。

<composite:interface>
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.Object action()" required="false" default="null"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#cc.attrs.actionMethod"
                      rendered="#cc.attrs.showComponent"
                      >
            <h:outputText value="#cc.attrs.namePrompt"/>    
       </p:commandLink>
    </div>
</composite:implementation>

没有方法:

<util:foo namePrompt="SomeName" showComponent="true"/>

使用方法:

<util:foo actionMethod="#someBean.someMethod()" namePrompt="SomeName" showComponent="true"/>

【讨论】:

【参考方案3】:

另一种解决方案是使用操作方法创建自己的组件类型。示例:

<composite:interface componentType="myButton">
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink actionListener="#cc.action()" rendered="#cc.attrs.showComponent">
          <h:outputText value="#cc.attrs.namePrompt"/>    
      </p:commandLink>
   </div>
</composite:implementation>

并且组件类型必须看起来像:

@FacesComponent("myButton")
public class MyButton extends UINamingContainer 

    public MyButton () 
    

    public String action() 
        MethodExpression me = (MethodExpression) this.getAttributes().get("actionMethod");
        if (me != null) 
            try 
                Object result = me.invoke(FacesContext.getCurrentInstance().getELContext(),     null);
                if (result instanceof String) 
                    return (String) result;
                
             catch (ValidatorException ve) 
                throw ve;
            
        
        return null;
    

【讨论】:

【参考方案4】:

有同样的错误,我的组件也需要一个可选的操作方法。

所以我尝试使用方法签名在复合属性上添加一个默认参数,指向相应 FacesComponent 类上的方法,效果很好!

组件:

<composite:interface componentType="myButton">
    <composite:attribute name="namePrompt" required="true"/>
    <composite:attribute name="actionMethod" method-signature="java.lang.String  action()" required="false" default="#cc.dummyAction"/>
    <composite:attribute name="showComponent" default="false"/>
</composite:interface>

<composite:implementation>
    <div>
       <p:commandLink action="#cc.attrs.actionMethod"
                      rendered="#cc.attrs.showComponent"
                      >
            <h:outputText value="#cc.attrs.namePrompt"/>    
       </p:commandLink>
    </div>
</composite:implementation>

FacesComponent 类:

@FacesComponent("myButton")
public class MyButton extends UINamingContainer 

    public MyButton () 
    

    public String dummyAction() 
       return "";
    


【讨论】:

【参考方案5】:

避免将方法放在复合材料中。如果您需要这样做,请将具有该方法的类放在组合中,并像这样使用它:

<composite:interface>
   <composite:attribute name="classWithMethod" 
                        method-signature="java.lang.String"/>
</composite:interface>

以及实现:

<composite:implementation>
   <div>
      <p:commandLink 
         actionListener="#cc.attrs.classWithMethod.actionMethod">    
      </p:commandLink>
   </div>
</composite:implementation>

为我工作! :D

【讨论】:

以上是关于JSF2.0 - 具有可选方法表达式的复合组件的主要内容,如果未能解决你的问题,请参考以下文章

JSF 复合组件支持 bean EL 表达式作为必需属性的默认值失败,方法未知

JSF 2——在 f:ajax 上具有可选监听器属性的复合组件

JSF 2.0 复合组件 - ajax 渲染参数 OUTSIDE 组件定义

结合接缝 3 和 JSF2 复合组件 valueChangeListener 评估 El 表达式的问题

JSF 自定义复合组件与自定义经典组件有啥区别

Python复合语句