Primefaces Bean 对象未正确更新

Primefaces Bean Object isn't updated correctly

我遇到了以下问题。我有一个 XHTML:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    template="../layout.xhtml">

    <ui:define name="header">
        <div id="header">
            Abfragen
        </div>
    </ui:define>

    <ui:define name="main">
        <p:toolbar>
            <p:toolbarGroup>
                <p:commandButton value="Neu" icon="pi pi-plus" actionListener="#{abfrageHandler.newAbfrage}"
                                 update="manage-queries-content" oncomplete="PF('manageQueriesDialog').show()"
                                 styleClass="ui-button-success" style="margin-right: .5rem">
                    <p:resetInput target=":ucmdbform:ucmdbtab:manage-ucmdb-queries-content"/>
                </p:commandButton>
            </p:toolbarGroup>
        </p:toolbar>
        
        <p:dataTable id="dt-queries" widgetVar="dtQueries" reflow="true" showGridlines="true" size="small"
                var="querie" value="#{abfrageHandler.abfragen}">
            <p:column headerText="Abfrage">
                <h:outputText value="#{querie.name}" />
            </p:column>
            <p:column headerText="TQL">
                <h:outputText value="#{querie.tql}" />
            </p:column>
            <p:column headerText="Zyklus">
                <h:outputText value="#{querie.zyklus}" />
            </p:column>
            <p:column headerText="Typ">
                <h:outputText value="#{querie.typ}" />
            </p:column>
            <p:column exportable="false">
                <p:commandButton icon="pi pi-pencil" update="manage-queries-content"
                        oncomplete="PF('manageQueriesDialog').show()"
                        styleClass="edit-button rounded-button ui-button-success" process="@this">
                    <f:setPropertyActionListener value="#{querie}" target="#{abfrageHandler.selected}"/>
                    <p:resetInput target="manage-queries-content"/>
                </p:commandButton>
                <p:commandButton icon="pi pi-search" actionListener="#{abfrageHandler.startAbfrage(querie)}"
                        styleClass="edit-button rounded-button ui-button-success" process="@this">
                </p:commandButton>
                <p:commandButton class="ui-button-warning rounded-button" icon="pi pi-trash" process="@this"
                        oncomplete="PF('deleteQuerieDialog').show()">
                    <f:setPropertyActionListener value="#{querie}" target="#{abfrageHandler.selected}"/>
                </p:commandButton>
            </p:column>
        </p:dataTable>
    
        <p:dialog header="Abfrage" showEffect="fade" modal="true" width="600px"
                    widgetVar="manageQueriesDialog" responsive="true">
            <p:outputPanel id="manage-queries-content" class="ui-fluid">
                <p:outputPanel rendered="#{not empty abfrageHandler.selected}">
                    <div class="p-field">
                        <p:outputLabel for="abfName">Name</p:outputLabel>
                        <p:inputText id="abfName" value="#{abfrageHandler.selected.name}" required="true"/>
                    </div>
                    <div class="p-field">
                        <p:outputLabel for="abfTql">TQL</p:outputLabel>
                        <p:inputText id="abfTql" value="#{abfrageHandler.selected.tql}" required="true"/>
                    </div>
                    <div class="p-field">
                        <p:outputLabel for="abfZyklus">Zyklus</p:outputLabel>
                        <p:inputText id="abfZyklus" value="#{abfrageHandler.selected.zyklus}" required="true"/>
                    </div>
                    <div class="p-field">
                        <p:outputLabel for="@next">Abfrageart</p:outputLabel>
                        <p:selectOneMenu id="abfTyp" value="#{abfrageHandler.selected.typ}" required="false">
                            <f:selectItem itemLabel="Eins wählen" itemValue=""/>
                            <f:selectItems value="#{abfrageHandler.requestResolutions}" var="reso"
                                itemLabel="#{reso.toString()}" itemValue="#{reso}"/>
                        </p:selectOneMenu>
                    </div>
                </p:outputPanel>
            </p:outputPanel>
    
            <f:facet name="footer">
                <p:commandButton value="Speichern" icon="pi pi-check" actionListener="#{abfrageHandler.saveAbfrage}"
                                update="manage-queries-content" process="manage-queries-content @this"/>
                <p:commandButton value="Abbruch" icon="pi pi-times" onclick="PF('manageQueriesDialog').hide()"
                                class="ui-button-secondary"/>
            </f:facet>
        </p:dialog>
    
        <p:confirmDialog widgetVar="deleteQuerieDialog" showEffect="fade" width="300"
                         message="TQL wirklich löschen?" header="Bestätigen" severity="warn">
            <p:commandButton value="Ja" icon="pi pi-check" actionListener="#{abfrageHandler.deleteParameter}"
                             process="@this" oncomplete="PF('deleteQuerieDialog').hide()"/>
            <p:commandButton value="Nein" type="button" styleClass="ui-button-secondary" icon="pi pi-times"
                             onclick="PF('deleteQuerieDialog').hide()"/>
        </p:confirmDialog>          
    
    </ui:define>
</ui:composition>

以及后端中的以下 bean:

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.PrimeFaces;

import main.java.ucmdbtool.RequestResolutions;
import main.java.ucmdbtool.UcmdbAbfrageInteface;
import main.java.ucmdbtool.table.Abfrage;
import main.java.ucmdbtool.table.UcmdbAbfTableHandler;

@SuppressWarnings("serial")
@Named("abfrageHandler")
@ViewScoped
public class AbfrageHandler implements Serializable {

    private List<Abfrage> abfragen = new ArrayList<>();
    private Abfrage selected;
    private RequestResolutions[] requestResolutions;
    
    @PostConstruct
    private void init() {
        abfragen = UcmdbAbfTableHandler.getAbfragen();
        requestResolutions = RequestResolutions.values();
    }

    public void newAbfrage() {
        selected = new Abfrage();
    }

    public void saveAbfrage() {
        if (selected.getPk() == null) {
            selected.setPk(UUID.randomUUID());
            UcmdbAbfTableHandler.insertAbfrage(selected);
            abfragen.add(selected);
        }
        else {
            UcmdbAbfTableHandler.updateAbfrage(selected);
        }
        PrimeFaces.current().executeScript("PF('manageQueriesDialog').hide()");
        PrimeFaces.current().ajax().update("dt-queries");
    }
    
    public void startAbfrage(Abfrage abf) {
        UcmdbAbfrageInteface.doRequest(abf);
    }
    
    public void deleteAbfrage() {
        if(selected != null) {
            UcmdbAbfTableHandler.deleteAbfrage(selected);
            abfragen.remove(selected);
        }
        PrimeFaces.current().ajax().update("dt-queries");
    }
    
    public List<Abfrage> getAbfragen() { return abfragen; }
    public Abfrage getSelected() { return selected; }
    public RequestResolutions[] getRequestResolutions() { return requestResolutions; }
    public void setSelected(Abfrage selected) { this.selected = selected; }

}

我已经包括了所有进口商品,因为可能有一个是假包裹。我的问题是,如果我点击新建,对话框将保持为空,因为他认为该对象是空的。当我点击编辑按钮时,对象被加载,但我无法保存它,因为 abfTyp 是空的(它是 required="true"),在我将 required 设置为 false 之后我可以保存,但我的对象有旧数据而不是我更改的日期。我有一个几乎相似的页面,它运行良好,但我找不到区别。 RequestResolutions 是一个愚蠢的 ENUM,没有任何功能。

使用“neu”时对话框为空,因为您每次都创建一个新版本的“selected”。旧数据重新出现在“编辑”中,因为上一次验证失败,但您立即关闭了对话框。然后你使用 p:resetInput 重置回存储的值。如果 selectList 值为空,这意味着来自数据源的内容与您提供的枚举 select 列表中的任何值都不匹配。

我在使示例正常工作时遇到了很多问题...缺少表格,更新=引用错误。但我认为主要的设计问题是您没有在对话框中显示任何验证错误 - 只是立即关闭对话框 window。顺便说一下,您应该主要在命令按钮上使用 action=,而不是 actionListener=。请参阅 here 了解原因。在执行操作方法之前,所有字段验证都将通过。

我建议修改如下:

    <p:commandButton value="Neu" icon="pi pi-plus" action="#{abfrageHandler.newAbfrage}"
                     update=":ucmdbform:manage-queries-content" 
                     oncomplete="PF('manageQueriesDialog').show()"
                     styleClass="ui-button-success" style="margin-right: .5rem">
<!--    <p:resetInput target=":ucmdbform:manage-queries-content"/> -->
    </p:commandButton>
    .
    .
    <p:commandButton value="Speichern" icon="pi pi-check" 
                     action="#{abfrageHandler.saveAbfrage}"
                     update=":ucmdbform:dt-queries :ucmdbform:manage-queries-content" 
                     oncomplete="if ( args.saved == 1 ) { PF('manageQueriesDialog').hide()};"/>

加上所有 actionListeners="..." --> action="...";加上 p:message 到所有可能验证失败的对话框字段。

    public void saveAbfrage() {
        if (selected.getPk() == null) {
            selected.setPk(UUID.randomUUID());
            UcmdbAbfTableHandler.insertAbfrage(selected);        
            abfragen.add(selected);
        } else {
            UcmdbAbfTableHandler.updateAbfrage(selected);
        }
        PrimeFaces.current().ajax().addCallbackParam("saved", 1);
//        PrimeFaces.current().ajax().update(":ucmdbform:dt-queries");
//        PrimeFaces.current().executeScript("PF('manageQueriesDialog').hide();");
    }