Java 使用p:calendar在jsf h:datatable中进行跨字段验证

Java 使用p:calendar在jsf h:datatable中进行跨字段验证,java,jsf,jsf-2,primefaces,Java,Jsf,Jsf 2,Primefaces,我注意到有人问了这个问题,但没有得到正确的回答 我有一个数据表,它有两列开始日期和结束日期。两者都包含primeface p:calendar控件。我需要确保每行第1列中的日期不在第2列中的日期之后。我想将此绑定到JSF验证框架中,但我遇到了麻烦 我已经尝试过将datatable rowStatePreserved=“true”标记为允许我获取值,但仍然存在一些问题,因为当它失败时,第一行中的所有值都会覆盖所有其他值。我做错了什么,还是应该使用完全不同的策略 xhtml代码 <h:

我注意到有人问了这个问题,但没有得到正确的回答

我有一个数据表,它有两列开始日期结束日期。两者都包含primeface p:calendar控件。我需要确保每行第1列中的日期不在第2列中的日期之后。我想将此绑定到JSF验证框架中,但我遇到了麻烦

我已经尝试过将datatable rowStatePreserved=“true”标记为允许我获取值,但仍然存在一些问题,因为当它失败时,第一行中的所有值都会覆盖所有其他值。我做错了什么,还是应该使用完全不同的策略

xhtml代码

    <h:form>
 <f:event type="postValidate" listener="#{bean.doCrossFieldValidation}"/>
       <p:dataTable id="eventDaysTable" value="#{course.courseSchedules}" var="_eventDay" styleClass="compactDataTable"
                                 >
                        <p:column id="eventDayStartColumn">
                            <f:facet name="header">
                                Start
                            </f:facet>
                            <p:calendar id="startDate" required="true"  value="#{_eventDay.startTime}" pattern="MM/dd/yyyy hh:mm a"/>
                        </p:column>
                        <p:column id="eventDayEndColumn">
                            <f:facet name="header">
                                End
                            </f:facet>
                            <p:calendar id="endDate" required="true"  value="#{_eventDay.endTime}" pattern="MM/dd/yyyy hh:mm a"/>
                        </p:column>                                        
                    </p:dataTable>
        </h:form>

开始
终点
验证代码

 public void doCrossFieldValidation(ComponentSystemEvent cse) {


        UIData eventsDaysStable = (UIData) cse.getComponent().findComponent("eventDaysTable");

        if (null != eventsDaysStable && eventsDaysStable.isRendered()) {

            Iterator<UIComponent> startDateCalendarIterator = eventsDaysStable.findComponent("eventDayStartColumn").getChildren().iterator();
            Iterator<UIComponent> endDateCalendarIterator = eventsDaysStable.findComponent("eventDayEndColumn").getChildren().iterator();

            while (startDateCalendarIterator.hasNext() && endDateCalendarIterator.hasNext()) {
                org.primefaces.component.calendar.Calendar startDateComponent = (org.primefaces.component.calendar.Calendar) startDateCalendarIterator.next();
                org.primefaces.component.calendar.Calendar endDateComponent = (org.primefaces.component.calendar.Calendar) endDateCalendarIterator.next();

                Date startDate = (Date) startDateComponent.getValue();
                Date endDate = (Date) endDateComponent.getValue();


                if (null != startDate && null != endDate && startDate.after(endDate)) {
                    eventScheduleChronologyOk = false;
                    startDateComponent.setValid(false);
                    endDateComponent.setValid(false);
                }

            }

            if (!eventScheduleChronologyOk) {
                showErrorMessage(ProductManagementMessage.PRODUCT_SCHEDULE_OUT_OF_ORDER);
            }

        }

    }
public void docrossfield验证(组件系统事件cse){
UIData EventsDayStable=(UIData)cse.getComponent().findComponent(“eventDaysTable”);
if(null!=eventsdaystable&&eventsdaystable.isRendered(){
迭代器startDateCalendarIterator=EventsDayStable.findComponent(“eventDayStartColumn”).getChildren().Iterator();
迭代器endDateCalendarIterator=EventsDayStable.findComponent(“eventDayEndColumn”).getChildren().Iterator();
while(startDateCalendarIterator.hasNext()&&endDateCalendarIterator.hasNext()){
org.primefaces.component.calendar.calendar startDateComponent=(org.primefaces.component.calendar.calendar)startDateCalendarIterator.next();
org.primefaces.component.calendar.calendar endDateComponent=(org.primefaces.component.calendar.calendar)endDateCalendarIterator.next();
Date startDate=(Date)startDateComponent.getValue();
日期endDate=(日期)endDateComponent.getValue();
如果(null!=startDate&&null!=endDate&&startDate.after(endDate)){
EventScheduleConomology=false;
startDateComponent.setValid(false);
endDateComponent.setValid(false);
}
}
如果(!eventschedule){
邮件(ProductManagementMessage.PRODUCT\u SCHEDULE\u OUT\u OF \u ORDER);
}
}
}
我做错了什么

以非标准JSF方式在datatable上下文之外执行验证。行数据仅在您(或JSF)迭代数据表时可用。每个列中物理上只有一个
组件,根据当前的datatable迭代轮,该组件具有多个不同的状态。当您不在datatable上迭代时,这些状态不可用。您将只获得
null
作为值

从技术上讲,使用到目前为止不同的验证方法,您应该调用
UIData
组件上的方法,并在
VisitCallback
实现中执行该工作。这将迭代数据表

比如说,

dataTable.visitTree(VisitContext.createVisitContext(), new VisitCallback() {
    @Override
    public VisitResult visit(VisitContext context, UIComponent component) {
        // Check if component is instance of <p:calendar> and collect its value by its ID.

        return VisitResult.ACCEPT;
    }
});

由于两个组件位于同一行中,因此每次调用此验证器时,
startDateComponent
都会“自动”在
getValue()
上返回正确的值。请注意,这个验证器在数据表之外也是可重用的,而您最初的方法是不可重用的


或者,您可以使用
作为完整的解决方案。其示例甚至展示了

@BalusC中
组件的特定用例验证跨字段和跨行验证的策略是什么?
@FacesValidator("dateRangeValidator")
public class DateRangeValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (value == null) {
            return; // Let required="true" handle.
        }

        UIInput startDateComponent = (UIInput) component.getAttributes().get("startDateComponent");

        if (!startDateComponent.isValid()) {
            return; // Already invalidated. Don't care about it then.
        }

        Date startDate = (Date) startDateComponent.getValue();

        if (startDate == null) {
            return; // Let required="true" handle.
        }

        Date endDate = (Date) value;

        if (startDate.after(endDate)) {
            startDateComponent.setValid(false);
            throw new ValidatorException(new FacesMessage(
                FacesMessage.SEVERITY_ERROR, "Start date may not be after end date.", null));
        }
    }

}