一、短路验证
若对一个字段使用多个验证器,默认情况下会执行所有的验证。若希望前面的验证器验证没有通过,后面的就不再验证,可以使用短路验证。
1)对同一个字段内的多个验证器,如果一个短路验证器验证失败,其他验证器不会继续校验
2)验证程序配置文件中<validator …/> 元素和 <field-validator …/> 元素可以指定一个可选的 short-circuit 属性,该属性指定该验证器是否是短验证器,默认值为 false。
1、示例:短路验证器
要求:为age字段配置两个验证器:conversion类型转换验证器和int整数验证器,并将conversion配置为一个短路验证器。
1)JSP页面代码、Action类的代码以及struts.xml的配置与“Struts2的输入验证(一)”中的相同;
2)验证配置文件TestValidationAction-testValidation-validation.xml中段的配置内容为:
<!-- 针对 age 属性进行验证. 基于字段的验证 --> <field name="age"> <!-- 设置短路验证: 若当前验证没有通过, 则不再进行下面的验证 --> <field-validator type="conversion" short-circuit="true"> <message>Conversion Error Occurred</message> </field-validator> <field-validator type="int"> <param name="min">20</param> <param name="max">60</param> <message key="error.int"></message> </field-validator> </field>
在Tomcat中部署运行后的结果如下图:
结果1:视频教程中conversion校验器未设置short-circuit="true"时的结果(其中第一条是类型转换错误的信息,第二条是类型转换校验器的信息,第三条是整形校验器的信息)
结果2:视频教程中conversion校验器设置了short-circuit="true"时的结果(这时,由于类型转换校验器校验未通过,因此没有再执行整形校验器)
结果3:自己测试的结果(在自己进行测试时发现,在conversion校验器与int校验器配合使用时,无论是否设置conversion校验器的short-circuit属性为true,当输入内容不是一个整数时,都不会有int校验器的提示信息。经过Debug发现,当输入内容不是一个整数时,int校验器执行时,其获得的value值始终为null,因此其就直接返回了一个null,而不再进行校验,也没有添加校验失败的信息。不知道视频中是如何做的,用的都是同样的代码啊。???)
总之,短路验证器的基本使用方法就同示例中一样,具体使用时在参考Struts2的官方文档了。
2、存在的问题
若类型转换失败,默认情况下还会执行后面的拦截器,还会进行验证(在Struts2默认的拦截器栈中,params拦截器在validate拦截器之前)。可以通过修改 ConversionErrorInterceptor 拦截器源代码的方式,使当类型转换失败时不再执行后续的验证拦截器,而直接返回 input 的 result。
方法即在ConversionErrorInterceptor拦截器的intercept()方法return之前添加如下代码:
1 Object action = invocation.getAction(); 2 if (action instanceof ValidationAware) { 3 ValidationAware va = (ValidationAware) action; 4 if(va.hasFieldErrors() || va.hasActionErrors()){ 5 return "input"; 6 } 7 }
即判断fielErrors与actionErrors中是否有值,如果有的话就说明有类型转换错误的信息,就直接返回不在执行后续的拦截器了。
二、非字段验证
即不是针对于某一个字段的验证。
1、示例:非字段验证
要求:校验两次输入的密码是否相同。
1)JSP页面主要代码:
1 <s:debug></s:debug> 2 <s:actionerror/> <%--注意:由于非字段校验不是针对于某个字段的校验,因此其错误消息不是fieldError类型的,而是actionError类型的,因此要使用actionerror标签来显示--%> 3 <s:form action="testValidation" theme="simple"> 4 Password: <s:password name="password"></s:password><br> 5 Password2: <s:password name="password2"></s:password><br> 6 <s:submit></s:submit> 7 </s:form>
2)Action类的代码:
1 package com.atguigu.struts2.validation.app; 2 import com.opensymphony.xwork2.ActionSupport; 3 public class TestValidationAction extends ActionSupport { 4 private String password; 5 private String password2; 6 public String getPassword() { 7 return password; 8 } 9 public void setPassword(String password) { 10 this.password = password; 11 } 12 public String getPassword2() { 13 return password2; 14 } 15 public void setPassword2(String password2) { 16 this.password2 = password2; 17 } 18 public String execute() throws Exception { 19 System.out.println("password: " + password); 20 System.out.println("password2: " + password2); 21 return SUCCESS; 22 } 23 }
3)struts.xml文件的基本配置:
<action name="testValidation" class="com.atguigu.struts2.validation.app.TestValidationAction"> <result>/success.jsp</result> <!-- 若验证失败转向的 input --> <result name="input">/validation.jsp</result> </action>
4)验证程序的配置文件,文件名为:TestValidationAction-validation.xml,配置内容:
<validators> <!-- 测试非字段验证--> <validator type="expression"> <param name="expression"><![CDATA[password==password2]]></param><!--注意:这里的表达式要写到CDATA区域(<![CDATA[……..]]>)中,因为其中可能有特殊字符--> <message>Password is not equals to password2</message> </validator> </validators>
在Tomcat中部署并运行后,当两次输入的密码不相同时,运行结果如下图:
注意:显示非字段验证的错误消息,使用 s:actionerror 标签: <s:actionerror/>。
2、字段验证 VS 非字段验证
1)字段验证字段优先,可以为一个字段配置多个验证规则。
2)非字段验证验证规则优先。
3)大部分验证规则支持两种验证器,但个别的验证规则只能使用非字段验证,例如表达式验证。
三、错误消息的重用性
问题:多个字段使用同样的验证规则,可否使用同一条验证消息 ?
1、示例:
要求:页面上有age和count两个字段,这两个字段都是用int验证规则,要求当验证失败时,两者分别显示各自的错误消息。
1)JSP页面的代码:
1 <s:form action="testValidation" theme="simple"> 2 Age: <s:textfield name="age" label="Age"></s:textfield> 3 ${fieldErrors.age[0] } <br> 4 Count: <s:textfield name="count"></s:textfield> 5 <s:fielderror fieldName="count"></s:fielderror> 6 <br> 7 <s:submit></s:submit> 8 </s:form>
2)Action类的代码:
1 package com.atguigu.struts2.validation.app; 2 import com.opensymphony.xwork2.ActionSupport; 3 public class TestValidationAction extends ActionSupport { 4 private Integer age; 5 private Integer count; 6 public Integer getAge() { 7 return age; 8 } 9 public void setAge(Integer age) { 10 this.age = age; 11 } 12 public Integer getCount() { 13 return count; 14 } 15 public void setCount(Integer count) { 16 this.count = count; 17 } 18 public String execute() throws Exception { 19 System.out.println("age: " + age); 20 System.out.println("count: " + count); 21 return SUCCESS; 22 } 23 }
3)struts.xml配置文件的内容同短路验证示例。
4)验证程序的配置文件,文件名为:TestValidationAction-validation.xml,配置内容:
1 <validators> 2 <field name="age"> 3 <field-validator type="int"> 4 <param name="min">20</param> 5 <param name="max">60</param> 6 <message key="error.int"></message> 7 </field-validator> 8 </field> 9 <field name="count"> 10 <field-validator type="int"> 11 <param name="min">1</param> 12 <param name="max">10</param> 13 <message key="error.int"></message> 14 </field-validator> 15 </field> 16 </validators>
5)添加国际化资源文件i18n.properties,并在其中添加如下内容:
error.int=${getText(fieldName)} needs to be between ${min} and ${max} age=u5E74u9F84 注:这里是年龄 count=u6570u91CF 注:这里是数量
在Tomcat中部署并运行结果如下图,注意:这时验证失败消息中分别显示出了age与count字段在国际化资源文件中对应的名称“年龄”与“数量”:
二、配置文件与验证器属性对应关系图解