在JSF2/PrimeFaces中通过AJAX触发类级bean验证

在JSF2/PrimeFaces中通过AJAX触发类级bean验证,jsf,jsf-2,primefaces,bean-validation,Jsf,Jsf 2,Primefaces,Bean Validation,问题描述 在我工作的公司,我们正在使用JSF2和PrimeFaces实现一个web应用程序。web应用程序是一系列业务方法和域模型的前端之一,这些方法和域模型创建为一组实体类,并使用JPA持久化。我们也有一些webservice方法在同一个域模型上运行。因此,我们希望在实体级别上使用bean验证来实现尽可能多的验证逻辑。到目前为止,一切都很顺利,但我们最近遇到了一个我真的不知道如何处理的问题。为了改善用户体验,我们使用AJAX(使用p:ajaxupdate=“errormessageforfie

问题描述

在我工作的公司,我们正在使用JSF2和PrimeFaces实现一个web应用程序。web应用程序是一系列业务方法和域模型的前端之一,这些方法和域模型创建为一组实体类,并使用JPA持久化。我们也有一些webservice方法在同一个域模型上运行。因此,我们希望在实体级别上使用bean验证来实现尽可能多的验证逻辑。到目前为止,一切都很顺利,但我们最近遇到了一个我真的不知道如何处理的问题。为了改善用户体验,我们使用AJAX(使用p:ajaxupdate=“errormessageforfieldwhere”)触发大多数bean验证逻辑,例如,当用户从文本字段中签出、更改下拉列表中的值等,以便他们能够立即反馈错误。在处理字段/属性级别的约束时,这一切都很好,但我不知道如何使它与类级别的bean验证器正常工作。让我举例说明。 假设以下实体对象CDIBean和facelets视图,以及要求MaxValue大于MinValue的自定义bean验证器

@Entity
@CustomClassLevelBeanValidator
public class Model {
    @Min(10) int minValue; int maxValue; // getters/setters ommitted }

@Named
@SessionScoped
public class ModelBean {
    @Valid private Model model; // getter and initialization ommitted }

最小值:
最大值:
我们希望实现以下目标:

  • 当用户制表符超出minValue时,该字段的错误消息将被更新。由于标准的JSF/单字段bean验证集成,这一点已经起到了作用
  • 当用户从minValue或maxValue选项卡中移出时,应更新maxValue的错误消息。请注意,这实际上由4种不同的情况组成:约束可以通过更改minValue变得有效,也可以通过更改maxValue变得无效。我不清楚如何在不进行JSF级验证的情况下实现这一点
当前事态

  • 直接更新ajax事件上的单字段错误消息已经起作用(开箱即用)
  • 通过使用MyFaces的ExtVal组件,我们还设法在表单提交时触发类级验证,尽管所有违反约束的行为最终都会出现在“全局错误”部分(p:messages globalOnly,这很有意义,因为在类级bean验证期间,您没有指定验证失败的属性)
  • 我们已经实现了一个解决方案,它在功能上等同于我上面列出的(从用户的角度来看),但我讨厌它。它涉及到facelets端的许多process=this/update=that,有时还涉及使用JSF级别的验证,因此违反了DRY,因为我们必须在域模型中再次重复这些约束,以确保webservice调用也得到了正确的验证
  • 如果结果证明我们想要实现的是不可能/不可行的,我们将不得不满足于通过AJAX触发字段级约束,并在表单提交中处理所有跨字段的内容。其实没那么糟糕,但我希望我们能做得更好。来自.NET的背景,我记得使用WPF和IDataErrorInfo可以相当容易地实现这种东西
解决方案要求

理想的解决方案应满足以下所有要求:

  • 仅使用Bean验证就可以完全实现,无需FacesMessages等
  • 允许在编辑表单字段后,针对该特定字段和约束受其影响的所有其他字段的验证错误,向最终用户提供直接反馈
  • 显示验证错误“它们所属的位置”,例如,在上面的示例中,至少从用户的角度来看,“max>min”规则与“maxValue”字段相关联。事实上,严格来说,这样的约束并不是maxValue上的错误,而是两个字段之间的关系并不重要,我应该能够选择其中一个作为验证的“受害者”,并向最终用户显示消息“对不起,该特定字段是错的”。 我理解,在一般情况下,对N个字段进行约束是不可能的,其中一些字段甚至可能不在当前视图中,但我认为可以涵盖诸如min>max、endDate>startDate等内容
从这里到哪里去?

据我所知,JSF、BeanValidation或PrimeFaces中没有让我实现这一点的东西。我不太确定ExtVal,它的设计似乎是非常可扩展的,但即使这样,我也不知道从哪里开始。如果这些库中有任何我完全忽略的东西让我来解决这个问题,请告诉我! 如果不是,则需要什么来构建此问题的自定义解决方案?我曾经考虑过手动实现这个,类似于定制的phaselistener,它触发当前视图中所有提交字段的所有bean验证器,并将它们转换为FacesMessages。然而,我怀疑这不是一项容易的任务:

  • 标准的类级约束violations不携带leafBean/属性路径,否则,验证错误可能无法与jsf的客户机ID匹配
  • 如果其中任何一个验证失败,JSF都不会应用模型值。在跨域验证场景中,应用单个值可能会违反约束,而应用所有这些值将使对象再次有效(ExtVal是如何做到这一点的?它不遵循JSF的规则吗?)
  • 我们是否在流程验证期间进行验证?如果是这样的话,我们是否应该启用DISABLE_DEFAULT_BEAN_VALIDATOR context param以允许其他无效的模型值填充实体
  • 问题似乎部分在于JSR303将约束验证视为一种状态(对象是否有效),而JSF将其视为一种操作(不,您不能提交此表单,它无效)。在这方面,JSF2.2会让生活更轻松吗?我不介意用户提交