使用Validator验证Primefaces中的单元格编辑

Ich*_*aki 5 validation jsf primefaces jsf-2 jsf-2.2

我有一个数据表如下:

<p:dataTable id="dataTablePlanningSalleAppareil"
             styleClass="dataTablePlanningSalleAppareil"
             editable="true" editMode="cell"
             value="#{beanPlanningSalleAppareil.getListPlanningSalleAppareilBySalleOrACAndDay(entry, jour.key)}"
             var="planning"
             sortBy="#{planning.heureDebut}">

    <p:ajax event="cellEdit"
            listener="#{beanPlanningSalleAppareil.onCellEdit}"
            update=":#{p:component('gestionPlanningSalleAppareilMessage')}">
    </p:ajax>

    <p:columnGroup type="header">
        <p:row>
            <p:column colspan="3" headerText="#{jour.value}" style="width:100px" />
        </p:row>
    </p:columnGroup>

    <p:column>
        <p:cellEditor rendered="#{planning.id != 0}" >
            <f:facet name="output"> <h:outputText value="#{planning.heureDebut}" /></f:facet>
            <f:facet name="input">
                <p:inputMask mask="99:99" value="#{planning.heureDebut}"
                             required="true" maxlength="4"
                             requiredMessage="Heure de début : vous devez indiquer une valeur.">
                    <f:validator validatorId="planningSalleAppareilFormuleCremationValidator" />
                    <f:attribute name="planningId" value="#{planning.id}" />
                </p:inputMask>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column  rendered='#{beanListPlanningSalleAppareil.acceuil.valeur eq "1"}'>
        <p:cellEditor rendered="#{planning.id != 0}">
            <f:facet name="output">
                <f:facet name="output">
                    <h:outputText value="#{planning.formuleCremation.alias}" /></f:facet>
            </f:facet>
            <f:facet name="input">
                <h:selectOneMenu value="#{planning.formuleCremation}" converter="#{formuleCremationConverter}">
                    <f:selectItems value="#{beanPlanningSalleAppareil.formules}"
                                   var="formule"
                                   itemLabel="#{formule.alias}"
                                   itemValue="#{formule}" />
                    <f:validator validatorId="planningSalleAppareilFormuleCremationValidator" />
                    <f:attribute name="planningId" value="#{planning.id}" />
                </h:selectOneMenu>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column >
        <p:row>
            <p:commandLink rendered="#{planning.id != 0}"
                           action="#{beanPlanningSalleAppareil.setSelectedPlanning(planning)}"
                           oncomplete="suppressionConfirmation.show()" process="@this" ajax="true">
                <h:graphicImage styleClass="ui-icon ui-icon-closethick" style="display: inline-block;"/>
            </p:commandLink>
        </p:row>
    </p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)

这个数据表是编辑,我可以编辑两个单元planning.heureDebutplanning.formuleCremation.

所以我想要做的是在执行更新之前进行一些验证,然后我将检查当前行和单元格的新值,以便知道我正在修改哪一行我添加了如下属性:

<f:attribute name="planningId" value="#{planning.id}" />
Run Code Online (Sandbox Code Playgroud)

为此,我创建了一个验证器:

@FacesValidator("planningSalleAppareilFormuleCremationValidator")
public class PlanningSalleAppareilFormuleCremationValidator implements Validator {
    private static final Logger LOG = Logger.getLogger(PlanningSalleAppareilFormuleCremationValidator.class);
    @Autowired
    private IPlanningSalleAppareilService planningSalleAppareilService;

    public PlanningSalleAppareilFormuleCremationValidator() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        ServletContext servletContext = (ServletContext) externalContext.getContext();
        WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).
                                   getAutowireCapableBeanFactory().
                                   autowireBean(this);
    }

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException {

        int id = (int) uic.getAttributes().get("planningId");

        //The selected Salle or Appareil
        Object selectedObject = null;
        //Current Planning
        PlanningSalleAppareil planningSalleAppareil = planningSalleAppareilService.trouver(id);

        if(planningSalleAppareil.getAppareil() != null)
            selectedObject = planningSalleAppareil.getAppareil();
        if(planningSalleAppareil.getSalle() != null)
            selectedObject = planningSalleAppareil.getSalle();

        if(o instanceof FormuleCremation)
            planningSalleAppareil.setFormuleCremation((FormuleCremation) o);

        if(o instanceof String)
            planningSalleAppareil.setHeureDebut((String) o);

        if(selectedObject != null){
            String errorMessage = planningSalleAppareilService.validPlanningSalleAppareil(planningSalleAppareil,selectedObject);
            if(!errorMessage.equals("1")){
                FacesMessage msg = new FacesMessage(errorMessage);
                    msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ValidatorException(msg);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我正在做的是当我修改planning.heureDebutplanning.formuleCremation具有我传递的id的行时,<f:attribute name="planningId" value="#{planning.id}" />我从数据库中获取它如下:

int id = (int) uic.getAttributes().get("planningId");
PlanningSalleAppareil planningSalleAppareil = planningSalleAppareilService.trouver(id);
Run Code Online (Sandbox Code Playgroud)

然后我将我编辑过的新值设置为此值planningSalleAppareil,然后从服务中调用验证函数.

所以我得到的行为是,当我编辑某个单元格时,我的应用程序在调用验证器之前将新值保存到数据库,因此当它调用验证器时,验证将始终失败,因为服务方法将始终获得具有新值的对象.

例如,如果我有这样的行:

planning.id = 1
planning.heureDebut = 18:00
...
Run Code Online (Sandbox Code Playgroud)

然后当我planning.heureDebut像这样编辑列时:

planning.heureDebut = 20:00
Run Code Online (Sandbox Code Playgroud)

它应该在更新新值之前执行验证,planning.heureDebut因此它将调用planningSalleAppareilService.trouver(id);将返回计划planning.heureDebut = 18:00的服务方法,但是服务方法返回计划,planning.heureDebut = 20:00这意味着在调用验证程序之前已执行更新.

那我怎么能防止这种情况发生呢?如何在更新前调用验证?