12

单击按钮时,如何使用 JSF 跳过 JSR-303 Bean 验证?

解释一些方法的有点冗长的问题......考虑一个表格中的列表:

<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) 使用 immediate="true" 并且不显示验证错误

对于非验证按钮,设置 immediate="true" 并且对于 h:messages 执行:

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

然后设置保存按钮(实际上应该尝试保存表单)以发送该参数:

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

SHOW_VALIDATION这会导致验证发生,但除非存在参数,否则根本不会显示消息。

2)有条件地在facelets中声明验证:

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

和保存按钮:

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

这会导致字段仅在VALIDATE参数存在时才有效(=当按下保存按钮时)。

但这些似乎有点像黑客。我怎样才能简单地使用 JSR-303 Bean Validation 但在声明时跳过它?

4

4 回答 4

9

将您的事件处理程序设置为immediate=trueFacesContext.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();
}
...
于 2011-01-31T15:30:08.323 回答
8

您可以使用具有 disabled 属性的标记f:validateBean禁用 bean 验证。

例子:

<h:inputText value="#{bean.name}">
   <f:validateBean disabled="#{anotherBean.flag}"/>
</h:inputText>
于 2011-02-09T02:22:47.163 回答
2

我们刚刚发布了这个问题的解决方案。完整的细节在这里: http ://www.springfuse.com/2011/12/15/skip-jsf-validation-depending-on-action.html

简而言之,它利用了 validateBean 标记的绑定属性。这样做使您能够拦截 validate 方法并根据单击的按钮决定是否让它通过。

于 2011-12-16T14:56:17.173 回答
-1

情况:在页面代码中有一个带有很多输入字段的大表单。有几个按钮,每个按钮都指向单独 bean 中的单独操作。

一个对我有用的解决方案......

  1. 在页面代码中:添加immediate="true"到按钮并为要在 bean 中使用的输入字段提供 id。
 <p:inputText id="someHtmlInputId"
               maxlength="30" 
               value="#{beanName.attr}" />


 <p:commandButton id="someHtmlButtonId"
                   actionListener="#{beanName.doStuff}" 
                   value="Button Label"
                   ajax="false"
                   immediate="true"/>
  1. 在 beandoStuff方法中,通过名称片段获取参数,在输入名称 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 ;)
}
于 2012-04-03T10:01:47.257 回答