JSF 2.0: Как пропустить проверку JSR-303 bean?

Как пропустить проверку JSR-303 Bean с помощью JSF, когда нажата кнопка?

Несколько длинный вопрос, чтобы объяснить несколько подходов... Рассмотрим список в форме:

<h:form id="form">
    <h:commandButton value="Add row">
        <f:ajax execute="foo" listener="#{bean.add()}" render="foo" />
    </h:commandButton>
    <h:dataTable id="foo" var="foo" value="#{bean.foos}">
        <h:column>
            Name: <h:inputText id="field" value="#{foo.name}" required="true" />
            <h:messages for="field" />
        </h:column>
        <h:column>
            <h:commandButton value="Remove">
                <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

Когда пользователь нажимает на добавление или удаление строки, действие должно выполняться без проверки. Проблема в том, что JSF повторно отображает весь список и пытается его проверить. Если есть проекты изменений, которые не проверяются, возникают ошибки проверки, и метод прослушивателя никогда не вызывается (поскольку эта проверка не позволяет это предотвратить). Однако добавление immediate="true" в f: ajax позволяет выполнять метод, несмотря на ошибки проверки. Тем не менее, ошибки проверки все еще встречаются и показаны здесь.

Я вижу два варианта:

1) Используйте немедленное = "true" и не показывайте ошибки проверки

Для неавтоматизирующих кнопок установите немедленное = "true" и для h: сообщения выполните:

<h:messages rendered="#{param['SHOW_VALIDATION']}" />

Затем установите Save-button (на самом деле попытайтесь сохранить форму), чтобы отправить этот параметр:

<h:commandButton>
    <f:param name="SHOW_VALIDATION" value="true" />
</h:commandButton>

Это вызывает проверку, но сообщения просто не отображаются, кроме случаев, когда присутствует параметр SHOW_VALIDATION.

2) Объявить валидацию в треугольниках условно:

<h:inputText>
    <f:validateRequired disabled="#{!param['VALIDATE']}" />
</h:inputText>

И Сохранить кнопку:

<h:commandButton>
    <f:param name="VALIDATE" value="true" />
</h:commandButton>

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

Но это похоже на хаки. Как я могу просто использовать JSR-303 Bean Validation, но пропустить его при объявлении?

Ответ 1

Установите обработчики событий как immediate=true и вызовите FacesContext.renderResponse(), прежде чем выходить из них.

ОБНОВЛЕНИЕ:

Изменения в форме вашего примера:

<h:form id="form">
    <h:commandButton value="Add row">
        <!-- Added immediate="true" to call bean.add() before validation phase -->
        <f:ajax execute="foo" listener="#{bean.add()}" render="foo" immediate="true"/>
    </h:commandButton>
    <h:dataTable id="foo" var="foo" value="#{bean.foos}">
        <h:column>
            Name: <h:inputText id="field" value="#{foo.name}" required="true" />
            <h:messages for="field" />
        </h:column>
        <h:column>
            <h:commandButton value="Remove">
                <!-- Added immediate="true" to call bean.remove() before validation phase -->
                <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" immediate="true"/>
            </h:commandButton>
        </h:column>
    </h:dataTable>
</h:form>

Изменения в коде bean:

...
public void add() {
    // Your add() code
    ...
    // Added FacesContext.renderResponse() call to skip to render response phase
    FacesContext.getCurrentInstance().renderResponse();
}
...
public void remove() {
    // Your remove() code
    ...
    // Added FacesContext.renderResponse() call to skip to render response phase
    FacesContext.getCurrentInstance().renderResponse();
}
...

Ответ 2

Вы можете отключить проверку bean с тегом f: validateBean, у которого есть атрибут отключен.

Пример:

<h:inputText value="#{bean.name}">
   <f:validateBean disabled="#{anotherBean.flag}"/>
</h:inputText>

Ответ 3

Мы только что опубликовали решение этой проблемы. Полная информация здесь: http://www.springfuse.com/2011/12/15/skip-jsf-validation-depending-on-action.html

Короче говоря, он использует атрибут привязки тега validateBean. Это позволит вам перехватить метод проверки и решить, на основе нажатой кнопки, разрешить ли это пройти или нет.

Ответ 4

Ситуация: В коде страницы есть большая форма с большим количеством полей ввода. Существует несколько кнопок, каждая из которых указывает на отдельное действие в отдельном bean.

Решение, которое сработало для меня...

  • В коде страницы: добавьте immediate="true" к кнопке и укажите идентификатор для полей ввода, которые вы хотите использовать в bean.
 <p:inputText id="someHtmlInputId"
               maxlength="30" 
               value="#{beanName.attr}" />


 <p:commandButton id="someHtmlButtonId"
                   actionListener="#{beanName.doStuff}" 
                   value="Button Label"
                   ajax="false"
                   immediate="true"/>
  • В методе bean doStuff получить параметры с помощью имени фрагмента couse перед именем ввода JSF введите некоторые другие идентификаторы, и результирующее имя параметра может выглядеть так: someFormId: j_idt54: someHtmlInputId
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
if (params != null) {
  for (String k: params.keySet())
      if (k.indexOf("someHtmlInputId") != -1)
          params.get(k); // This is Your input parameter value waiting to be processed ;)
}