精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-04-14
本教程介绍在 AOM 2.0中,是如何对用户的输入参数进行验证的。在阅读本文之前,我建议你首先阅读前两篇文章: http://www.operamasks.org/articles/magic-1/html_single http://www.operamasks.org/articles/magic-2/html_single
坦白说,我已经厌倦了介绍常规JSF引擎是如何实现用户输入校验的,无非就是在页面中加入: <f:validateLength minimum="5" maximum="6" />诸如此类的代码。在我看来,倘若你了解了 AOM 是如何实现校验机制的,那么,你肯定无法再忍受传统的校验方式。现在,就让我们来体验一下吧! 我们依然围绕计算器这个例子。首先,我们希望用户输入的数值不能为空,那么, 我们只需要在CalcBean中做如下更改: @Bind Requiredprivate double first = 22.0; @Bind @Requiredprivate double second = 7.0;
请注意,我们只是在 first 及 second 这两个成员变量上增加了一个新的annotation:@Required,那么,运行结果是怎样的呢? 中文环境下: 英文环境下: 是不是非常简单? 再做个稍微复杂些的,我们希望:第一个参数必须位于 10 至 100 之间,如果输入参数不合法,则显示给用户我们的自定义异常信息,如何做?将 CalcBean 改成这样: @Bind @Required @ValidateDoubleRange(minimum=10, maximum=100, message="This number must be between 10 to 100 ") private double first = 22.0; 运行效果如下: “等等,我希望这个错误信息也是多语言的,怎么办?” 首先,我们修改一下properties文件 #demo.LocalStrings_zh_CN.properties CalcBean.firstRangeErrMessage=该数值必须位于10至100之间 #demo.LocalStrings_en_US.properties CalcBean.firstRangeErrMessage=This number must be between 10 to 100 然后,我们修改一下CalcBean: @LocalString private Map<String,String> messages; @Bind @Required @ValidateDoubleRange(minimum=10, maximum=100, message="#{this.messages.firstRangeErrMessage}") 请注意,在message中,我们也可以嵌入 EL表达式的。现在,让我们看一下中文的运行效果: 好像非常简单的就实现了用户校验的功能,但你可能又有新的疑问了:“以前我在做这种输入校验时, 我可以在页面中嵌入一些 javascript,虽然我的开发工作量较大,但是这种校验是放在客户端的,性能及用户体验都很好。AOM 虽然可以方便我完成校验功能,但每一次校验,都要与服务器端交互,这岂非对性能造成很大的影响?”。 你说的对,我完全明白你的意思,而且,我负责任的告诉你: AOM 能够满意你的所有要求!请在页面中加入如下代码: <w:form id="calc" clientValidate="true"> <layout:panelGrid columns="3"> ... </layout:panelGrid> </w:form> 请注意,我只是加入一个属性:clientValidate="true",那么,运行效果是怎样的呢? 执行效果完全达到我们的预期目的,并且,当你点击“加”、“减”、“乘”、“除”这些按钮时,浏览器根本就没有和服务器端交互,我建议你可以装个 Firebug 监控一下,以证实我说的是真是假。 AOM 是怎么做到的呢?又是在变魔术?我们不妨打开页面生成的源代码看一下,其中包含这样一些代码片断: <script type="text/javascript" language="Javascript"> document.forms['calc']._validators=[ new RequiredValidator('calc:first','数值一:: 校验错误,输入不能为空。','calc:j_id3'), new FloatValidator('calc:first','该数值必须位于10至100之间','calc:j_id3',10.0,100.0), new RequiredValidator('calc:second','数值二:: 校验错误,输入不能为空。','calc:j_id5')]; </script> 明白了吗?AOM 自动帮你生成了客户端的校验代码,而这一切,对你而言都是透明的,这就是 AOM 神奇魔力的其中之一! 但你可能又会问了:“你举的这些例子太简单了,有时候我需要在客户端完成非常复杂的逻辑,譬如,我这个人好吉利, 我希望第一个参数不能是514,该怎么办?”。 你逼我出狠招了!你可以在页面中嵌入一个<ajax:clientValidator/>,将页面修订成这样: <w:textField id="first"> <ajax:clientValidator message="数值不能等于514"> if(value == 514) return false; return true; </ajax:clientValidator> </w:textField> 我们在<ajax:clientValidator/>标签中嵌入任意的 JavaScript 代码,并且,在这段 JavaScript 代码中,可以直接引用 "value" 这个变量,该变量就是控件传递给你需要进行校验的值,然后你可以通过 JavaScript 完成你想要完成的任何逻辑。上述示例的效果如下: “但是,那个 message 能否以 IoVC 的思想放到CalcBean呢?” 唉,你已经在页面中嵌入 JavaScript 代码了,你还指望什么 IoVC呢?
回顾刚才介绍的校验方式,我们可能会有一些疑问:上文所列的校验方式都是基于Annotation的,但毕竟Annotation 的表述能力是有限的,而有时候,我们需要进行的校验逻辑是非常复杂的,那么,这个问题如何解决? 可惜,由于我所举的 Calculator 例子过于简单,要描述复杂的校验逻辑,无法举出一个适合的场景,我只能把客户端校验那个比较“委琐”的校验逻辑拿过来做以示意: 我们不希望用户输入的第一个参数为514,那么,我们该怎么做?最简单的做法是通过基于正则表达式的@ValidateRegexp的 Annotation,但你还可以定义自己的校验方法: @Validate private boolean validateFirst(double value) { return Double.compare(514, value) != 0; } 为什么 AOM 会自动调用此方法?第一,它有一个 @Validate 的 annotation 声明,其次,它的名称为:validateFirst 。哦,又是“约定优于配置”这一原则的体现。 执行效果如下: 事实上,这个方法签名可以有很多种,除了直接返回boolean值的这种最简单形式,你还可以: 1) 标准写法: public void validate(FacesContext context, UIComponent component, Object value); 这是javax.faces.validator.Validator接口所定义的标准方法,采用这种写法可以得到当前正在校验的UI组件, 以获得更多的控制。 2) 简略写法 public boolean validate(Object value); 对输入值进行校验,如果成功则返回true,否则返回false。当采用这种写法时最好设置 @Validate 标注的message属性,用于提供出错信息。 3) 返回不同出错信息的简略写法 public String validate(Object value); 当需要根据不同的校验结果显示不同的出错信息时可以采用这种写法,当方法返回null时表示校验成功, 否则将返回值作为出错信息。注意在返回的字符串中可以包含EL表达式,因此可以很容易地实现国际化 而不是硬编码的固定字符串。 4) 抛出ValidatorException的简略写法 public void validate(Object value) throws ValidatorException; 同第三种方式类似,只不过将出错信息包含在ValidatorException中抛出。
你可能又提出一个新的问题:“刚才所有的验证,无论是基于 Annotation的,还是用自定义方法的,无论是服务器端校验,还是客户端校验,都是对单个控件的值进行校验,但有时候, 我需要在完整上下文中进行校验,这种情况又该如何实现呢?” 这种情况下,你可以在某个具体的 Action 中进行校验。举个简单的例子,众所周知,除数是不能为零的。在这种场景下,你需要知道完整的上下文:即需要知道 second 的具体数值,还需要知道用户点击的是哪个operator,那么,这种逻辑如何实现?你可以对 CalcBean 进行这样的修订: @Action public void divide() { if (second == 0) { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Divide by zero", null); FacesContext.getCurrentInstance().addMessage("calc:second", message); return; } result = first / second; } 上述第1条语句无非是先 new 一个 FacesMessage,但 addMessage 方法中的 "calc:second" 是怎么回事呢?还记得我们的页面吗? <w:form id="calc" clientValidate="true"> ...... <h:outputLabel for="second"/> <w:textField id="second"/> <h:message for="second"/> ...... </w:form> 哦,原来calc指的是 form的id,而second,指的是 message的id。
本章节,我们简单体验了 AOM 2.0 对“输入校验”的处理,同样,我们也不需要再去阐述 AOM 和常规处理模式的差异,优劣高下,我想,各位读者自有判断。 更多技术文章,请见:http://www.operamasks.org/ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-04-29
JSF目前验证是基于java 5以前的技术,这种基于文件配置的方式,我更喜欢struts那样使用独立的文件来配置。
现在用annotation方式验证的验证框架也不少,如 hiberante validator (http://www.hibernate.org/412.html) javalid(http://sourceforge.net/projects/javalid) 但我希望的还是基于jsr303(http://jcp.org/en/jsr/detail?id=303)标准的验证,毕竟不是每个人都喜欢满天飞的框架。 hibernate validator已经向这方面努力。 |
|
返回顶楼 | |
浏览 1973 次