You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PrimeFaces 12复合属性传方法时SelectEvent为null的原因与解决

问题描述

使用PrimeFaces 12 + Jakarta EE 10开发时,将方法作为复合组件属性传递,出现传入的SelectEvent为null的问题:

  1. 复合组件<compositeremittance:RemittanceOutSettlementBanks>的接口定义:
<composite:interface>
    <composite:attribute name="selectReceiverBank" method-signature="void selectReceiverBank(org.primefaces.event.SelectEvent)" />
</composite:interface>
  1. 复合组件内部将该属性作为<p:ajax>的dialogReturn事件监听器:
<p:commandButton id="receiverBankSearch"
                 class="iscSelectCommand"
                 icon="fa fa-search"
                 actionListener="#{queryBuilder.showDialog()}"
                 immediate="true"
                 process="@this"
                 partialSubmit="true"
                 disabled="${not ModeOperator}">
    <f:param name="queryId" value="2"/>
    <p:ajax event="dialogReturn"
            listener="#{cc.attrs.selectReceiverBank}"
            update="receiverBankPanel"
            process="receiverBankPanel" />
</p:commandButton>
  1. 后端基类中的方法定义:
public void selectReceiverBank(SelectEvent event) {
    Banks selectedBank = (Banks) event.getObject();
    if (selectedBank != null) {
        this.remittance.setReceiverBankId(selectedBank.getBankId());
    }
}

问题现象:通过复合组件属性调用selectReceiverBank时,event参数为null;但直接将监听器绑定为#{myBean.selectReceiverBank}时,SelectEvent能正常传递。

原因与解决方案

原因

直接在<p:ajax>中使用listener="#{cc.attrs.selectReceiverBank}"时,JSF不会自动将dialogReturn事件生成的SelectEvent对象注入到方法参数中。复合组件的方法属性本质是一个方法表达式,若不明确指定参数传递,JSF会尝试调用无参版本的方法,导致有参方法接收的参数为null。而直接绑定#{myBean.selectReceiverBank}时,PrimeFaces的ajax机制会自动识别方法签名并传递事件参数。

解决方案

有两种可行的解决方式:

方式一:EL表达式中明确传递事件参数

修改复合组件内部的<p:ajax>标签,在监听器调用时直接传递event参数:

<p:ajax event="dialogReturn"
        listener="#{cc.attrs.selectReceiverBank(event)}"
        update="receiverBankPanel"
        process="receiverBankPanel" />

复合组件接口的method-signature保持原有定义即可,EL表达式会将dialogReturn事件产生的SelectEvent对象作为参数传递给目标方法。

方式二:通过复合组件后台类包装调用

  1. 创建复合组件对应的后台类,继承UINamingContainer:
@FacesComponent("RemittanceOutSettlementBanks")
public class RemittanceOutSettlementBanksComponent extends UINamingContainer {

    public void handleReceiverBankSelection(SelectEvent event) {
        // 获取复合组件属性中的方法表达式
        MethodExpression selectMethod = (MethodExpression) getAttributes().get("selectReceiverBank");
        // 调用方法并传递事件参数
        selectMethod.invoke(getFacesContext().getELContext(), new Object[]{event});
    }
}
  1. 修改复合组件接口,指定后台类(若组件名和类名匹配可省略此步):
<composite:interface componentType="RemittanceOutSettlementBanks">
    <composite:attribute name="selectReceiverBank" method-signature="void selectReceiverBank(org.primefaces.event.SelectEvent)" />
</composite:interface>
  1. 修改复合组件内部的<p:ajax>监听器,绑定到后台类的包装方法:
<p:ajax event="dialogReturn"
        listener="#{cc.handleReceiverBankSelection}"
        update="receiverBankPanel"
        process="receiverBankPanel" />

内容的提问来源于stack exchange,提问作者Ali Kheiri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:03:26