ssh之struts学习笔记(三)输入校验

来源:互联网 发布:龙卷风网络加速器 编辑:程序博客网 时间:2024/05/16 15:07

 

Struts2提供的输入校验有两种方式,一种是硬编码的方式,一种是采用Struts2的输入校验框架进行校验,即采用XML配置的方式进行校验。

对硬编码来说

举例说明:需要对一个用户注册的数据进行校验

1WebRoot下面创建一个register.jsp 页面,代码

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>register page</title>

    

  </head>

  <body>

    <form action="register.action" method="post">

        <font color="red" size="2"><s:fielderror /></font>

        <table border="1"  cellpadding="0" cellspacing="0" width="500">

            <tr>

                <td colspan="2"> 用户注册</td>

            </tr>

            <tr>

                <td width="100">username</td>

                <td><input type="text" name="username" value="${requestScope.username }"/>6-10 cahr</td>

            </tr>

            <tr>

                <td>password</td>

                <td><input type="password" name="password" value="${requestScope.password }"/></td>

            </tr>

            <tr>

                <td>re-password</td>

                <td><input type="password" name="repassword"  value="${requestScope.repassword }"/></td>

            </tr>

            <tr>

                <td>age</td>

                <td><input type="text" name="age"  value="${requestScope.age }"/>0-150</td>

            </tr>

            <tr>

                <td>birthday</td>

                <td><input type="text" name="birthday"  value="${requestScope.birthday }"/>must be date</td>

            </tr>

            <tr>

                <td>graduation</td>

                <td><input type="text" name="graduation"  value="${requestScope.graduation }/>must after birthday</td>

            </tr>

            <tr>

                <td></td>

                <td><input type="submit" value="register"/></td>

            </tr>

        </table>

    </form>

  </body>

</html>

上面一个表单使用HTML描述表单内容。显示如:

 

校验需要,username: 不能为空  必须是6-10个字符

          password repassword不能为空  必须是6-10个字符,而且两次输入密码要一致

                   age 必须是0-150数字

                   birthday graduation  都必须是日期,且出生日期要大于毕业日期

12下面创建一个RegisterAction 来处理用户注册数据代码如下:

package com.snt.struts2.action;

import java.util.Calendar;

import java.util.Date;

 

import com.opensymphony.xwork2.ActionSupport;

 

public class RegisterAction extends ActionSupport {

         private String username;

         private String password;

         private String repassword;

         private int age;

         private Date birthday;

         private Date graduation;

        省略gettersetter

         

         @Override

         public String execute() throws Exception {

                   return SUCCESS;

         }

         

         

         /***

          * 当遇到类型转化时,struts2自动生成一条错误信息,放到

          * fielderrors 

          */

         @Override

         public void validate() {

                   //当用户直接访问action,action的属性都是null

                   //防止NullPointException

                   System.out.println("validate()...........");

if(null==username || username.length()<6 || username.length()>10){

                            this.addFieldError("username", "username is invalid");

}

if(null==password ||  password.length()<6 || password.length()>10){                     this.addFieldError("password", "password is invalid!");

}else if(null==repassword ||  repassword.length()<6 || repassword.length()>10){

                            this.addFieldError("password", "password is invalid!");    

}else if(!password.equals(repassword)){

                            this.addFieldError("password", "tow password is not be same!");

}

if(age<0 || age>150){

                            this.addFieldError("age", "age is invalid!");

}

if(null==birthday){

                            this.addFieldError("birthday", "birthday invalid!");

}

if(null==graduation){

                            this.addFieldError("graduation", "graduation  invalid!");

}

                   if(null!=birthday && null!=graduation){

                            Calendar c1=Calendar.getInstance();

                            c1.setTime(birthday);

                            Calendar c2=Calendar.getInstance();

                            c2.setTime(graduation);

                            if(!c1.before(c2)){

                                     this.addFieldError("birthday","birthday shoud before graduation!");

                            }

                   }

         }

}

红色的是检验的代码,我创建的Action继承了ActionSupport类,ActionSupport 双继承了Validateable ValidationAware 接口,validate()Validateable接口中的方法,我们继承Validateable 接口,实现validate()就可以在调用Actionexecute()方法之前,执行validate()方法进行数据检验。根据的我们的检验逻辑如果某个属性出错了,会产生一个相应的错误信息,以属性名为Key,以错误信息为值,形成一个键值对通过addFieldError()方法放在一个保存错误信息的Map 

13struts.xml 文件本配置RegisterAction 如下:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

   <struts>

        <constant name="struts.custom.i18n.resources" value="message" />

        <package name="struts2" extends="struts-default">

            <action name="register" 

class="com.snt.struts2.action.RegisterAction">

                <result name="success">/success.jsp</result>

                <result name="input">/register2.jsp</result>

            </action>

        </package>

   </struts> 

   

运行应用测试:

 

OK,验证信息成功,但是我们发现错误信息中出现一些我们没有见过的信息,

比如:Invalid field value for field "birthday". 这样的信息,这是由Struts2自身的校验给出来的信息,默认的情况下,如果遇到类型转化失败的问题,struts2会自动添加一条错误信息,使用addFieldError()添加一条错误信息。但是这样的信息并不是我们想要的,因为这些信并不友好,我们又不好控制,所有我们要想办法取消这些信息,但是这些是信息是struts2自身的一些拦截器实现的功能,又不容易取掉(应该可以去掉,可以找到这个拦截器,重写它去掉这部分功能,自己再组织拦截器栈),所以考虑将其替换掉;因此Struts2提供一此替换这些信息的方法:可以通过替换国际化资源配置文件,来达到目的,具体做法:

[1]strrts.xml 配置中指定国际化资源文件常量

<package >标签下加一条

   <constant name="struts.custom.i18n.resources" value="message" />

Name代表常量名,固定的;value代表指定的资源配置文件

这样配置会覆盖default.properties struts2的配置常量

[2]classes 目录下,创建工程时可以在src目录下创建一个message.properties 文件,文件名要和上面的vlaue值对应,这个文件是全局的配置,输入内容如下:

xwork.default.invalid.fieldvalue={0} error

等号左边的是固定不变的,右边是{0}一个占位符,将来会被错误的字段名替换;

         也是当一个字段发生错误了,比如:age转化时错了,就会显示age error 的信息 

运行测试,这样显示就友好一点了!如下显示:

 

但是还存在一些问题,信息出错时,错误信息显示太死板了,我们想给一些字段加上个性化的信息。Struts2也提供对应的方法:

[1]在需要输入校验的Action同目标下,创建一个与Action同名的资源文件,比如:RegisterAction.properties这个文件将成功局部的资源配置文件,它里面的配置可以替换全局的配置;输入以下内容

invalid.fieldvalue.age=/u5e74/u9f84/u8f93/u5165/u4fe1/u606f/u4e0d/u6b63/u786e

invalid.fieldvalue.birthday=/u65e5/u671f/u8f93/u5165/u9519/u8bef

invalid.fieldvalue.graduation=/u6bd5/u4e1a/u65f6/u95f4/u65e5/u671f/u8f93/u5165/u4e0d/u6b63/u786e

这样的信息,注意等号左边的invalid.fieldvalue 是固定的,之后跟的是字段名;右边是要显示的错误信息这样运行即可以显示友好的中文信息:

 

 

回显表单数据,排除信息重复显示

OK,上面的基本的输入校验已经完成,当然还存在一些问题,比如:错误信息提示还是有重复的,当数据错误时不能回显,这都是一些不友好的做法!我们下面一步步完善!

为了添加回显的功能,我用采用Struts2标签库来很容易地实现!当然使用HTML,通过JSPEL表达式也可以实现回显,上面写过了,介这种做法并不好,显示过程中可能会出现问题,特别是日期显示那块!

下面我们采用struts2的标签库来重构页面:

创建一个register2.jsp  页面,导入struts2的标签库,代码如下:

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>register page</title>

    <meta http-equiv="pragma" content="no-cache">

    <meta http-equiv="cache-control" content="no-cache">

    <meta http-equiv="expires" content="0">    

    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

    <meta http-equiv="description" content="This is my page">

  </head>

  <!-- 回显 -->

  <body>

    <s:actionerror cssStyle="color:red;"/>

    <hr>

    <s:fielderror cssStyle="color:red;"/>

    <s:form action="register2" theme="simple">

    <table border="1" cellpadding="0" cellspacing="0">

        <tr>

            <td>username</td>

            <td><s:textfield name="username"  label="usernmae"/></td>

        </tr>

        <tr>

            <td>password</td>

            <td><s:password name="password" label="password"/></td>

        </tr>

        <tr>

            <td>repassword</td>

            <td><s:password name="repassword" label="repassword" /></td>

        </tr>

        <tr>

            <td>age</td>

            <td><s:textfield  name="age" label="age"/></td>

        </tr>

        <tr>

            <td>birthday</td>

            <td><s:textfield name="birthday" label="birthday"/></td>

        </tr>

        <tr>

            <td>graduation</td>

            <td><s:textfield name="graduation" label="graduation"/></td>

        </tr>

        <tr>

            <td> </td>

            <td><s:submit /></td>

        </tr>

    </table>

    </s:form>

  </body>

</html>

上面我们采用了表格布局,当然如果不采用表格的话,struts2在翻译struts2标签是,会为每个标签添加一个单元格将控件括起来。这是struts表单默认的显示样式。

显示如下:

 

运行测试仪可以正常回显数据

 

错误级别

上面我们提到过,错误信息的级别,其实Struts2中的错误有两种级别:

1   Action级别的错误

2   Field 级别的错误

Struts2只有判断到两种错误级别的信息都没有的情况,才认为是输入校验通过。

查看VlidationAwareSupport 类的原代码:高亮显示的一句代码,可以确定struts2是这样做的。

public synchronized boolean hasActionErrors() {

        return (actionErrors != null) && !actionErrors.isEmpty();

    }

    public synchronized boolean hasActionMessages() {

        return (actionMessages != null) && !actionMessages.isEmpty();

    }

    public synchronized boolean hasErrors() {

        return (hasActionErrors() || hasFieldErrors());

    }

    public synchronized boolean hasFieldErrors() {

        return (fieldErrors != null) && !fieldErrors.isEmpty();

    }

下面我们重写一下validate()方法,将所有添加addFieldError() 的信息,转化成addActionError();

如下:

public void validateExecute() {

                   //当用户直接访问action,action的属性都是null

                   //防止NullPointException

                   System.out.println("validate()...........");

                   

                   if(null==username || username.length()<6 || username.length()>10){

                            this.addActionError("username invalid!");

                   }

                   if(null==password ||  password.length()<6 || password.length()>10){

                            this.addActionError("password is invalid!");

                   }else if(null==repassword ||  repassword.length()<6 || repassword.length()>10){

                            this.addActionError("password is invalid!");

                   }else if(!password.equals(repassword)){

                            this.addActionError( "tow password is not be same!");

                   }

                   

                   if(age<=0 || age>150){

                            System.out.println("ERROR");

                            this.addActionError( "age is invalid!");

                   }

                   if(null!=birthday && null!=graduation){

                            Calendar c1=Calendar.getInstance();

                            c1.setTime(birthday);

                            Calendar c2=Calendar.getInstance();

                            c2.setTime(graduation);

                            if(!c1.before(c2)){

                                     this.addActionError("birthday shoud before graduation!");

                            }

                   }

再将运行界面时,我们发现数据校验明明是错误的却不会显示错误信息;这是因为Struts2标签默认只会显示Field级别的错误信息。要想显示Action级别的信息,需要在表单一加上一句;

<s:actionerror cssStyle="color:red;"/>

多方法情况下输入校验

OK,上面讲的都是针对Actionexecute()方法之前的验证,我们知道struts2中也提供了一个Action中多个方法,处理多种请求的机制。可能通过,struts.xml 配置action中,加一个method属性来实现!如:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

   <struts>

        <constant name="struts.custom.i18n.resources" value="message" />

        <package name="struts2" extends="struts-default">

            <action name="register1" class="com.snt.struts2.action.RegisterAction" method="register">

                <result name="success">/success.jsp</result>

                <result name="input">/register.jsp</result>

            </action>

            <action name="register2" 

class="com.snt.struts2.action.RegisterAction">

                <result name="success">/success.jsp</result>

                <result name="input">/register2.jsp</result>

            </action>

        </package>

   </struts> 

这样配置是可以的,使用register1 的请求会调用Action中的register()方法;

使用regiser2的请求会调用Acrtion中的execute()方法。

但这时输入校验如何处理呢?Struts2是这样处理的:

对于execute()方法,它会执行validate()方法进行输入校验,对于register()它会调用validateRegiser()方法进行输入校验,但是对于register()的情况比较特别,它调用validateRegister()方法后,它还会调用validate()方法。也是就说validate()方法总会被调用的!对于这种情况呢,当然是对我们输入校验会产生干扰的!~

如何处理这样的问题呢?提供以下解决方案:

1   空实现valiate()方法,但是这样有问题,如何校验execute()方法呢?可以选择不用execute()方法

2   不提供validate()方法,也就是空实现,但要提供一个validateExecute()方法来校验execute()方法!

 

1.1采用Struts2的检验框架需要创建一个配置文件,规则如下,我们需要在与所有要进行校验的Action同级别目录下创建一个xml文件,命名必须遵守规则:Action-validation.xml 文件,对于这个例子就是:RegisterAction-validation.xml 做为校验的配置文件,下面我创建这个文件:代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC

        "-//OpenSymphony Group//XWork Validator 1.0.2//EN"

        "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

<validators>

    <field name="username">

        <field-validator type="requiredstring" short-circuit="false">

            <param name="trim">true</param>

            <message>username shoudld not be blank!</message>

        </field-validator>

        <field-validator type="stringlength">

            <param name="minLength">6</param>

            <param name="maxLength">10</param>

            <message>username should be between ${minLength} and ${maxLength}</message>

        </field-validator>

    </field>

    

    <field name="password">

        <field-validator type="requiredstring">

            <message>password should not be balank!</message>

        </field-validator>

        <field-validator type="stringlength">

            <param name="minLength">6</param>

            <param name="maxLength">10</param>

            <message>password should be between ${minLength} and ${maxLength}</message>

        </field-validator>

    </field>

    

    <field name="repassword">

        <field-validator type="requiredstring">

            <message>repassword should not be balank!</message>

        </field-validator>

        <field-validator type="stringlength">

            <param name="minLength">6</param>

            <param name="maxLength">10</param>

            <message>repassword should be between ${minLength} and ${maxLength}</message>

        </field-validator>

    </field>

    

    <field name="repassword"> 

        <field-validator type="fieldexpression"> 

            <param name="expression"> <![CDATA[(password==repassword)]]> 

            </param> 

            <message>two password should be the same! </message> 

        </field-validator> 

    </field> 

        

    <field name="age">

        <field-validator type="int">

            <param name="min">1</param>

            <param name="max">150</param>

            <message>age should be between ${min} and ${max}</message>

        </field-validator>

    </field>

    

    <field name="birthday">

        <field-validator type="required">

            <message>birthday should not be blank!</message>

        </field-validator>

        <field-validator type="date">

            <param name="min">2001-01-01</param>

            <param name="max">2004-01-01</param>

            <message>birthday should be between ${min} and ${max}</message>

        </field-validator>

    </field>

    

    <field name="graduation">

        <field-validator type="required">

            <message>graduation should not be blank!</message>

        </field-validator>

        <field-validator type="date">

            <param name="min">2005-01-01</param>

            <param name="max">2008-01-01</param>

            <message>graduationshould be between ${min} and ${max}</message>

        </field-validator>

        

    </field>

</validators>

对于Struts2提供的校验方式有两种:字段校验   2 非字段校验 

针对字段校验就如上面xml文件所写,是针对字段,字段中再配置各种校验规则。

 

先用<field>标签描述要校验的字段,里面定义校验器,使用<field-vaidator>标签,这个标签中有个type 属性,这个属性指是就是校验规则,比如:requiredstring  就代表必填表的字符串,表明这个信息是用户必须输入的。需要注意的是type属性不是随便写的,这个名字会对应struts2 提供的各样校验器类。我们查找strust2 原代码会在xwork jar包中的 com.opensymphony.xwork2.validator.validators包下面找到一个default.xml 配置文件

上面说过了,字段校验有两种,一种是上面所说的字段校验,另一种是非字段校验,下面我们看一下:

针对username 的非字段校验配置如下:

         <validator type="requiredstring">

        <param name="fieldName">username</param>

        <message>username should not be blank</message>

    </validator>

    

    <validator type="stringlength">

        <param name="fieldName">username</param>

        <param name="minLength">6</param>

        <param name="maxLength">10</param>

        <message>username should  be between ${minLength} and 

${maxLength}</message>

    </validator>

看上面的配置,先定义一个校验器,使用<validator>标签,然后在标签里配置的参数

<param name="fieldName">username</param>

name 属性是不变的,使用fieldName 代表字段名,标签中间的值代表要校验的字段,下面的<message>标签中信息是校验失败后要显示的信息。其实非字段校验和这字段校验没什么区别,只是配置文件不一样而已,建议使用字段校验,会更清晰一点!

 

1-2OK这样配置,整个配置文件都可以生产了,运行测试应用,显示如下:

OK,校验测试成功。

 

另外在校验过程中还要注意一些问题:

多方法Action情况如何使用配置文件进行校验?

我们知道大多数据情况下,Action可能会有多个方法,面我们上面所说的都是针对execute()方法进行的校验,如果存在多方法的情况下,需要进行校验的信息肯定是不样的,一个配置文件肯定解决不了问题,所有在多方式需要校验的情况下,我们需要在Action同级别的目录下,创建命名规则如下的配置文件:ActionName-method-validation.xml 配置文件,比如:RegisterAction中有个test()方法需要校验,可以创建

RegisterAction-test-validation.xml 配置文件进行配置,这个文件就会针对tets()方法进行校验,但是需要注意的是:在调用test()方法时,使用RegisterAction-test-vaidation.xml  文件进行校验后,还会调用RegisterAction-vaidation.xml 文件进行校验,这样的话,肯定会产生干扰,为了解决这样问题,可以在开发过程中,不提供RegisterAction-validtion.xml 这样的文件,对于execute()方法,可以提供一个RegisterAction-execute-validation.xml 文件进行配置校验。

 XML方式校验与硬编码方式校验的选择|

我们采用了XML 配置文件的方式进行校验,介是Action中的validate()方法同时也会被执行的,这时一些校验就可能会重复!所以在开发过程中,我们只采用一种方式,要么使用XML方式进行校验,要么采用硬编码的方式进行校验,而不建议混合使用的方式;一般情况下,我们采用XML方式进行校验,而且XML方式可以满足我们的需求,在业务特别复杂或校验粒度比较细的情况下我们可以采用硬编码的方式校验。

 

1Struts2 XML配置方式进行是服务器端校验,当然在开发过程中我们经常会需要客户端校验,Struts2也提供了客户端校验功能,使用客户端校验,首先页面中Struts2 标签的主题不能设为simple主题,另外form标签的validate 属性要改为true。但是Struts2提供的这种客户端校验功能是非常有限的,所有在需要使用客户端校验的情况,可以采用javascript Ajax的方式进行校验,会更灵活一点。

原创粉丝点击