1 ,输入校验介绍
Struts2 提供了功能强大的输入校验机制,通过 Struts2 内建的输入校验器,应用无需书写任何代码,即可完成大部分的校验功能,并可以同时完成客户端和服务器端的校验。如果应用的输入校验规则特别, Struts2 也允许通过重写 validate 方法来完成自定义校验,另外 Struts2 的开放性还允许开发者提供自定义的校验器。
表现层的数据处理包括两个方面:一是数据类型的转化,因为 Web 应用接收到的所有数据都是字符串类型的;另一个就是输入校验,因为开发者必须全面考虑用户输入的各种情况,尤其需要注意那些非正常输入。
客户端的校验最基础的方法就是在页面写 javascript 代码手工校验,服务器端的校验最基础的方法就是在处理请求的 Servlet 的 service() 方法中添加校验代码。
Struts2 中可以通过重写 validate 方法来完成输入校验。如果我们重写了 validate 方法,则该方法会应用于此 Action 中的所有提供服务的业务方法。 Struts2 支持校验特定方法的 validateXxx() 方法。例如某个 Action 中有一个 regist() 业务方法,我们可以写一个 validateRegist() 方法来进行 regist() 的特殊校验,客户端请求调用的次序如下: validateRegist()--------------->validate()-------------->regist()
Struts2 的输入校验流程如下:
1 ,类型转换器负责对字符串的请求参数执行类型转换,并将这此值设置成 Action 的属性值。
2 ,在执行类型转换过程中可能出现异常,如果出现异常,将异常信息保存到 ActionContext 中, conversionError 拦截器负责将其封装到 fieldError 里,然后执行第 3 步;如果转换过程没有异常信息,则直接进入第 3 步。
3 ,通过反射调用 validateXxx() 方法,其中 Xxx 是即将处理用户请求的处理逻辑所对应的方法名。
4 ,调用 Action 类里的 validate() 方法。
5 ,如果经过上面 4 步都没有出现 fieldError ,将调用 Action 里处理用户请求的处理方法;如果出现了 fieldError ,系统将转入 input 逻辑视图所指定的视图资源。
2 ,java 中 Struts2 的输入校验
1 ,最基础的 Struts2 输入校验
Struts2 中单独对每一个 Action 指定一个校验文件,它的命名方式为 <Action-name>-validation.xml 。它存放在与 Action 相同的包中,校验只需要配置一个校验文件即可实现。系统的其它地方不需要改动,系统会自动加载该文件。校验文件 RegistAction-validation.xml 如下例:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<!-- 校验文件的根元素 -->
<validators>
<!-- 校验Action的name属性 -->
<field name="name">
<!-- 指定name属性必须满足必填规则 -->
<field-validator type="requiredstring">
<!-- 校验前去掉name属性的前后空格 -->
<param name="trim">true</param>
<!-- 提示信息 -->
<message>必须输入名字</message>
</field-validator>
<!-- 指定name属性必须满足匹配指定的正则表达式 -->
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>您输入的用户名只能是字母和数组,且长度必须在4到25之间</message>
</field-validator>
</field>
<field name="pass">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>必须输入密码</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>您输入的密码只能是字母和数组,且长度必须在4到25之间</message>
</field-validator>
</field>
<field name="age">
<!-- 指定age属性必须在指定的范围内 -->
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>年纪必须在1到150之间</message>
</field-validator>
</field>
<field name="birth">
<!-- 指定age属性必须在指定的范围内 -->
<field-validator type="date">
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>年纪必须在${min}到${max}之间</message>
</field-validator>
</field>
</validators>
2 , Struts2 中输入校验提示信息的国际化
在 Struts2 的校验中应用国际化也非常简单,请看如下 xml 配置代码: <field name="name">
<field>
<field-validator type="requiredstring">
<param name="trim">true</param>
<message key="name.requried"/>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message key="name.regex"/>
</field-validator>
</field>
message 元素指定 key 属性指定的是国际化资源中对应的 key 。还可以使用以下配置获取国际化资源中的信息: <message>${getText("name.requried")}</message> 这种方式是通过调用 ActionSupport 类的 getText() 方法来获取国际化资源的。
3 , Struts2 中应用客户端输入校验
使用客户端输入校验可以减轻服务器的负担。 Struts2 对客户端的输入校验进行了封装,使得我们开发时特别容易。
1 , JSP 页面代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册页面</title>
</head>
<body>
<s:form action="regist" validate="true">
<s:textfield label="用户名" name="name"></s:textfield>
<s:password label="密码" name="pass"></s:password>
<s:textfield label="年龄" name="age"></s:textfield>
<s:textfield label="生日" name="birth"></s:textfield>
<s:submit></s:submit>
</s:form>
</body>
</html>
注意这里要用 Struts2 的标签, form 的 validate 属性要设置为 true ,并且不要将 theme 属性指定为 simple.(simple 表示 struts2 将把这个解析成普通的 HTML 标签 )
2 ,校验配置文件:这里的校验配置文件同原先的配置文件并没有不同,但是这里使用 <message key="name.requried"/> 无法从全局国际化资源中获取信息,只能使用 <message>${getText("name.requried")}</message> 方式获取国际化资源。
3 ,部署后的 JSP 页面代码:
大家可以看到部署后的 JSP 页面中自动生成了我们在校验配置文件中对应的 javascript 代码。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册页面</title>
</head>
<body>
<script src="/lovely/struts/xhtml/validation.js"></script>
<form namespace="" id="regist" name="regist" οnsubmit="return validateForm_regist();" action="/lovely/regist.action" method="POST">
<table class="wwFormTable">
<tr>
<td class="tdLabel"><label for="regist_name" class="label">用户名:</label></td>
<td
><input type="text" name="name" value="" id="regist_name"/>
</td>
</tr>
<tr>
<td class="tdLabel"><label for="regist_pass" class="label">密码:</label></td>
<td
><input type="password" name="pass" id="regist_pass"/>
</td>
</tr>
<tr>
<td class="tdLabel"><label for="regist_age" class="label">年龄:</label></td>
<td
><input type="text" name="age" value="" id="regist_age"/>
</td>
</tr>
<tr>
<td class="tdLabel"><label for="regist_birth" class="label">生日:</label></td>
<td
><input type="text" name="birth" value="" id="regist_birth"/>
</td>
</tr>
<tr>
<td colspan="2"><div align="right"><input type="submit" id="regist_0" value="Submit"/>
</div></td>
</tr>
</table></form>
<script type="text/javascript">
function validateForm_regist() {
form = document.getElementById("regist");
clearErrorMessages(form);
clearErrorLabels(form);
var errors = false;
// field name: name
// validator name: requiredstring
if (form.elements['name']) {
field = form.elements['name'];
var error = "必须输入用户名!";
if (field.value != null && (field.value == "" || field.value.replace(/^\s+|\s+$/g,"").length == 0)) {
addError(field, error);
errors = true;
}
}
// field name: name
// validator name: regex
if (form.elements['name']) {
field = form.elements['name'];
var error = "您输入的用户名只能是字母和数组,且长度必须在4到25之间";
if (field.value != null && !field.value.match("(\\w{4,25})")) {
addError(field, error);
errors = true;
}
}
// field name: pass
// validator name: requiredstring
if (form.elements['pass']) {
field = form.elements['pass'];
var error = "必须输入密码";
if (field.value != null && (field.value == "" || field.value.replace(/^\s+|\s+$/g,"").length == 0)) {
addError(field, error);
errors = true;
}
}
// field name: pass
// validator name: regex
if (form.elements['pass']) {
field = form.elements['pass'];
var error = "您输入的密码只能是字母和数组,且长度必须在4到25之间";
if (field.value != null && !field.value.match("(\\w{4,25})")) {
addError(field, error);
errors = true;
}
}
// field name: age
// validator name: int
if (form.elements['age']) {
field = form.elements['age'];
var error = "年纪必须在1到150之间";
if (field.value != null) {
if (parseInt(field.value) <
1 ||
parseInt(field.value) >
150) {
addError(field, error);
errors = true;
}
}
}
// field name: birth
// validator name: date
if (form.elements['birth']) {
field = form.elements['birth'];
var error = "年纪必须在00-1-1到50-2-21之间";
}
return !errors;
}
</script>
</body>
</html>
从上面 Struts2 自动生成的 javascript 代码可以看到,最后的 birth 校验并没有按照我们要求的来校验,可见 Struts2 中并不是所有的服务器端校验都可以转换成客户端校验。客户端校验仅仅支持如下几种校验器:
required validator 必填校验器
requiredstring validator 必填字符串校验器
stringlength validator 字符串长度校验器
regex validator 表达式校验器
email validator 邮件校验器
url validator 网址校验器
int validator 整数校验器
double validator 双精度数校验器
4 ,为指定的方法配置特殊的校验规则
当一个 Action 中有多个业务方法时,我们可能需要对其中的某个方法配置单独的校验规则,比如注册时的要求用户两次输入的密码必须相同等,这时我们可以配置一个单独的校验文件,命名规则为: <actionName>-<methodName>-validation.xml ,可以看到这里多了一个方法名,这个方法名就是要校验的业务逻辑在 struts.xml 配置文件中配置的 name ,这个文件也要同 Action 放在同一个目录下。
5 ,多个校验规则文件的搜索次序
例如有一个 LoginAction 继承 BaseAction ,这两个 Action 中都有业务方法 login ,并且存在 4 份校验规则文件如下: BaseAction-vadition.xml, BaseAction-login-validation.xml , LoginAction-validation.xml, LoginAction-login-validation.xml 那么用户访问 LoginAction 的 login 方法里,会按照以上的顺序执行校验规则,实际的校验规则是以上四个校验规则的总和,但是如果存在冲突的情况下,后面的校验规则优先。
6 ,非字段校验器的配置
Struts2 中除了有象我们的配置文件的那种以字段为基础的校验文件的配置外,还有另外一种以校验规则为基础的配置,请看下面的配置文件的代码:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<!-- 配置指定必填字符串的校验器 -->
<validator type="requiredstring">
<!-- 要校验的属性为name -->
<param name="fieldName">name</param>
<!-- 其它参数 -->
<param name="trim">true</param>
<!-- 返回的提示 -->
<message>${getText("name.requried")}</message>
</validator>
<validator type="regex">
<param name="fieldName">name</param>
<param name="trim">true</param>
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>${getText("name.regex")}</message>
</validator>
<validator type="requiredstring">
<param name="fieldName">pass</param>
<param name="trim">true</param>
<message>${getText("pass.requried")}</message>
</validator>
<validator type="regex">
<param name="fieldName">pass</param>
<param name="trim">true</param>
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>${getText("pass.regex")}</message>
</validator>
<validator type="int">
<param name="fieldName">age</param>
<param name="min">1</param>
<param name="max">150</param>
<message>${getText("age.range")}</message>
</validator>
<validator type="date">
<param name="fieldName">birth</param>
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>${getText("birth.range")}</message>
</validator>
</validators>
7 ,短路校验器的配置
Struts2 默认的校验配置是非短路的方式,即把一个字段所有的不符合要求的提示都提示用户,我们也可以配置以短路的方式提示用户,即当用户输入的条件不满足第一次校验的时候就返回提示信息,不再往下执行。这种配置方式只能是以字段为基础的校验器 。只需要在 <field-validator> 元素上加上 short-circuit="true" 即可,例如:
<field name="name">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message>${getText("name.requried")}</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,25})]]></param>
<message>${getText("name.regex")}</message>
</field-validator>
</field>