数据校验:
struts1.x : actionform的validate方法和commons-validate.jar
常用两种方式:validatexxx()方法与集成xwork框架校验
两种方式比较:
前一种若有多个action在一个类里须写很多validate方法,不好维护,麻烦,不推荐使用,它调用的是原生的action-validate
后一种:又能够将校验与Action分离,扩展好
api-validation(详细看API)
Struts Action 2 relies on a validation framework provided by [XWork] to enable
the application of input validation rules to your Actions before they are executed.
This section only provides the bare minimum to get you started and focuses on our extension of the XWork
validators to support client-side validation.
struts2.x:
下面这些我想说明,xwork校验是内置在struts2框架里的
struts2-defalut.xml
默认包
<package name="struts-default" abstract="true">
默认拦截器栈
<default-interceptor-ref name="defaultStack"/>
拦截器栈
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="profiling"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo/..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/> //conversionError拦截器
<interceptor-ref name="validation"> //校验拦截器
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
Struts 2.0的数据校验工作方式:
1.通过转换器将请求提交参数转换成相应的Bean(VO)属性;
2.判断转换过程是否出现异常。如果有,则将其保存到ActionContext中,conversionError拦截器再封装为fieldError;如果没有,进行下一步;
3.通过反射(Reflection)来调用validateXxx()方法(其中,Xxx表示Action的方法名);
4.调用validate()方法;
如果经过上述步骤没有出现fieldError,则调用Action方法;如果有,则会跳过Action方法,若有国际化通过国际化将fieldError输出到页面。
案例配置:
使用Struts 2.0的校验框架:
步骤:两步:
在struts.xml里为配置的action增加input 视图
写好Action后,直接为它 加一个校验配置文件 如xxx-validation.xml,自己定义规则。放在src/与Action同包下,注意命名规则
一个例子:
a.搭起正常的struts+spring框架,用spring管理方便扩展
b.下面是具体配置示范
===struts.xml===
<struts>
<constant name="struts.custom.i18n.resources" value="ApplicationResources" />
<constant name="struts.objectFactory" value="spring"/>
<package name="lib" extends="struts-default" namespace="/">
<action name="check" class="checkAction" method="check" >
<result name="input">/check1.jsp</result> //这个加了校验,必加入,表示校验不成后的视图
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
===action.CheckAction===
import com.opensymphony.xwork2.ActionSupport;
import domain.User;
/**
* 示范校验action
* @author 111
*
*/
public class CheckAction extends ActionSupport {
/**
* value object值对象
*/
private User user;
/**
* 真正处理action的方法
* @return String result
* @throws Exception
*/
public String check() throws Exception {
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
====domain(VO).user.java===
//把值放在值对象,方便
import java.util.Date;
public class User {
private String text1;
private String text2;
private String email;
private Integer int1;
private Date date1;
private Date date2;
private String select1;
public String getText1() {
return text1;
}
public void setText1(String text1) {
this.text1 = text1;
}
public Integer getInt1() {
return int1;
}
public void setInt1(Integer int1) {
this.int1 = int1;
}
public Date getDate1() {
return date1;
}
public void setDate1(Date date1) {
this.date1 = date1;
}
public Date getDate2() {
return date2;
}
====CheckAction-validation.xml====
// 详细校验控制,还有其他的校验配置,这里是合适的一种
<validators>
<field name="user.text1">
<field-validator type="requiredstring"> //user.text1字段必须输入字符也包括数字
<param name="trim">true</param>
<message>You must enter a value for 必须输入.</message>
</field-validator>
</field>
<field name="user.text2">
<field-validator type="stringlength"> //长度限制
<param name="minLength">2</param>
<param name="maxLength">20</param>
<message>长度应在${minLength}到${maxLength}个字符间</message>
</field-validator>
</field>
<field name="user.int1">
<field-validator type="required"> // 必须输入
<message>You must enter a value for 年龄.</message>
</field-validator>
<field-validator type="int"> //要求是INT型,有范围限制
<param name="min">6</param>
<param name="max">100</param>
<message>tesxt1 must be between ${min} and ${max}, current value is ${user.int1}.</message>
</field-validator>
</field>
<field name="user.date1">
<field-validator type="required"> //一样
<message>You must enter a value for 日期加范围左边.</message>
</field-validator>
<field-validator type="date"> //这里就是日期的校验,
<param name="min">1900-01-01</param>
<param name="max">2009-12-29</param>
<message>The date(u put:${user.date1}) must be between ${min} and ${max}.</message>
</field-validator>
</field>
<field name="user.date2">
<field-validator type="required">
<message>You must enter a value for 日期加范围右边.</message>
</field-validator>
<field-validator type="fieldexpression"> //这里就是实现两个日期的比较,应该有更好的方式
<param name="expression"><![CDATA[user.date2>user.date1]]></param>
<message>左边日期${user.date1}必须小于右边日期${user.date2}</message>
</field-validator>
</field>
<field name="user.select1">
<field-validator type="fieldexpression">
<param name="expression">(user.select1!="s0")</param>
<message>You must enter a value for 下拉框必输入.</message>
</field-validator>
</field>
<field name="user.email"> //邮件校验
<field-validator type="email">
<message><![CDATA[ 请输入有效的邮件地址 ]]></message>
</field-validator>
</field>
</validators>
页面
===check1.jsp====
<%@ page language="java" pageEncoding="utf-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<s:head/> <body>
<s:form action="check" theme="simple" validate="false" namespace="/">
<center><h3>这里会出现所有校验出错信息</h3>
<div style="color:red"><s:fielderror/></div>
<hr>
必须输入<s:textfield name="user.text1" value="这是必须输入的"/> <br> <s:fielderror><s:param>user.text1</s:param>
</s:fielderror><br>
字符长度限制(2)<s:textfield name="user.text2" value="sdd"/> <br><s:fielderror>
<s:param>user.text2</s:param>
</s:fielderror><br>
Email校验<s:textfield name="user.email" value="hello@163.com"/> <br><s:fielderror><s:param>user.email</s:param>
</s:fielderror><br>
有长度限制的数字年龄(6-100)<s:textfield name="user.int1" value="100"/><br>
<s:fielderror><s:param>user.int1</s:param>
</s:fielderror><br>
日期加范围(格式1900-01-01) <s:textfield name="user.date1" maxlength="20" size="13" value="1924-2-22"/>--
<s:textfield name="user.date2" maxlength="20" size="13" value="1944-2-22"/><br>
<s:fielderror><s:param>user.date1</s:param><s:param>user.date2</s:param>
</s:fielderror><br>
下拉列表<s:select label="FooBar" name="user.select1" list="#{'s0':'请选择','s1':'选择一','s2':'选择二'}" /> <br>
<s:fielderror><s:param>user.select1</s:param></s:fielderror><br>
<s:submit value="试试看"></s:submit>
<br>
</center>
<s:debug/>
</s:form>
</body>
</html>
====index.jsp====
<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
</head>
<body>
This is my JSP page. <br>
<hr>
<h4>user attribute:</h4>
<s:property value="user.text1" /><br>
<s:property value="user.text2" /><br>
<s:property value="user.email" /><br>
<s:property value="user.int1" /><br>
<s:property value="user.date1" /><br>
<s:property value="user.date2" /><br>
<s:property value="user.select1"/><br>
<br><center> <s:debug/></center>
</body>
</html>
配置时注意 :a。文件名放在action一起,命名规则为: action名(别名)-validation.xml,
b。action的input 视图不能少,不然会报错
上面的例子有两点不足:
1. 还没有国际化错误消息;
2. 没有实现客户端的校验。
当然,要完善以上不足,对于Struts 2.0来说,只是小菜一碟。
1. 在Xxx-validation.xml文件中的<message>元素中加入key属性; getText
2. 在Input.jsp中的<s:form>标志中加入validate="true"属性,就可以在用Javascript在客户端校验数据。
校验框架是通过validation拦截器实现,该拦载被注册到默认的拦截器链中。它在conversionError拦截器之后,在validateXxx()之前被调用。
这里又出现了一个选择的问题:到底是应该在action中通过validateXxx()或validate()实现校验,还是使用validation拦截器?绝大多数情况
权威建议大家使用校验框架,只有当框架满足不了您的要求才自已编写代码实现。
已有的校验器
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 >
总结
使用校验框架既可以方便地实现表单数据校验,又能够将校验与Action分离,
故我们应该尽可能使用校验框架。在使用校验框架时,
请不要忘记通过在资源文件加入invalid.fieldvalue.xxx字符串,
显示适合的类型转换出错信息;
或者使用conversion校验器。
附录:Type Conversion
我们通过表单输入的数据其实都是一个String,有时需要把这些String转成int date等等
Struts1中也提供了类型转换器,比如form中有一个字段age,当我们输入表单时,
Struts1的转换器会将这个age字符串转换成Form表单中对应的age数值,Struts2提供了更加强大的类型转换.