validation.xml文件中的<form>代表一组校验规则,我们可以使用它的name属性值来选择这组规则去对某个JavaBean进行校验,也就是给JavaBean安上一组怎样的校验规则。
<Valdiator>元素的msg属性相当于该Validator的一个标记,如果该validator校验失败,我们可以取出它的msg,至于msg代表什么信息,validator框架不管。我们自己拿着msg去我们的资源文件中查。
Validator,ValidatorResources,ValidatorAction,Field是Validator框架中的几个重要的API类。Validator是调用Validator框架的入口类,ValidatorResources对应validator的xml配置文件,ValidatorAction对应xml文件中的<validator>元素、Field对应<field>元素、Form类对应<form>元素。查看Validator的源代码,了解了Validator是怎样去调用校验方法的,是怎样将参数信息传递给这些校验方法的。validator.validate()方法的源代码,对于1.3.0版本,validate方法中的如下代码应该是一个Bug。
if (form != null) {
this.setParameter(FORM_PARAM, this);
应改为:this.setParameter(FORM_PARAM, form);
调用validator.setParameter方法将一个个参数对象存入到一个Map中,关键字就是类的名称,Validator.BEAN_PARAM等常量也是一些类的完全限定名称,在ValidatorAction内部通过反射获得验证方法对应的Method对象,然后根据其参数的类型名作为关键字从Map中检索相应的值作为参数,所以,Map中存储的条目可以多于验证方法所接收的参数个数的。
valiator.validate-->form.validate-->field.validate-->ValidateAction.executeValidationMethod
这一串的方法调用过程向存储参数的Map对象中存入了Validator、Form、Field、ValidateAction等对象。在validator的源代码中,有使用validator的example。Validator框架调用校验方法时,根据参数的类型来选择参数对象,如果要给校验方法传递多个参数类型完全一样的参数,那该怎么做呢?个人的一个想法:可以把这些参数打包成一个组装对象后再传递。
要使用Validator的JavaScript校验功能,要在jsp页面中使用struts的<html:javascript formName="xxx">标签,其中的xxx是某个校验域的名称,并在需要验证的表单的onsubmit属性中调用"return validateXxx()"方法。validateXxx方法可以通过<html:javascript>的method属性来改变。在struts-rules.xml文件中看到:
Note: Starting in Struts 1.2.0 the default javascript definitions have
been consolidated to commons-validator. The default can be overridden
by supplying a <javascript> element with a CDATA section, just as
in struts 1.1.
以后有时间还应该看看<html:javascript>的源代码,看看JavaScript代码是如何生成的,以及看看生成的JavaScript代码的实现细节,这个已经安排张艳清去熟悉了,有机会让他给大家讲讲。在二进制发行包中,有各个javascript源代码,看谁能够读懂这些源代码。
struts的Validator插件中的有关代码:
public static Validator initValidator(
String key,
Object bean,
ServletContext application,
HttpServletRequest request,
ActionMessages errors,
int page) {
ValidatorResources resources =
Resources.getValidatorResources(application, request);
Locale locale = RequestUtils.getUserLocale(request, null);
Validator validator = new Validator(resources, key);
validator.setUseContextClassLoader(true);
validator.setPage(page);
validator.setParameter(SERVLET_CONTEXT_PARAM, application);
validator.setParameter(HTTP_SERVLET_REQUEST_PARAM, request);
validator.setParameter(Validator.LOCALE_PARAM, locale);
validator.setParameter(ACTION_MESSAGES_PARAM, errors);
validator.setParameter(Validator.BEAN_PARAM, bean);
return validator;
}
Struts中的ValidatorForm与ValidatorActionForm的设计思想,可以作为面向对象的一个很好案例。为什么getValidationKey方法中只有一句代码,那还要把这句代码抽取到一个单独的函数中来实现,而不在主函数中直接编写这句代码?不是说有多行代码才要抽取到一个函数中吗?
如果要为ValidatorActionForm对应的表单生成前台的javascript校验代码,可以使用类似如下的代码:
<html:javascript formName="/logon" />,其中的formName与校验域的名字完全一样,生成的javascript方法则是按formBean的名称来的。
如何校验两个密码字段的内容是否相等:讲解了validateif的设计思路,与当前字段进行比较的另外一个字段名必须作为当前校验器的变量进行配置。通过在struts帮助文挡的Validator帮助页面中搜索validateWhen,迅速掌握了ValidateWhen的使用:this两边都有*,整个表达式必须套在()中。
两个典型的<field>元素的配置:
<field property="password2"
depends="validwhen">
<arg key="prompt.password"/>
<var>
<var-name>test</var-name>
<var-value>(*this* == password)</var-value>
</var>
</field>
<field property="age"
depends="intRange">
<arg key="prompt.age"/>
<arg key="${var:min}" resource="false" position="1"/>
<arg key="${var:max}" name="intRange" position="2"
resource="false"/>
<var>
<var-name>max</var-name>
<var-value>60</var-value>
</var>
<var>
<var-name>min</var-name>
<var-value>18</var-value>
</var>
</field>
实验中的一个小插曲:即使没有配置DispatchAction的parameter属性,如果表单校验出错,也不会出现该Action的问题,因为只有通过表单校验后,ActionServlet才去调用Action。
学员们的发现:struts 1.2.4中的mailreader例子的validator-rules.xml文件中的required validator的方法的参数列表中少了一个参数,validateRequired方法本来接受6个参数,但该文件中只声明了5个参数,所以,在使用到该validator时总是报告错误。
最后讲解了DynaActionForm和DynaValidatorForm,完全不写一行代码,也玩了个登录用例的view层处理,Action使用的是ForwardAction,这可以作为以后免费讲座的一个很吸引人的主题。
杂记:struts的mail-reader例子程序中的一段<validator>配置。
<!--
This simply allows struts to include the validateUtilities into a page, it should
not be used as a validation rule.
-->
<validator name="includeJavaScriptUtilities"
classname=""
method=""
methodParams=""
depends=""
msg=""
jsFunction="org.apache.commons.validator.javascript.validateUtilities"/>