JSF 2.0:如何跳过JSR-303 bean验证?

12

如何在单击按钮时跳过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参数存在时(=按下保存按钮时),此操作会导致字段仅进行验证。

但这些看起来有点像hack。如何简单地使用JSR-303 Bean Validation,但在声明时跳过它?


嗯,除了JSR-303和JSF的facelets之外,我还没有尝试过其他验证解决方案。我认为这个问题与JSF有关,而不是JSF-303的问题——就像他们忘记在JSF中“本地”支持跳过验证一样。似乎有很多混淆在这里... - Tuukka Mustonen
4个回答

9

将事件处理程序设置为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();
}
...

你如何在实践中做到这一点?你能举个例子吗? - Tuukka Mustonen
澄清一下:这样做会使JSF跳过3-5阶段(处理验证、更新模型、调用应用程序),直接进入第6阶段(呈现响应)。这是可以的,因为结果与如果验证在第3阶段失败并且JSF将跳转到第6阶段的结果相同。如果我错了,请纠正我。从这里开始的下一步将是通用化/组件化,以便不需要调用FacesContext.getCurrentInstance().renderResponse()。选择作为采纳的答案,感谢您提供的好解决方案! :) - Tuukka Mustonen
1
我尝试了上述方法,总体来说它运行良好。我的情况是这样的 - 我使用一个命令按钮动态地向页面添加多个文本框。如果我使用 immediate="false",页面验证将阻止更新,并且也不会显示。如果我使用 immediate="true",并在进行 AJAX 请求之前修改一些输入值,则修改将不会被提交。有什么想法可以同时实现读取更改后的输入数据和不触发验证吗?提前致谢。 - Ivaylo Slavov
我有同样的问题。我希望更新模型,但跳过验证。我有一个带有不同选项卡的表单。当选择不同的复选框时,我会添加选项卡。Ajax渲染p:tabView。但我不想失去已经在选项卡中输入或更改的信息。 - roel
1
您可以在 inputText 上设置 immediate="true",这样它就会在调用任何操作之前更改值。 - gpeche

8
您可以使用标签f:validateBean并设置属性disabled来禁用Bean验证。

示例:

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

这也是很好的信息。然而,为每个表单字段设置这些仍然有点繁琐... - Tuukka Mustonen
2
您也可以使用f:validateBean来包装多个输入组件,就像这里所示:https://dev59.com/7XTYa4cB1Zd3GeqPrCGQ#17503608 - Jens Piegsa

2

-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"/>
在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 ;)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接