10.2 验证框架入门
10.2.1准备基础资源
通过示例来初步学习一下如何使用Struts2的验证框架,只简单的做这样一个用户注册的功能:用户注册的时候只需要填写自己的账号、姓名、年龄,其中,账号和姓名要求必填,年龄要求必填而且在18岁以上。
1:封装用户注册信息的域对象
ta�Ktr�-�8%�t;text-justify-trim:punctuation'>
10.2.1准备基础资源
java代码:
- public class UserModel {
- private String account;
- private String name;
- private int age;
- public String getAccount() {
- return account;
- }
- public void setAccount(String account) {
- this.account = account;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String toString(){
- return "account="+account+",name="+name+",age="+age;
- }
- }
2:用户的注册页面
在这个页面上,使用<s:form>表单标签来提交信息,不指定其风格,默认使用xhtml。这个jsp为WebContent/validate/register.jsp,示例如下:
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312" pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- 用户注册
- <hr>
- <s:form action="/registerAction.action" method="post">
- <s:textfield name="user.account" label="账号"/>
- <s:textfield name="user.name" label="姓名"/>
- <s:textfield name="user.age" label="年龄"/>
- <s:submit value="注册"/>
- </s:form>
- </body>
- </html>
3:注册用的Action
只是简单实现:接到注册页面传入的数据,并在execute方法中将它打印出来,示例如下:
java代码:
- public class RegisterAction extends ActionSupport{
- public UserModel user = new UserModel();
- public String execute() throws Exception {
- System.out.println("传入的数据为="+user);
- return SUCCESS;
- }
- }
4:注册成功后的结果页面
这个页面非常简单,就是简单的显示注册成功的信息,示例如下:
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312" pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- 恭喜您注册成功!
- </body>
- </html>
5:在struts.xml中添加配置
java代码:
- <package name="helloworld" extends="struts-default">
- <action name="registerAction" class="cn.javass.validate.RegisterAction">
- <result>/validate/success.jsp</result>
- </action>
- </package>
所有的工作都准备完了,来运行测试一下,先访问注册页面,然后填入合适的数据,点击注册看看是否能正确提交,并跳转到成功页面。应该是没有问题的,那么,接下来就在这个示例的基础上,来使用验证框架。
10.2.2初会验证框架
在上一节的例子中,并没有使用验证框架。这时候,用户的任何输入都会被RegistAction所接收。
现在来加入验证框架,非常简单,只需要添加一个xml,这个xml命名为Action类名-validation.xml,放在需要验证的Action类同包下,其内容为这个Action的execute方法运行前要对用户的输入进行的各种验证。
很显然,需要在RegisterAction同包下,新建一个RegisterAction-validation.xml的文件,示例内容如下:
java代码:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE validators PUBLIC
- "-//OpenSymphony Group//XWork Validator 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-
- <validators>
- <field name="user.account">
- <field-validator type="requiredstring">
- <message>请填入账号</message>
- </field-validator>
- </field>
- <field name="user.name">
- <field-validator type="requiredstring">
- <message>请填入姓名</message>
- </field-validator>
- </field>
- <field name="user.age">
- <field-validator type="int">
- <param name="min">18</param>
- <message>年龄必须在18岁以上</message>
- </field-validator>
- </field>
- </validators>
在这个示例里面:
- 用户的账号字段(user.account)要求必填。这个要求对应着<validators>元素中,name属性为user.account的<field >子元素。
l 在这个<field>元素中,只有一个<field-validator>子元素,说明这个字段只需要使用一个条件进行验证。
l <field-validator>元素的type属性为requiredstring,说明这个字段必填,而验证框架不管用户填的什么。
l <field-validator>元素的<message>子元素是当这个验证条件不满足的时候,验证框架返回的错误信息。
- 用户的姓名字段(user.name)也要求必填,与上个字段验证条件相似,就不再赘述了。
- 用户的年龄字段(user.age)要求必须填入一个不小于18的整数。这个要求对应着<validators>元素中,name属性为user.age的<field >子元素。
l 在这个<field>元素中,只有一个<field-validator>子元素,说明这个字段只需要使用一个条件进行验证。
l <field-validator>元素的type属性为int,说明这个字段必填,而且必须是个整数。
l <field-validator>元素的<param>子元素name属性为min,值为18,指明了这个整数的最小值为18。
l <field-validator>元素的<message>子元素是当这个验证条件不满足的时候,验证框架返回的错误信息
很简单吧,每个字段是否需要验证,需要什么样的验证,验证是否需要更明确的参数等等信息,都是通过配置来指定。
那么,在添加了验证文件之后,什么时候运行呢?验证通不过怎么办呢?
- 验证的时机。验证发生在execute方法运行之前,在Struts2的params拦截器已经把请求的参数反射的设置到Action的属性之后。所以,验证框架实际上验证的是值栈内的值。
- 验证的结果。如果用户输入的参数完全满足验证条件,则会继续执行execute方法,如果用户输入的参数不满足验证条件,注意:三个验证条件只要有一个验证通不过,就会跳转到这个Action所配置的名为input的Result。
示例里面还没有名为input的Result,一般情况下,input结果都是在验证不成功的情况下,返回到原来提交的页面,所以,稍稍修改一下struts.xml,加上这个input的配置:
java代码:
- <package name="helloworld" extends="struts-default">
- <action name="registerAction" class="cn.javass.validate.RegisterAction">
- <result name="input">/validate/register.jsp</result>
- <result>/validate/success.jsp</result>
- </action>
- </package>
再次运行测试,不过,这次故意不填姓名,并把年龄填成12,运行结果为:
图10.1 验证框架入门
可以看到,不满足验证条件的姓名和年龄的错误信息,会从RegistAction-validation.xml中读出,并显示在对应文本框的上面。
10.2.3验证框架的运行原理
通过前面的示例会发现,要加上验证框架是那么的简单惬意,只需要增加一个验证文件,再为Action配置一个名为input的Result就可以了。但是验证框架到底是如何运行的呢?接下来就来分析一下验证框架的运行流程。
1:相关的拦截器
在Struts2中,要为Action配置相应的验证功能,需要引用validation拦截器,可以在struts-default.xml中找到与validation拦截器相关的配置,示例如下:
java代码:
- <package name="struts-default" abstract="true">
- <interceptors>
- <interceptor name="validation"
- s="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
- <interceptor-stack name="defaultStack">
- .
- <interceptor-ref name="params">
- <param name="excludeParams">dojo\..*,^struts\..*</param>
- </interceptor-ref>
- <interceptor-ref name="conversionError"/>
- <interceptor-ref name="validation">
- <param name="excludeMethods">input,back,cancel,browse</param>
- </interceptor-ref>
- .
- </interceptor-stack>
- </interceptors>
-
- <default-interceptor-ref name="defaultStack"/>
- </package>
首先,validation拦截器被声明在了defaultStack拦截器栈里,因此,我们的Action引用了这个拦截器,因为我们的Action没有配置拦截器,那就使用默认的defaultStack。
其次,在validation拦截器之前,又声明了params拦截器和conversionError拦截器。这三个拦截器都在Action的execute方法执行前运行,分别实现:
- params拦截器将请求的参数反射的设置入Action的属性。当然,这时候有可能出错,比如,要将“18a”这个字符串放入一个int属性的时候,肯定会出错。
- conversionError拦截器在params拦截器出错的情况下,把出现的错误放在值栈中。
- validation拦截器验证Action的属性是否符合条件。
在以上的三个功能中,最关键的是validation拦截器,它会根据验证文件的配置进行验证,但是到底验证的是谁呢?
其实validation验证的是值栈里面的相应内容,而值栈里面的这些相应内容则来源于请求的参数部分。
2:validation拦截器操作值栈
通过示例来说明validation拦截器验证的是值栈的内容。
示例大概需要进行三步修改:
- 修改一下UserModel,为它的age属性设置默认值,比如为12,示例如下:
修改一下注册页面,去掉user.age这个文本框,但是在前面加上显示错误信息部分:
java代码:
- 用户注册
- <hr>
- <s:fielderror/>
- <hr>
- <s:form action="/registerAction.action">
- <s:textfield name="user.account" label="账号"/>
- <s:textfield name="user.name" label="姓名"/>
- <s:submit value="注册"/>
- </s:form>
注意:加上的<s:fielderror/>即为显示错误信息的标签。
修改一下验证文件,让返回的错误信息中直接引用值栈的内容,只需要修改其中关于user.age的部分:
java代码:
- <field name="user.age">
- <field-validator type="int">
- <param name="min">18</param>
- <message>年龄必须在18岁以上,您输入的是${user.age}</message>
- </field-validator>
- </field>
在message中引用${user.age}即为使用ognl引用值栈的内容,当前的值栈的顶层对象为Action对象,所以${user.age}实为引用Action对象的user属性的age属性。
这时候,再访问注册页面,发现已经没有年龄的文本框了。提交的时候填入账号和姓名,这时候发现运行的结果为:
图10.2 验证validation拦截器验证值栈的内容
有些朋友可能会问,页面并没有传入user.age参数,validation拦截器怎么说输入的值是12呢?
这就是因为在UserModel的age属性上设置了age的默认值为12,而且提交请求的时候也没有提交user.age这个参数,所以,Struts2默认就把12放入值栈,因此,验证操作的user.age的数据也就是12了。
这也变相说明:validation拦截器操作的是值栈而不仅仅是请求的参数了。不过,这绝对是个好事,值栈可是个聚宝盆,里面什么都有,比如,要验证填入的参数是不是和session中的某个值相等,都是可以做到的了。
另外一个就是注意在验证的配置文件里面,引用值栈的语法,是“${}”,里面写的同样是OGNL表达式。
验证完之后,请大家将域对象UserModel和注册页面还原,以备后需使用,验证文件不用还原,保留就可以了。
3:类型转换出错的情况
在详细描述验证框架的运行流程前,还需要思考一个问题,如果在进行类型转换的时候出错了怎么办?
比如在user.age中填入的是个字符串,如“18a”,不能转换为数字怎么办?
params拦截器不能把18a转换为数字,不能操作值栈中user.age对应的值,而user.age就保持其初始值,即Action对象的user属性的age属性的初始值,如果没有设置默认值的话,它就是0;接下来conversionError拦截器把这个错误放入值栈,注意:这个错误和拦截器验证得到的有关user.age的错误一样,姑且称之为字段验证错误;最后validation拦截器框架仍然执行user.age验证,这时值栈中user.age的值就是0。所以,综上所述,关于user.age会得到两条错误,“类型转换错误”和“填入的年龄小于18”。
运行测试一下,现在填入账号和姓名,但是年龄填入18a,得到的结果为:
图10.3 用户输入无法正确类型转换时验证器框架的工作情况
4:验证框架的运行流程
把上面的知识总结一下,用流程图来描述验证器框架的运行流程,如下图所示:
图10.4 验证器框架运行流程
私塾在线网站原创《研磨struts2》系列
转自请注明出处:【http://sishuok.com/forum/blogPost/list/0/4091.html】
欢迎访问http://sishuok.com获取更多内容