【问题标题】:How to retrieve values of textboxes in JSF managed bean which are generated through a loop?如何检索通过循环生成的 JSF 托管 bean 中的文本框的值?
【发布时间】:2025-12-27 14:10:06
【问题描述】:

我需要通过如下循环生成文本框。

<p:panel id="dataPanel"  closable="true" toggleOrientation="horizontal" toggleable="true" header="Data">
    <h:panelGrid id="dataPanelGrid" columns="3" cellpadding="5">

        <c:forEach var="row" items="#{zoneChargeManagedBean.list}">

            <p:outputLabel for="txtCharge" value="#{row[1]}"/>          

            <p:inputText id="txtCharge" value="#{row[2]}" converter="#{bigDecimalConverter}" onkeydown="return isNumberKey(event, this.value);" label="#{row[1]}" required="false" maxlength="45">
                <f:validator validatorId="negativeNumberValidator"/>
                <f:attribute name="isZeroAllowed" value="false"/>

                <f:validator validatorId="bigDecimalRangeValidator"/>
                <f:attribute name="minPrecision" value="1"/>
                <f:attribute name="maxPrecision" value="33"/>
                <f:attribute name="scale" value="2"/>
            </p:inputText>

            <p:message for="txtCharge" showSummary="false"/>

        </c:forEach>

        <p:commandButton id="btnSubmit" update="dataPanel messages" actionListener="#{zoneChargeManagedBean.insert}" icon="ui-icon-check" value="Save"/>
        <p:commandButton value="Reset" update="dataPanel" process="@this">
            <p:resetInput target="dataPanel" />
        </p:commandButton>
    </h:panelGrid>
</p:panel>

给定文本框的值是来自数据库的BigDecimal 类型。

当按下给定的命令按钮时,应该从相应的 JSF 托管 bean 中检索这些文本框保存的值,以便可以在数据库中插入或更新它们。

如果可以在按下给定按钮时在某种集合(如java.util.List)中一次检索所有这些文本字段的值,那就更好了。

【问题讨论】:

  • 您可以使用 PrimeFaces 数据表 - 行编辑功能。 primefaces.org/showcase/ui/datatableRowEditing.jsf
  • 我不清楚这个问题。 ZoneChargeManagedBean 是您的代码,您应该最了解如何访问其数据。顺便说一句,使用索引来访问行数据似乎很尴尬,但如果没有 bean 的代码就很难说。
  • 您的具体问题是什么?您已经有一个 #{zoneChargeManagedBean.list} 来保存这些值。在action方法中检查时是否为空?
  • 新值不会在zoneChargeManagedBean.list 中累积,当然,当与&lt;c:foreEach&gt; 一起使用时,&lt;ui:repeate&gt; 不会发生这种情况,其中填充了新值(列表已经在从数据库中检索时填充,如果数据库表中有相应的行。更新只需要在列表持有的对象数组row[2]的最后一个元素中进行。最后一个元素的值显示在&lt;p:inputText&gt;)。
  • 哦,对了,你还在用 Spring 来管理 bean。显然,它的视图范围与c:forEach 不兼容,这会导致在每次迭代时重新创建 bean。在旧的 Mojarra 版本中,JSF 自己的视图范围中存在类似的错误。在以后的问题中,请描述实际问题! (并消除代码噪音,我看不出使用BigDecimal 而不是String 并让那些验证器/转换器、&lt;p:panel&gt; 等...与具体问题相关。

标签: jsf jsf-2 primefaces


【解决方案1】:

&lt;ui:repeate&gt;,一个渲染时间标签工作正常,但不是&lt;c:foreEach&gt;,一个视图构建时间组件(我无法解释为什么)但在这种特殊情况下,我发现&lt;p:dataGrid&gt; 更合适。 XHTML 已相应修改如下。

<p:panel id="dataPanel" rendered="#{zoneChargeManagedBean.renderedDataPanel}" closable="true" toggleOrientation="horizontal" toggleable="true" header="Data">
    <p:dataGrid columns="3" value="#{zoneChargeManagedBean.list}" var="row" paginator="true" paginatorAlwaysVisible="false" pageLinks="10" rows="15">
        <p:watermark for="txtCharge" value="Enter charge."/>
        <p:tooltip for="lblCharge" value="Some message."/>

        <p:column>
            <p:outputLabel id="lblCharge" for="txtCharge" value="#{row[1]}"/><br/>
            <p:inputText id="txtCharge" value="#{row[2]}" onkeydown="return isNumberKey(event, this.value);" converter="#{bigDecimalConverter}" label="#{row[1]}" required="false" maxlength="45">
                <f:validator validatorId="negativeNumberValidator"/>
                <f:attribute name="isZeroAllowed" value="false"/>

                <f:validator validatorId="bigDecimalRangeValidator"/>
                <f:attribute name="minPrecision" value="1"/>
                <f:attribute name="maxPrecision" value="33"/>
                <f:attribute name="scale" value="2"/>
            </p:inputText>
            <h:message for="txtCharge" showSummary="false" style="color: #F00;"/>
        </p:column>
    </p:dataGrid>

    <p:commandButton id="btnSubmit" update="dataPanel messages" actionListener="#{zoneChargeManagedBean.insert}" icon="ui-icon-check" value="Save"/>
    <p:commandButton value="Reset" update="dataPanel" process="@this">
        <p:resetInput target="dataPanel" />
    </p:commandButton>
</p:panel>

托管 bean:

@Controller
@Scope("view")
public final class ZoneChargeManagedBean implements Serializable
{
    @Autowired
    private final transient ZoneChargeService zoneChargeService=null;
    private ZoneTable selectedZone;     //Getter and setter
    private List<Object[]>list;         //Getter and setter
    private boolean renderedDataPanel;  //Getter and setter

    public ZoneChargeManagedBean() {}

    public void ajaxListener() {
        if(this.selectedZone!=null){
            list=zoneChargeService.getZoneChargeList(this.selectedZone.getZoneId());
            renderedDataPanel=true;
        }
        else {
            renderedDataPanel=false;
        }
    }

    public void insert() {
        //Just do whatever is needed based on the list with new values which is retrieved when <p:commandButton> as shown in the given XHTML is clicked.

        if(selectedZone!=null&&zoneChargeService.addOrUpdate(list, selectedZone)) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Message Summary", "Message"));
        }
        else {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, "Message Summary", "Message"));
        }
    }
}

ajaxListener() 方法中的服务方法返回对象数组类型的列表 - List&lt;Object[]&gt;

public List<Object[]>getZoneChargeList(Long id) {
    return entityManager.createQuery("select w.weightId, w.weight, zc.charge from Weight w left join w.zoneChargeSet zc with zc.zoneTable.zoneId=:id order by w.weight").setParameter("id", id).getResultList();
}

我无法使用相应的 JPA 条件查询,因为 with 运算符似乎不受 JPA 条件 API 的支持。

This method is invoked when an item from &lt;p:selectOneMenu&gt; is selected which is not covered in this question.

【讨论】: