struts2 输入校验 validate

来源:互联网 发布:kingkong1024控台编程 编辑:程序博客网 时间:2024/06/05 11:41

原文地址:http://blog.csdn.net/yaosan109901/article/details/4481378

1,输入校验介绍

Struts2提供了功能强大的输入校验机制,通过Struts2内建的输入校验器,应用无需书写任何代码,即可完成大部分的校验功能,并可以同时完成客户端和服务器端的校验。如果应用的输入校验规则特别,Struts2也允许通过重写validate方法来完成自定义校验,另外Struts2的开放性还允许开发者提供自定义的校验器。

表现层的数据处理包括两个方面:一是数据类型的转化,因为Web应用接收到的所有数据都是字符串类型的;另一个就是输入校验,因为开发者必须全面考虑用户输入的各种情况,尤其需要注意那些非正常输入。

客户端的校验最基础的方法就是在页面写javascript代码手工校验,服务器端的校验最基础的方法就是在处理请求的Servlet的service()方法中添加校验代码。

Struts2中可以通过重写validate方法来完成输入校验。如果我们重写了validate方法,则该方法会应用于此Action中的所有提供服务的业务方法。Struts2支持校验特定方法的validateXxx()方法。例如某个Action中有一个regist()业务方法,我们可以写一个validateRegist()方法来进行regist()的特殊校验,客户端请求调用的次序如下:validateRegist()--------------->validate()-------------->regist()

-----begin相比原作者,此处新加以下内容

      平时开发过程中,SSH 项目,服务端我多使用Struts2的validate方法来完成输入校验,一般来说Action A中会有一个save()方法

在save方法执行之前,采用validateSave()方法进行输入校验(即validateXxx()方法,其中‘Xxx'指得是,你要进行输入校验的方法名,首字母大写,本例为Save)

当多个Action类B,C,D同时继承Action A 时,B,C,D里面若同时有save()方法,那么A 的validateSave()方法会帮助B,C,D完成一些共有的输入校验。

-----end

Struts2的输入校验流程如下:

1,类型转换器负责对字符串的请求参数执行类型转换,并将这此值设置成Action的属性值。

2,在执行类型转换过程中可能出现异常,如果出现异常,将异常信息保存到ActionContext中,conversionError拦截器负责将其封装到fieldError里,然后执行第3步;如果转换过程没有异常信息,则直接进入第3步。

3,通过反射调用validateXxx()方法,其中Xxx是即将处理用户请求的处理逻辑所对应的方法名。

4,调用Action类里的validate()方法。

5,如果经过上面4步都没有出现fieldError,将调用Action里处理用户请求的处理方法;如果出现了fieldError,系统将转入input逻辑视图所指定的视图资源。

2,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-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" onsubmit="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>

这种方式可能会造成多次提示用户,所以并不推荐使用此方式,并且客户端校验并不支持这种方式。并且采用这种方式之后,校验的顺序将很难控制(主要是按照规则来进行控制,但此时将花费大量时间)。

3,Struts2的内建校验器的介绍

Struts2已经为我们准备了一些内建校验器,我们可以直接使用它们,可以打开Struts2的lib包下的xwork.jar包,在com/opensymphony/xwork2/validator/validators/default.xml文件中,我们可以看到Struts2的内建校验器。我们也可以开发自己的校验器。方法如下:添加一个validators.xml文件在WEB/INF/classes目录下,validators.xml文件中的配置则同刚才说的Struts2的内建校验器的配置相同。再开发出自己的校验器类,在validators.xml中注册就可以了。如果在WEB-INF/classes目录添加了文件validators.xml文件,则Struts2不会再应用默认的校验器,因此这时需要将default.xml文件中的所有校验器都复制到validators.xml文件中。

从Struts2的配置文件中可以看到Struts2有如下内建校验器:

1,required 必填校验器,要求字段必须有值

2,requiredstring 必填字符串校验器,要求必须有值且长度大于0,即不能是空字符串。默认会去掉字符串前后空格

3,int 整数校验器,可以配置整数在指定的范围内

4,double 双精度校验器,可以配置双精度数在指定的范围内

5,date 日期校验器,可以配置日期在指定的范围内

6,expression 表达式校验器,它是一个非字段校验器,当参数expression计算的值为true时,校验通过,否则返回提示。

7,fieldexpression 字段表达式校验器,当参数expression计算的值为true时,校验通过,否则返回提示。它和6一样多用于在用户的两次输入中间进行判断,如下例:

<!-- 要校验的属性为rpass -->
    <field name="rpass">
    <!-- 使用fieldexpression校验器 -->
        <field-validator type="fieldexpression">
        <param name="expression"><![CDATA[(rpass == password)]]></param>
            <message>两次密码不相同!</message>
        </field-validator>
    </field>

7,email 邮件地址校验器,要求被检查的字段如果非空,则必须是合法的邮件地址。

8,url 网址校验器,要求被检查的字段如果非空,则必须是合法的URL地址。7和8都是基于正则表达式来计算的,可能会随着技术的进步而不同,用户可以自己扩展。

9,visitor Visitor校验器,用于检测Action里的复合属性。例如:RegistAction中包含了一个User属性,那么要校验User里的属性就要使用Visitor校验器,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>
<!-- 指定校验user属性 -->
<field name="user">
   <!-- 使用visitor校验器 -->
   <field-validator type="visitor">
    <!-- 指定校验规则文件的context -->
    <param name="context">userContext</param>
    <!-- 指定校验失败后的提示信息是否添加下面的前缀 -->
    <param name="appendPrefix">true</param>
    <!-- 指定校验失败的提示信息的前缀 -->
    <message>用户的:</message>
   </field-validator>
</field>

</validators>

还要另外再为User属性配置单独的校验文件,默认的文件名应为User-validation.xml,因为刚在在RegistAction-validation.xml文件中指定了visitor的context属性为userContext,因此校验文件名应为:User-userContext-validation.xml,该文件同一般的校验文件一样,代码如下:

<?xml version="1.0" encoding="GBK"?>

<!DOCTYPE validators PUBLIC
   "-//OpenSymphony Group//XWork Validator 1.0//EN"
   "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
  
<validators>
<field name="name">
   <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="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">
   <field-validator type="int">
    <param name="min">1</param>
    <param name="max">150</param>
    <message>年纪必须在1到150之间</message>
   </field-validator>
    </field>
<field name="birth">
   <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>

当然这时候的JSP页面中也与之前的不一样,它要把页面属性直接赋值给Action中的User中的属性,这在之前的几课中已经有过说明,页面代码如下:

<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>

<html>

<head>

<title>请输入您的注册信息</title>

</head>


<body>
<H1>请输入您的注册信息</H1>
<s:fielderror/>
<FORM METHOD="POST" ACTION="regist.action">
用户名:<INPUT TYPE="text" NAME="user.name"><br>
密&nbsp;&nbsp;码:<INPUT TYPE="text" NAME="user.pass"><br>
年&nbsp;&nbsp;龄:<INPUT TYPE="text" NAME="user.age"><br>
生&nbsp;&nbsp;日:<INPUT TYPE="text" NAME="user.birth"><p>
<INPUT TYPE="submit" value="注册">
</FORM>
</body>

</html>

10,conversion 转换校验器,它检查被校验字段在类型转换过程中是否出现错误。例子如下:

<field name="age">
   <field-validator type="int">
    <param name="min">1</param>
    <param name="max">150</param>
    <message>年纪必须在1到150之间</message>
   </field-validator>
   <field-validator type="conversion">
    <!-- 指定类型转换失败后,返回输入页面依然保留原来的错误输入 -->
    <param name="repopulateField">true</param>
    <!-- 转换失败后的提示信息 -->
    <message>你的年龄必须是一个整数</message>
   </field-validator>

    </field>

11,stringlength 字符串长度校验器,它要求被校验的字段长度必须在指定的范围内,否则校验失败。例:

<field name="pass">
   <field-validator type="stringlength">
    <param name="minLength">4</param>
    <param name="maxLength">10</param>
    <message>长度必须在4-10之间</message>
   </field-validator>

</field>

12,regex 正则表达式校验器,它检查被校验的字段是否匹配指定的正则表达式,例:

<field name="pass">
   <field-validator type="regex">
   <param name="expression"><![CDATA[(/w{4,25})]]></param>
    <message>您输入的密码只能是字母和数组,且长度必须在4到25之间</message>
   </field-validator>
</field>

0 0
原创粉丝点击