Проверка диапазона дат

Я хочу сравнить две даты (StartDate и EndDate) и проверить, находится ли один перед другим. Самое простое решение - просто сделать это на основе bean и "короткого замыкания" метода.

Однако эта проверка не выполняется одновременно с другими формами. Например, если у меня есть другое поле, которое требует проверки (кроме дат) и имеет недопустимый ввод, я получаю сообщение только для этого конкретного поля. Только если другие поля верны, я получу подтверждение даты на основе поддержки bean.

У кого-нибудь есть решение?

Ответ 1

Однако эта проверка не выполняется одновременно с другими формами.

Метод поддержки bean действительно не предназначен для выполнения проверки ввода.


У кого-нибудь есть решение?

Используйте подходящий инструмент для задания; используйте обычный Validator.

@FacesValidator("dataRangeValidator")
public class DateRangeValidator implements Validator {
    // ...
}

Валидация нескольких входных значений с одним валидатором в свою очередь, тем не менее, является историей. В принципе, вы должны захватывать/передавать другой компонент или его значение в реализацию метода validate(). В своей простейшей форме вы можете использовать <f:attribute> для этого. Предполагая, что вы используете <p:calendar> для выбора дат, вот конкретный пример запуска:

<p:calendar id="startDate" binding="#{startDateComponent}" value="#{bean.startDate}" pattern="MM/dd/yyyy" required="true" />
<p:calendar id="endDate" value="#{bean.endDate}" pattern="MM/dd/yyyy" required="true">
    <f:validator validatorId="dateRangeValidator" />
    <f:attribute name="startDateComponent" value="#{startDateComponent}" />
</p:calendar>

(обратите внимание на атрибут binding, он делает компонент доступным в области EL на точно данном имени переменной, а также обратите внимание, что этот пример является как есть, и что вы не должны полностью привязывать его к свойству bean!)

Где dateRangeValidator выглядит так:

@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));
        }
    }

}

Если вы используете библиотеку утилиты JSF OmniFaces, то вы также можете просто использовать ее <o:validateOrder> компонент. Требование может быть достигнуто следующим образом без необходимости использования специального валидатора:

<p:calendar id="startDate" value="#{bean.startDate}" pattern="MM/dd/yyyy" required="true" />
<p:calendar id="endDate" value="#{bean.endDate}" pattern="MM/dd/yyyy" required="true" />
<o:validateOrder components="startDate endDate" />

См. также:

Ответ 2

если вы используете PrimeFaces, который может ограничить минимальные и максимальные даты. пользователь не может выбрать более широкий диапазон, это пример:

<p:calendar id="startDate" value="#{bean.startDate}" maxdate="#{bean.endDate}">
     <p:ajax event="dateSelect" update="endDate"/>
</p:calendar>
<p:calendar id="endDate" value="#{bean.endDate}" mindate="#{bean.startDate}" disabled="#{empty bean.startDate}">
      <p:ajax event="dateSelect" update="startDate"/>
 </p:calendar>

Ответ 3

Поскольку решение BalusC работает только в том случае, если у вас есть один диапазон дат для проверки в форме, вот улучшение, позволяющее проводить несколько проверок диапазона дат:

  • добавьте еще один <f:attribute> в компонент календаря endDate, где вы указываете имя атрибута привязки для компонента startDate:

    <f:attribute name="bindingAttributeName" value="startDateComponent" />
    
  • затем в валидаторе:

    String startDateBindingAttrName = (String) component.getAttributes().get("bindingAttributeName");
    UIInput startDateComponent = (UIInput) component.getAttributes().get(startDateBindingAttrName);