【问题标题】:JSF how to temporary disable validators to save draftJSF 如何临时禁用验证器以保存草稿
【发布时间】:2011-02-16 09:03:33
【问题描述】:

我有一个非常复杂的表单,其中包含大量输入和验证器。对于用户而言,完成该过程需要相当长的时间(甚至超过一个小时),因此他们希望能够保存草稿数据,即使它违反了诸如未输入必填字段之类的规则。

我相信这个问题在许多 Web 应用程序中都很常见,但是找不到任何公认的模式应该如何实现。您能告诉我如何实现吗?

现在我可以看到以下选项:

  1. 在“保存草稿”按钮上使用 immediate=true 不起作用,因为 UI 数据不会存储在 bean 上,所以我无法访问它。从技术上讲,我可以在 UI 组件树中找到数据,但遍历这似乎不是一个好主意。
  2. 从页面中删除所有字段验证,并在为表单定义的操作侦听器中以编程方式验证数据。同样,这不是一个好主意,表单真的很复杂,有很多字段,所以以这种方式实现的验证会非常混乱。
  3. 实现我自己的验证器,该验证器将由一些请求属性控制,该属性将设置为标准表单提交(需要完整验证),并将取消设置为“另存为草稿”提交(应跳过验证时)。同样,这不是一个好的解决方案,我需要为我正在使用的所有验证器提供自己的包装器。

但正如你所见,没有人是真正合理的。问题真的没有简单的解决办法吗?

【问题讨论】:

    标签: jsf validation


    【解决方案1】:

    我遇到了同样的问题,我不喜欢跳过所有验证的想法。经过深思熟虑,我最终只想跳过必填字段验证。这背后的逻辑是用户要么正确完成一个字段,要么根本没有完成它。这对我来说非常重要,因为一切最终都在数据库中,当然,我不想溢出数据库字段或最终将 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()。

    • 如果true 至少有一个必填字段未填写:我取消选中标志completed。 (草稿)
    • 如果false 所有表格都已完成:我检查标志completed。 (这不是草稿)

    这还允许我使用一个“保存”按钮而不是两个按钮(“保存”和“另存为草稿”)。

    注意事项和已知陷阱:

    • 如果要将草稿保存到数据库中,则必须确保没有 NOT NULL 约束。
    • 使用转换器和验证器时,您必须确保它们可以处理NULL 值。
    • 您的字段将丢失outputLabel 中的必填字段星号。

    【讨论】:

      【解决方案2】:

      确实没那么容易。验证在 JSF 生命周期中非常紧密地耦合在一起。

      我个人会选择选项 1。确实,肮脏的工作,但您可以将其隐藏在实用程序类中。只需从视图根中获取有问题的<h:form>,递归迭代其子代,从而测试component instanceof EditableValueHolder 是否为真,将找到的id-value 对存储为Map,最后将其持久化。

      作为第四种选择,您可以使用 ajaxical 功能独立保存所有数据。 jQuery 对此很有帮助。

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

      它只需要客户端的 Javascript 支持。


      更新:JSF 实用程序库OmniFaces 有一个<o:ignoreValidationFailed> 标记处理程序用于确切用途。这确实不是一个简单的解决方案,因为它还需要自定义 <h:form>。它通过在验证和更新模型值阶段提供自定义 FacesContext 实例来完成其工作,该实例在 validationFailed() 和 renderResponse() 方法中执行 NOOP。所以组件仍然无效并且消息仍然附加,但它仍然会继续更新模型值并调用应用程序阶段。

      【讨论】:

      • 谢谢巴鲁斯。我喜欢您对选项 1 的想法,当相位侦听器加载数据并重新初始化 EditableValueHolders 时,我可能应该能够做相反的事情。关于您的第二个建议,我在 jQuery 中找不到任何 unserialize() 函数,您将如何加载草稿数据?
      • 通过在服务器端相应地设置托管 bean 属性。
      猜你喜欢
      • 2022-10-18
      • 1970-01-01
      • 2012-03-06
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 2016-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多