RichFaces 4 - 对象验证

作者:    |      
文章已更新。在《实现细节》部分更正了3.3.x功能描述中的错误

简介

正如我们在之前的博客中提到的,使用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 最终版发布之前稳定且文档完善的这些功能!


[在我的推特上获取博客更新]

[我的 jroller.com 博客]


返回顶部