简介
正如我们在之前的博客中提到的,使用JSF 2和RichFaces 4,您已经可以通过客户端验证支持Bean Validation,直到浏览器。因此,您可以有效地处理服务器端对象,而无需任何与验证相关的视图级别代码。
本博客将回顾RichFaces 4为JSF 2添加的最后一个(但并非最不重要的)验证功能。这被称为对象验证,它提供了一种方法,可以验证所有模型对象字段,包括当前视图中未使用的字段。
为什么需要这个?我脑海中首先想到的一个例子,它在各种论坛上经常出现,是依赖字段的验证。
密码验证示例
让我们检查密码验证的例子
<h:form> <rich:panel header="Change password" style="width:500px"> <h:panelGrid columns="3"> <h:outputText value="Enter new password:" /> <h:inputSecret value="#{userBean.password}" id="pass"/> <rich:message for="pass"/> <h:outputText value="Confirm the new password:" /> <h:inputSecret value="#{userBean.confirm}" id="conf"/> <rich:message for="conf"/> </h:panelGrid> <a4j:commandButton value="Store changes" action="#{userBean.storeNewPassword}" /> </rich:panel> </h:form>
和简单的托管Bean源
@ManagedBean @RequestScoped public class UserBean { @Size(min = 5, max = 15, message="Wrong size for password") private String password; @Size(min = 5, max = 15, message="Wrong size for confirmation") private String confirm; //... public void storeNewPassword(){ FacesContext.getCurrentInstance().addMessage("", new FacesMessage(FacesMessage.SEVERITY_INFO, "Succesfully changed!", "Succesfully changed!")); } //Getters and setters }
所以我们解决了问题的一半
如果密码字段不符合给定的验证规则,我们会看到错误消息。然而,没有检查密码是否相同,只是它们各自是有效的。那么,验证字段是否相等的最简单方法是什么呢?我们可以在操作中进行,但这在JSF生命周期中对于验证来说太晚了。我们可以使用f:attribute之类的解决方案来传递依赖字段的id到其他输入,并在自定义验证方法中通过该id找到组件。还有其他一些方法,在各个知识库中很容易找到。但大多数方法要么在不当的阶段调用(例如在INVOKE_APPLICATION时),要么有潜在的维护问题(例如,f:attribute解决方案需要我们耐心等待id在视图中的变化,因为验证依赖于它们)。
RichFaces 4对象验证用于跨字段验证
这就是RichFaces 4对象验证功能发挥作用的地方!以下是我们可以使用的内容
<h:form> <rich:graphValidator value="#{userBean}" id="gv"> <rich:panel header="Change password" style="width:500px"> <rich:messages globalOnly="true"/> <rich:messages for="gv"/> <h:panelGrid columns="3"> <h:outputText value="Enter new password:" /> <h:inputSecret value="#{userBean.password}" id="pass"/> <rich:message for="pass"/> <h:outputText value="Confirm the new password:" /> <h:inputSecret value="#{userBean.confirm}" id="conf"/> <rich:message for="conf"/> </h:panelGrid> <a4j:commandButton value="Store changes" action="#{userBean.storeNewPassword}" /> </rich:panel> </rich:graphValidator> </h:form>
以及Bean(已更新为实现了Cloneable)
@ManagedBean @RequestScoped public class UserBean implements Cloneable{ @Size(min = 5, max = 15, message="Wrong size for password") private String password=""; @Size(min = 5, max = 15, message="Wrong size for confirmation") private String confirm=""; @AssertTrue(message = "Different passwords entered!") public boolean isPasswordsEquals() { return password.equals(confirm); } public void storeNewPassword(){ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Succesfully changed!", "Succesfully changed!")); }
让我们来看看示例细节。 rich:graphValidator 标签应包裹我们要验证的对象绑定的输入。 value 属性应指向该bean名称。然后在 PROCESS_VALIDATION 阶段,所有对象字段将根据添加的约束进行验证。在特定情况下,将使用 AssertTrueValidator 验证 isPassWordEquals。这正是我们期望的!
输入不同的密码(但根据大小有效)
验证成功
实现细节
更新(28.02)以下部分。实际上 3.3.x 使用了相同的方式。错误地写成它在模型更新时工作。只有一个问题出现。了解 JSF 生命周期的人会立即问,在模型更新之前如何验证 bean?RichFaces 提议在处理更新阶段后使用验证?不。我们在验证阶段对你的 bean 实例执行一个 clone(),并用所有提交的新值更新新实例(这就是我们为什么仍然需要包裹所有与 rich:graphValidator 相关的输入)。然后,如果需要,我们验证克隆对象并触发验证消息。您的模型对象保持干净,生命周期在 Process Validations 阶段后得到适当的中断,并在 Render Response 期间将消息编码到客户端。
注意:如果对象抛出 cloneNotSupportedException – 验证将在模型更新时完成。这是我们架构的唯一例外,实际上无法解决。
试试看!
现在,由于 JSF 2 Bean Validation 支持标准化,RichFaces 4 客户端验证和对象验证功能,我们相信您将能够完全专注于您的业务任务,而不会在验证阶段花费时间进行任何额外的 JSF 开发。在我们的 RichFaces 4.0.0.M6 中尝试我们的新功能,并让我们知道出现的任何问题或疑问。这将极大地帮助我们提供在 RichFaces 4 最终版发布之前稳定且文档完善的这些功能!