在Struts 2.0中实现表单数据校验(Validation) - Max On Jav...
来源:百度文库 编辑:神马文学网 时间:2024/07/08 14:54:42
All Input Is Evil!
-Writing secure code
在写前几篇文章的时候,有些朋友建议我的写一篇关于表单数据校验的文章。 正如文章的开头所引用的《Writing Secure Code》的名言:“所有的输入都是罪恶的”,所以我们应该对所有的外部输入进行校验。而表单是应用程序最简单的入口,对其传进来的数据,我们必须进行校验。
转换与校验(Conversion & Validation)
其实上篇文章,我本来是打算写表单数据校验的内容,但是经过再三思考后,还是决定先写Struts 2.0转换器的内容。原因是我认为转换是校验的基础,只有在数据被正确地转换成其对应的类型后,我们才可以对其取值范围进行校验。看个例子相信大家可以更清楚。现在我们就来改造一下《转换器(Converter)——Struts 2.0中的魔术师》的第一个例子。
首先,从Action开始,修改后的代码如下:
package tutorial;
![](http://image.360doc.cn/DownloadImg/10754/261233_2.gif)
import java.util.Locale;
![](http://image.360doc.cn/DownloadImg/10754/261233_4.gif)
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
![](http://image.360doc.cn/DownloadImg/10754/261233_7.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_8.gif)
public class HelloWorld extends ActionSupport
{
private String msg;
private Locale loc = Locale.US;
![](http://image.360doc.cn/DownloadImg/10754/261233_13.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_14.gif)
public String getMsg()
{
return msg;
}
![](http://image.360doc.cn/DownloadImg/10754/261233_19.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_20.gif)
public Locale getLoc()
{
return loc;
}
![](http://image.360doc.cn/DownloadImg/10754/261233_25.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_26.gif)
public void setLoc(Locale loc)
{
this .loc = loc;
}
![](http://image.360doc.cn/DownloadImg/10754/261233_31.gif)
@Override
![](http://image.360doc.cn/DownloadImg/10754/261233_33.gif)
public void validate()
{
System.out.println( " Calling validate()
" );
![](http://image.360doc.cn/DownloadImg/10754/261233_38.gif)
if ( ! (loc.equals(Locale.US) || loc.equals(Locale.CHINA)))
{
addFieldError( " loc " , getText( " validation.loc " ));
}
}
![](http://image.360doc.cn/DownloadImg/10754/261233_44.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_45.gif)
public void validateExecute()
{
System.out.println( " Calling validateExecute() by reflection
" );
}
![](http://image.360doc.cn/DownloadImg/10754/261233_51.gif)
@Override
![](http://image.360doc.cn/DownloadImg/10754/261233_53.gif)
public String execute()
{
System.out.println( " Calling execute()
" );
// LocalizedTextUtil是Struts 2.0中国际化的工具类,标志就是通过调用它实现国际化的
msg = LocalizedTextUtil.findDefaultText( " HelloWorld " , loc);
return SUCCESS;
}
}
然后,修改Struts.xml中Action的定义指明输入地址:
< action name ="HelloWorld" class ="tutorial.HelloWorld" >
< result > /HelloWorld.jsp result >
< result name ="input" > /HelloWorld.jsp result >
action >
接着,在HelloWorld.jsp中加入错误提示:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
head >
< body >
< div style ="color:red;" >
< s:fielderror />
div >
< s:form action ="HelloWorld" theme ="simple" >
Locale: < s:textfield name ="loc" /> < s:submit />
s:form >
< h2 >< s:property value ="msg" /> h2 >
body >
html >
再修改LocaleConverter.java文件,将内容改为:
package tutorial;
![](http://image.360doc.cn/DownloadImg/10754/261233_64.gif)
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
![](http://image.360doc.cn/DownloadImg/10754/261233_68.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_69.gif)
public class LocaleConverter extends ognl.DefaultTypeConverter
{
@Override
![](http://image.360doc.cn/DownloadImg/10754/261233_73.gif)
public Object convertValue(Map context, Object value, Class toType)
{
![](http://image.360doc.cn/DownloadImg/10754/261233_76.gif)
if (toType == Locale. class )
{
System.out.println( " Converting String to Locale
" );
String locale = ((String[]) value)[ 0 ];
return new Locale(locale.substring( 0 , 2 ), locale.substring( 3 ));
![](http://image.360doc.cn/DownloadImg/10754/261233_83.gif)
} else if (toType == String. class )
{
System.out.println( " Converting Locale to String
" );
Locale locale = (Locale) value;
return locale.toString();
}
return null ;
}
}
之后,修改国际化资源文件,内容为:
HelloWorld = 你好,世界!
invalid.fieldvalue.loc = Locale必须为\ " xx_XX\ " 的格式
validation.loc = 区域必须为中国或美国
globalMessages_zh_CN.properties
HelloWorld = Hello World!
invalid.fieldvalue.loc = Locale must like \ " xx_XX\ "
validation.loc = Locale must be China or USA
globalMessages_en_US.properties
发布运行应用程序,在浏览器中键入http://localhost:8080/Struts2_Validation/HelloWorld.action,在Locale中输入zh_CN,按“Submit”提交,效果如上篇文章所示。而在服务器控制台有如下输出:
Converting String to Locale...
Calling validateExecute() by reflection...
Calling validate()...
Calling execute()...
Converting Locale to String...
上述的输出说明了Struts 2.0的数据校验工作方式,它需要经过下面几个步骤:
通过转换器将请求参数转换成相应的Bean属性; 判断转换过程是否出现异常。如果有,则将其保存到ActionContext中,conversionError拦截器再封装为fieldError;如果没有,进行下一步; 通过反射(Reflection)来调用validateXxx()方法(其中,Xxx表示Action的方法名); 调用validate()方法; 如果经过上述步骤没有出现fieldError,则调用Action方法;如果有,则会跳过Action方法,通过国际化将fieldError输出到页面。
不喜欢看文字的朋友,可以参考下面的图1。
![](http://image.360doc.cn/DownloadImg/10754/261233_94.jpg)
图1 校验顺序图
看到这里可能大家会疑问:“这么多地方可以校验表单数据,到底我应该在那里做呢?”有选择是好事,但抉择的过程往往是痛苦的,往往让人不知所措。如果大家参照以下几点建议,相信会比较容易地做出正确的抉择。
如果需要转换的数据,通常做法在转换的时候做格式的校验,在Action中的校验方法中校验取值。假如用户填错了格式,我们可以通过在资源文件配置invalid.fieldvalue.xxx(xxx为属性名)来提示用户正确的格式,不同的阶段出错显示不同的信息。具体做法请参考上面的例子; 至于用validate()还是validateXxx(),我推荐使用validate()。原因是validateXxx()使用了反射,相对来说性能稍差,而validate()则是通过接口com.opensymphony.xwork2.Validateable调用。当然如果你的表单数据取值是取决于特定Action方法,则应该使用validateXxx()。
在运行上面的例子时,在Locale中输入zh并提交时出现图2所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_95.gif)
图2 错误格式
在Locale中输入de_DE时,出现如图3所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_96.gif)
图3 取值错误
使用Struts 2.0的校验框架
上一节的内容都是关于如何编程实现校验,这部分工作大都是单调的重复。更多情况下,我们使用Struts 2.0的校验框架,通过配置实现一些常见的校验。
我学习编程有个习惯——喜欢先看输出结果,再看代码实现。这样学的好处是先看结果可以刺激学习的激情,也可以在看代码前自已思考一下如何实现,然后带着问题去看代码,那就清晰多了。因此下面我们先来做演示。
首先,在tutorial包下新建ValidationAction.java,代码如下:
package tutorial;
![](http://image.360doc.cn/DownloadImg/10754/261233_98.gif)
import com.opensymphony.xwork2.ActionSupport;
![](http://image.360doc.cn/DownloadImg/10754/261233_100.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_101.gif)
public class ValidationAction extends ActionSupport
{
private String reqiuredString;
![](http://image.360doc.cn/DownloadImg/10754/261233_105.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_106.gif)
public String getReqiuredString()
{
return reqiuredString;
}
![](http://image.360doc.cn/DownloadImg/10754/261233_111.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_112.gif)
public void setReqiuredString(String reqiuredString)
{
this .reqiuredString = reqiuredString;
}
![](http://image.360doc.cn/DownloadImg/10754/261233_117.gif)
@Override
![](http://image.360doc.cn/DownloadImg/10754/261233_119.gif)
public String execute()
{
return SUCCESS;
}
}
然后,配置上述所建的Ation,代码片段如下:
< action name ="ValidationAction" class ="tutorial.ValidationAction" >
< result > /Output.jsp result >
< result name ="input" > /Input.jsp result >
action >
接着,创建Input.jsp和Output.jsp,内容分别如下:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
< s:head />
head >
< body >
< s:form action ="ValidationAction" >
< s:textfield name ="reqiuredString" label ="Required String" />
< s:submit />
s:form >
body >
html >
Input.jsp
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
head >
< body >
Required String: < s:property value ="reqiuredString" />
body >
html >
Output.jsp
再接下来,在tutorial包下创建ValidationAction的校验配置文件Xxx-validation.xml(Xxx为Action的类名),在本例中该文件名ValidationAction-validation.xml,内容如下:
xml version="1.0" encoding="UTF-8" ?>
"-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd" >
< validators >
< field name ="reqiuredString" >
< field-validator type ="requiredstring" >
< message > This string is required message >
field-validator >
field >
validators >
发布运行应用程序,在地址栏中键入http://localhost:8080/Struts2_Validation/Input.jsp,出现如图4所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_125.gif)
图4 Input.jsp
直接点击“Submit”提交表单,出现图5所示的页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_126.gif)
图5 错误提示
在Required String中随便填点东西,转到Output.jsp页面,如图6所示。
![](http://image.360doc.cn/DownloadImg/10754/261233_127.gif)
图6 Output.jsp
通过上面的例子,大家可以看到使用该校验框架十分简单方便。不过,上例还有两点不足:
还没有国际化错误消息; 没有实现客户端的校验。
当然,要完善以上不足,对于Struts 2.0来说,只是小菜一碟。
在Xxx-validation.xml文件中的元素中加入key属性; 在Input.jsp中的标志中加入validate="true"属性,就可以在用Javascript在客户端校验数据。
下面是具体的实现,首先在国际化资源文件中加入错误消息,然后按照上面说明实现。因为要使用Javascript在客户端显示出错信息,所以在加载Input.jsp页面时,Struts 2.0需要获得国际化的字符串,故我们需要使用Action来访问Input.jsp页面,具体实现请参考《在Struts 2.0中国际化(i18n)您的应用程序》的最后部分。最后发布运行应用程序,直接在页面中点击“Submit”,表单没有被提交并出现错误提示,如图7所示:
![](http://image.360doc.cn/DownloadImg/10754/261233_128.gif)
图7 客户端校验
校验框架是通过validation拦截器实现,该拦载被注册到默认的拦截器链中。它在conversionError拦截器之后,在validateXxx()之前被调用。这里又出现了一个选择的问题:到底是应该在action中通过validateXxx()或validate()实现校验,还是使用validation拦截器?绝大多数情况,我建议大家使用校验框架,只有当框架满足不了您的要求才自已编写代码实现。
配置文件查找顺序
在上面的例子中,我们通过创建ValidationAction-validation.xml来配置表单校验。Struts 2.0的校验框架自动会读取该文件,但这样就会引出一个问题——如果我的Action继承其它的Action类,而这两个Action类都需要对表单数据进行校验,那我是否会在子类的配置文件(Xxx-validation.xml)中复制父类的配置吗?
答案是不,因为Struts 2.0的校验框架跟《在Struts 2.0中国际化(i18n)您的应用程序》提到的“资源文件查找顺序”相似,有特定的配置文件查找顺序。不同的是校验框架按照自上而下的顺序在类层次查找配置文件。假设以下条件成立:
接口 Animal; 接口 Quadraped 扩展了 Animal; 类 AnimalImpl 实现了 Animal; 类 QuadrapedImpl 扩展了 AnimalImpl 实现了 Quadraped; 类 Dog 扩展了 QuadrapedImpl;
如果Dog要被校验,框架方法会查找下面的配置文件(其中别名是Action在struts.xml中定义的别名):
Animal-validation.xml Animal-别名-validation.xml AnimalImpl-validation.xml AnimalImpl-别名-validation.xml Quadraped-validation.xml Quadraped-别名-validation.xml QuadrapedImpl-validation.xml QuadrapedImpl-别名-validation.xml Dog-validation.xml Dog-别名-validation.xml
已有的校验器
Struts 2.0已经为您实现很多常用的校验了,以下在jar的default.xml中的注册的校验器。
< validators >
< validator name ="required" class ="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator" />
< validator name ="requiredstring" class ="com.opensymphony.xwork2.validator.validators.RequiredStringValidator" />
< validator name ="int" class ="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator" />
< validator name ="double" class ="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator" />
< validator name ="date" class ="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator" />
< validator name ="expression" class ="com.opensymphony.xwork2.validator.validators.ExpressionValidator" />
< validator name ="fieldexpression" class ="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator" />
< validator name ="email" class ="com.opensymphony.xwork2.validator.validators.EmailValidator" />
< validator name ="url" class ="com.opensymphony.xwork2.validator.validators.URLValidator" />
< validator name ="visitor" class ="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator" />
< validator name ="conversion" class ="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator" />
< validator name ="stringlength" class ="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator" />
< validator name ="regex" class ="com.opensymphony.xwork2.validator.validators.RegexFieldValidator" />
validators >
关于每个校验器的具体用法,请参考以下链接:
http://wiki.javascud.org/display/ww2cndoc/Validation
该链接中还有一些很有的信息,请大家仔细阅读。
总结
使用校验框架既可以方便地实现表单数据校验,又能够将校验与Action分离,故我们应该尽可能使用校验框架。在使用校验框架时,请不要忘记通过在资源文件加入invalid.fieldvalue.xxx字符串,显示适合的类型转换出错信息;或者使用conversion校验器。
posted on 2006-11-14 13:38Max 阅读(393)评论(2) 编辑 收藏引用收藏至365Key 所属分类:Struts 2.0系列
![](http://www.blogjava.net/max/aggbug/81106.html?webview=1)
评论:
# re: 在Struts 2.0中实现表单数据校验(Validation) 2006-11-15 15:51 |ronghai
你好怎么样才能联系到你,好好了解一些struts2。发现1.X和2有太大的差别了,刚把1.x弄得差不多,看2觉得很不是理解。 回复
# re: 在Struts 2.0中实现表单数据校验(Validation) 2006-11-16 09:01 |Max
你可以通过email联系我, max.m.yuan@gmail.com 回复
-Writing secure code
在写前几篇文章的时候,有些朋友建议我的写一篇关于表单数据校验的文章。 正如文章的开头所引用的《Writing Secure Code》的名言:“所有的输入都是罪恶的”,所以我们应该对所有的外部输入进行校验。而表单是应用程序最简单的入口,对其传进来的数据,我们必须进行校验。
转换与校验(Conversion & Validation)
其实上篇文章,我本来是打算写表单数据校验的内容,但是经过再三思考后,还是决定先写Struts 2.0转换器的内容。原因是我认为转换是校验的基础,只有在数据被正确地转换成其对应的类型后,我们才可以对其取值范围进行校验。看个例子相信大家可以更清楚。现在我们就来改造一下《转换器(Converter)——Struts 2.0中的魔术师》的第一个例子。
首先,从Action开始,修改后的代码如下:
![](http://image.360doc.cn/DownloadImg/10754/261233_1.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_2.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_3.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_4.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_5.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_6.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_7.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_8.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_9.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_10.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_11.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_12.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_13.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_14.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_15.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_16.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_17.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_18.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_19.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_20.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_21.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_22.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_23.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_24.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_25.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_26.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_27.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_28.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_29.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_30.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_31.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_32.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_33.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_34.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_35.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_36.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_37.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_38.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_39.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_40.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_41.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_42.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_43.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_44.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_45.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_46.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_47.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_48.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_49.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_50.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_51.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_52.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_53.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_54.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_55.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_56.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_57.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_58.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_59.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_60.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_61.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_62.gif)
然后,修改Struts.xml中Action的定义指明输入地址:
< action name ="HelloWorld" class ="tutorial.HelloWorld" >
< result > /HelloWorld.jsp result >
< result name ="input" > /HelloWorld.jsp result >
action >
接着,在HelloWorld.jsp中加入错误提示:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
head >
< body >
< div style ="color:red;" >
< s:fielderror />
div >
< s:form action ="HelloWorld" theme ="simple" >
Locale: < s:textfield name ="loc" /> < s:submit />
s:form >
< h2 >< s:property value ="msg" /> h2 >
body >
html >
再修改LocaleConverter.java文件,将内容改为:
![](http://image.360doc.cn/DownloadImg/10754/261233_63.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_64.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_65.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_66.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_67.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_68.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_69.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_70.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_71.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_72.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_73.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_74.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_75.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_76.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_77.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_78.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_79.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_80.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_81.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_82.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_83.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_84.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_85.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_86.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_87.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_88.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_89.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_90.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_91.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_92.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_93.gif)
之后,修改国际化资源文件,内容为:
HelloWorld = 你好,世界!
invalid.fieldvalue.loc = Locale必须为\ " xx_XX\ " 的格式
validation.loc = 区域必须为中国或美国
globalMessages_zh_CN.properties
HelloWorld = Hello World!
invalid.fieldvalue.loc = Locale must like \ " xx_XX\ "
validation.loc = Locale must be China or USA
globalMessages_en_US.properties
发布运行应用程序,在浏览器中键入http://localhost:8080/Struts2_Validation/HelloWorld.action,在Locale中输入zh_CN,按“Submit”提交,效果如上篇文章所示。而在服务器控制台有如下输出:
Converting String to Locale...
Calling validateExecute() by reflection...
Calling validate()...
Calling execute()...
Converting Locale to String...
上述的输出说明了Struts 2.0的数据校验工作方式,它需要经过下面几个步骤:
通过转换器将请求参数转换成相应的Bean属性; 判断转换过程是否出现异常。如果有,则将其保存到ActionContext中,conversionError拦截器再封装为fieldError;如果没有,进行下一步; 通过反射(Reflection)来调用validateXxx()方法(其中,Xxx表示Action的方法名); 调用validate()方法; 如果经过上述步骤没有出现fieldError,则调用Action方法;如果有,则会跳过Action方法,通过国际化将fieldError输出到页面。
不喜欢看文字的朋友,可以参考下面的图1。
![](http://image.360doc.cn/DownloadImg/10754/261233_94.jpg)
图1 校验顺序图
看到这里可能大家会疑问:“这么多地方可以校验表单数据,到底我应该在那里做呢?”有选择是好事,但抉择的过程往往是痛苦的,往往让人不知所措。如果大家参照以下几点建议,相信会比较容易地做出正确的抉择。
如果需要转换的数据,通常做法在转换的时候做格式的校验,在Action中的校验方法中校验取值。假如用户填错了格式,我们可以通过在资源文件配置invalid.fieldvalue.xxx(xxx为属性名)来提示用户正确的格式,不同的阶段出错显示不同的信息。具体做法请参考上面的例子; 至于用validate()还是validateXxx(),我推荐使用validate()。原因是validateXxx()使用了反射,相对来说性能稍差,而validate()则是通过接口com.opensymphony.xwork2.Validateable调用。当然如果你的表单数据取值是取决于特定Action方法,则应该使用validateXxx()。
在运行上面的例子时,在Locale中输入zh并提交时出现图2所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_95.gif)
图2 错误格式
在Locale中输入de_DE时,出现如图3所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_96.gif)
图3 取值错误
使用Struts 2.0的校验框架
上一节的内容都是关于如何编程实现校验,这部分工作大都是单调的重复。更多情况下,我们使用Struts 2.0的校验框架,通过配置实现一些常见的校验。
我学习编程有个习惯——喜欢先看输出结果,再看代码实现。这样学的好处是先看结果可以刺激学习的激情,也可以在看代码前自已思考一下如何实现,然后带着问题去看代码,那就清晰多了。因此下面我们先来做演示。
首先,在tutorial包下新建ValidationAction.java,代码如下:
![](http://image.360doc.cn/DownloadImg/10754/261233_97.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_98.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_99.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_100.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_101.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_102.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_103.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_104.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_105.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_106.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_107.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_108.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_109.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_110.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_111.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_112.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_113.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_114.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_115.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_116.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_117.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_118.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_119.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_120.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_121.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_122.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_123.gif)
![](http://image.360doc.cn/DownloadImg/10754/261233_124.gif)
然后,配置上述所建的Ation,代码片段如下:
< action name ="ValidationAction" class ="tutorial.ValidationAction" >
< result > /Output.jsp result >
< result name ="input" > /Input.jsp result >
action >
接着,创建Input.jsp和Output.jsp,内容分别如下:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
< s:head />
head >
< body >
< s:form action ="ValidationAction" >
< s:textfield name ="reqiuredString" label ="Required String" />
< s:submit />
s:form >
body >
html >
Input.jsp
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Hello World title >
head >
< body >
Required String: < s:property value ="reqiuredString" />
body >
html >
Output.jsp
再接下来,在tutorial包下创建ValidationAction的校验配置文件Xxx-validation.xml(Xxx为Action的类名),在本例中该文件名ValidationAction-validation.xml,内容如下:
xml version="1.0" encoding="UTF-8" ?>
"-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd" >
< validators >
< field name ="reqiuredString" >
< field-validator type ="requiredstring" >
< message > This string is required message >
field-validator >
field >
validators >
发布运行应用程序,在地址栏中键入http://localhost:8080/Struts2_Validation/Input.jsp,出现如图4所示页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_125.gif)
图4 Input.jsp
直接点击“Submit”提交表单,出现图5所示的页面。
![](http://image.360doc.cn/DownloadImg/10754/261233_126.gif)
图5 错误提示
在Required String中随便填点东西,转到Output.jsp页面,如图6所示。
![](http://image.360doc.cn/DownloadImg/10754/261233_127.gif)
图6 Output.jsp
通过上面的例子,大家可以看到使用该校验框架十分简单方便。不过,上例还有两点不足:
还没有国际化错误消息; 没有实现客户端的校验。
当然,要完善以上不足,对于Struts 2.0来说,只是小菜一碟。
在Xxx-validation.xml文件中的
下面是具体的实现,首先在国际化资源文件中加入错误消息,然后按照上面说明实现。因为要使用Javascript在客户端显示出错信息,所以在加载Input.jsp页面时,Struts 2.0需要获得国际化的字符串,故我们需要使用Action来访问Input.jsp页面,具体实现请参考《在Struts 2.0中国际化(i18n)您的应用程序》的最后部分。最后发布运行应用程序,直接在页面中点击“Submit”,表单没有被提交并出现错误提示,如图7所示:
![](http://image.360doc.cn/DownloadImg/10754/261233_128.gif)
图7 客户端校验
校验框架是通过validation拦截器实现,该拦载被注册到默认的拦截器链中。它在conversionError拦截器之后,在validateXxx()之前被调用。这里又出现了一个选择的问题:到底是应该在action中通过validateXxx()或validate()实现校验,还是使用validation拦截器?绝大多数情况,我建议大家使用校验框架,只有当框架满足不了您的要求才自已编写代码实现。
配置文件查找顺序
在上面的例子中,我们通过创建ValidationAction-validation.xml来配置表单校验。Struts 2.0的校验框架自动会读取该文件,但这样就会引出一个问题——如果我的Action继承其它的Action类,而这两个Action类都需要对表单数据进行校验,那我是否会在子类的配置文件(Xxx-validation.xml)中复制父类的配置吗?
答案是不,因为Struts 2.0的校验框架跟《在Struts 2.0中国际化(i18n)您的应用程序》提到的“资源文件查找顺序”相似,有特定的配置文件查找顺序。不同的是校验框架按照自上而下的顺序在类层次查找配置文件。假设以下条件成立:
接口 Animal; 接口 Quadraped 扩展了 Animal; 类 AnimalImpl 实现了 Animal; 类 QuadrapedImpl 扩展了 AnimalImpl 实现了 Quadraped; 类 Dog 扩展了 QuadrapedImpl;
如果Dog要被校验,框架方法会查找下面的配置文件(其中别名是Action在struts.xml中定义的别名):
Animal-validation.xml Animal-别名-validation.xml AnimalImpl-validation.xml AnimalImpl-别名-validation.xml Quadraped-validation.xml Quadraped-别名-validation.xml QuadrapedImpl-validation.xml QuadrapedImpl-别名-validation.xml Dog-validation.xml Dog-别名-validation.xml
已有的校验器
Struts 2.0已经为您实现很多常用的校验了,以下在jar的default.xml中的注册的校验器。
< validators >
< validator name ="required" class ="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator" />
< validator name ="requiredstring" class ="com.opensymphony.xwork2.validator.validators.RequiredStringValidator" />
< validator name ="int" class ="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator" />
< validator name ="double" class ="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator" />
< validator name ="date" class ="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator" />
< validator name ="expression" class ="com.opensymphony.xwork2.validator.validators.ExpressionValidator" />
< validator name ="fieldexpression" class ="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator" />
< validator name ="email" class ="com.opensymphony.xwork2.validator.validators.EmailValidator" />
< validator name ="url" class ="com.opensymphony.xwork2.validator.validators.URLValidator" />
< validator name ="visitor" class ="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator" />
< validator name ="conversion" class ="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator" />
< validator name ="stringlength" class ="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator" />
< validator name ="regex" class ="com.opensymphony.xwork2.validator.validators.RegexFieldValidator" />
validators >
![](http://image.360doc.cn/DownloadImg/10754/261233_129.gif)
http://wiki.javascud.org/display/ww2cndoc/Validation
该链接中还有一些很有的信息,请大家仔细阅读。
总结
使用校验框架既可以方便地实现表单数据校验,又能够将校验与Action分离,故我们应该尽可能使用校验框架。在使用校验框架时,请不要忘记通过在资源文件加入invalid.fieldvalue.xxx字符串,显示适合的类型转换出错信息;或者使用conversion校验器。
posted on 2006-11-14 13:38Max 阅读(393)评论(2) 编辑 收藏引用收藏至365Key 所属分类:Struts 2.0系列
评论:
# re: 在Struts 2.0中实现表单数据校验(Validation) 2006-11-15 15:51 |ronghai
你好怎么样才能联系到你,好好了解一些struts2。发现1.X和2有太大的差别了,刚把1.x弄得差不多,看2觉得很不是理解。 回复
# re: 在Struts 2.0中实现表单数据校验(Validation) 2006-11-16 09:01 |Max
你可以通过email联系我, max.m.yuan@gmail.com 回复
在Struts 2.0中实现表单数据校验(Validation) - Max On Jav...
在Struts 2.0中实现表单数据校验(Validation)
在Struts 2中实现文件上传 - Max On Java - BlogJava
在Struts 2中实现文件上传 - Max On Java - BlogJava
Struts 2.0系列-在Struts 2中实现IoC
Struts 2.0的Action讲解 - Max On Java - BlogJava
在Struts 2中实现IoC
在Struts 2中实现文件上传
在Struts 2中实现文件上传
在Struts 2中实现CRUD
在Struts 2中实现CRUD
在Struts 2中实现IoC
在Struts 2中实现文件上传
具有自动数据校验功能的struts标签
具有自动数据校验功能的struts标签
在Struts中应用Ajax
asp取动态表单中数据并写入xml文件
asp取动态表单中数据并写入xml文
学习Struts 2.0系列(4) 在Struts 2.0中国际化您的应用程序
在Struts 2.0中国际化(i18n)您的应用程序
在Struts 2.0中国际化(i18n)您的应用程序
ASP.NET 2.0中实现模板中的数据绑定
ASP.NET 2.0中实现模板中的数据绑定
Silverlight实例教程 - Validation数据验证开篇