JSF как временно отключить валидаторы для сохранения черновика

У меня довольно сложная форма с большим количеством входов и валидаторов. Для пользователя требуется довольно много времени (даже более часа), чтобы завершить это, поэтому они хотели бы сохранить черновик данных, даже если он нарушает правила, такие как обязательные поля, которые не были введены.

Я считаю, что эта проблема распространена во многих веб-приложениях, но не может найти общепризнанного шаблона, как это должно быть реализовано. Не могли бы вы посоветовать, как это достичь?

Теперь я вижу следующие параметры:

  •  
  • использование функции немедленного = true на кнопке "Сохранить черновик" не работает, так как данные пользовательского интерфейса не будут храниться на bean, поэтому я не смог бы получить к нему доступ. Технически я мог найти данные в дереве компонентов пользовательского интерфейса, но обход, который, похоже, не является хорошей идеей.    
  • удалите все проверки полей со страницы и проверьте данные программно в прослушивателе действий, определенном для формы. Опять же, не очень хорошая идея, форма действительно сложна, есть много полей, поэтому эта проверка была бы очень грязной.    
  • реализовать мои собственные валидаторы, которые будут контролироваться некоторым атрибутом запроса, который будет установлен для представления стандартной формы (с полной ожидаемой валидацией) и не будет отменен для представления "сохранить как черновик" (когда валидация должна быть пропущена). Опять же, не очень хорошее решение, мне нужно будет предоставить свои собственные обертки для всех валидаторов, которые я использую.  

Но, как вы видите, никто не является действительно разумным. Нет ли простого решения проблемы?

Ответ 1

Это действительно не так просто. Валидация довольно тесно связана с жизненным циклом JSF.

Я бы лично пошел на вариант 1. Правда, грязная работа, но вы можете просто скрыть это в классе полезности или так. Просто возьмите <h:form> в вопросе из viewroot, итерайте его рекурсивно, тем самым, проверяя, является ли component instanceof EditableValueHolder true, сохраните найденную пару id-value в виде Map и, наконец, сохраните ее.

В качестве четвертой альтернативы вы можете сохранять все данные независимо с помощью аяксиальных полномочий. jQuery полезен в этом.

$.post('/savedraft', $('#formid').serialize());

Требуется только поддержка Javascript на стороне клиента.


Обновление: библиотека утилиты JSF OmniFaces имеет <o:ignoreValidationFailed> taghandler для конкретной цели. Это действительно не простое решение, так как для него требуется также <h:form>. Он выполняет свою работу, предоставляя собственный экземпляр FacesContext во время фаз валидации и обновления значений модели, которые выполняют NOOP в методах validationFailed() и renderResponse(). Таким образом, компоненты по-прежнему недействительны и сообщения по-прежнему подключены, но они все равно будут переходить к значениям модели обновления и вызывать фазы приложения.

Ответ 2

У меня была такая же проблема, и мне не понравилась идея пропустить все проверки. После долгих мыслей мне захотелось пропустить проверку обязательных полей. Логикой этого является то, что пользователь либо заполняет поле правильно, либо не заполняет его вообще. Это очень важно для меня, потому что все заканчивается в базе данных и, конечно же, я не хочу переполнять поле базы данных или в конечном итоге сохранять значение String в поле базы данных INT, например.

По моему опыту, пропускание необходимых полей позволяет достаточно маневрировать для сохранения черновика. Для этого я написал requiredWarnValidator, в котором отображается одно предупреждение.

public void validate(FacesContext context, UIComponent component, Object value)
    throws ValidatorException {

  if (value == null) {
    FacesMessage message = new FacesMessage();
    message.setSeverity(FacesMessage.SEVERITY_WARN);
    message.setSummary("This field is required.");
    context.addMessage(component.getClientId(), message);
    context.validationFailed();
  }
}

В этом валидаторе я не бросаю ValidatorException(), потому что хочу передать фазу проверки, но я вызываю validationFailed(), потому что хочу знать, не заполнено ли обязательное поле.

У меня есть флаг (completed) в сущности, которую я использую для сохранения моей формы. При сохранении формы я проверяю isValidationFailed().

  • if true по крайней мере одно обязательное поле не заполнено: снимите флажок completed. (это черновик)
  • if false все формы завершены: я проверяю флаг completed. (это не черновик)

Это также позволяет мне иметь одну кнопку "Сохранить" вместо двух кнопок ( "Сохранить" и "Сохранить как черновик" ).

Примечания и известные ловушки:

  • Если вы сохраняете черновик в базе данных, вы должны убедиться, что нет ограничений NOT NULL.
  • При использовании преобразователей и валидаторов вы должны убедиться, что они могут обрабатывать значения NULL.
  • В поле outputLabel для полей вы потеряете требуемую звездочку поля.