Struts2之-数据校验详解

客户端校验和服务器端校验

数据的输入校验分为客户端校验和服务器端校验,客户端校验主要是过滤正常用户的误操作,主要通过JavaScript代码完成;服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现。

客户端校验

客户端校验的步骤一般通过JavaScript实现,来过滤常见的错误操作和用户的误操作,步骤如下:
1、编写校验函数;
2、在提交表单的事件中调用校验函数;
3、根据校验函数来判断是否进行表单提交;

一个简单的客户端校验案例

<%--
  Created by IntelliJ IDEA.
  User: mairr
  Date: 17-12-5
  Time: 下午10:07
  To change this template use File | Settings | File Templates.
--%>


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page language = "java" import = "java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>


<html>
  <head>
    <title>注册界面</title>
    <script type="text/javascript" >

        // 去掉前后的空格
      function deltrim(x) {
          while (x.length > 0 && x.charAt(0) == ' ')
              x = x.substring(1, x.length);
          while (x.length > 0 && x.charAt(x.length - 1) == ' ')
              x = x.substring(0, x.length - 1);
          return x;
      }

        // 非空验证
      function isNULL(elem,message){
          var va = deltrim(elem.value);
          if(va == " ") {
              alert(message);
              elem.focus();
              return false;
          }
          return true;
          }

          // 验证帐号,帐号只能是小写字母数字,并且只能以字母开头
      function validateId(){
          var first = document.forms[0].id.value.charAt(0);
          var exp = /^[a-z0-9]+$/;
          if(isNULL(document.forms[0].id,"请输入帐号")){     // 验证非空
              // 验证首字符
              if((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')){}
              else{
                  alert("帐号首字符必须是字母!");
                  document.forms[0].id.focus();
                  return false;
              }
              if(!exp.test(document.forms[0].id.value)){
                  alert("帐号必须是字母或者数字!");
                  document.forms[0].id.focus();
                  return false;
              }
              return true;
          }
          else{
              return false;
          }
      }


      // 验证密码,密码要在8位以上,且需要有字母或者数字之外的字符
      function validatepwd(){
          var exp = /^[a-z0-9]+$/;
          if(isNULL(document.forms[0].pwd," 请输入密码")){   //验证非空
              if(document.forms[0].pwd.value.length <= 8){
                  alert("密码大于8位");
                  document.forms[0].pwd.focus();
                  return false;
              }else{
                  if(exp.test(document.forms[0].pwd.value)){
                      alert("密码要有字母和数字之外的字符!");
                      document.forms[0].pwd.focus();
                      return false;
                  }
              }
          }else{
              return false;
          }
          if(document.forms[0].pwd.value != document.forms[0].repwd.value)
          {
              alert("两次密码不一样!");
              document.forms[0].pwd.focus();
              return false;
          }
          return true;
          }


          // 验证邮箱,右边为六位数子
          function checkcode() {
              var exp = /^[0-9]+$/;
              if(isNULL(document.forms[0].ecode,"请输入邮编")){    // 验证非空
                  if(document.forms[0].ecode.value.length != 6){
                      alert("邮编为6位");
                      document.forms[0].ecode.focus();
                      return false;
                  }else{
                      if(!exp.test(document.forms[0].ecode.value)){
                          alert("邮编为数字");
                          document.forms[0].ecode.focus();
                          return false;
                      }
                  }
                  return true;
              }else{
                  return false;
              }
          }


          // 验证E-mail的基本格式
          function checkEmail(){
              var exp = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
              if(isNULL(document.forms[0].email,"请输入Email")){     // 验证非空
                  if(!exp.test(document.forms[0].email.value)){
                      alert("Email格式错误");
                      document.forms[0].email.focus();
                      return false;
                  }
                  return true;
              }else{
                  return false;
              }
          }


          // 提交按钮
        function gogo(){
              if(validateId() && validatepwd() && checkcode() && checkEmail()){
                  document.forms[0].submit();
                  return true;
              }
              return false;
        }
    </script>
  </head>


  <body>
     <s:form action ="" theme="simple">
        <table>
          <tr>
            <td>登录帐号</td>
            <td><s:textfield name="id"/></td>
          </tr>
          <tr>
            <td>密码</td>
            <td><s:password name="pwd"/></td>
          </tr>
          <tr>
            <td>确认密码</td>
            <td><s:password name="repwd"/></td>
          </tr>
          <tr>
            <td>邮编</td>
            <td><s:textfield name = "ecode"/></td>
          </tr>
          <tr>
            <td>Mail</td>
            <td><s:textfield name = "email"/></td>
          </tr>
          <tr>
            <td><input type="button" value="提交" onclick="return gogo()" /></td>
            <td><s:reset value = "重置"/></td>
          </tr>
        </table>
     </s:form>
  </body>


</html>

通过点击button触发校验方法,校验通过提交表单,否则不提交并提示错误

服务器端校验

服务器对于系统的安全性、完整性、健壮性起到至关重要的作用。Struts2框架提供了一套验证框架,通过验证框架能够非常简单和快速地完成输入校验。

在服务器端,对于输入校验Struts2提供了两种实现方法:一是采用手工编写代码实现;另外一种是,给予XML配置方式的实现(校验框架校验)。接下来详细介绍这两种方法。

手动实现数据校验

手动编程校验主要是通过在类中编写校验逻辑代码,有两种方式i:一是在Action类中重写validate()方法;二是在Action类中重写validateXxx()方法,Xxx是方法名,第一个字母大写。

重写validate方法实现校验

validate()方法会校验Action中所有与execute()方法签名相同的方法。当某个数据校验失败时,在validate()方法中应该调用addFiledError()方法向系统fieldErrors添加校验失败信息。为了使用addFileError方法,Action类需要继承ActionSupport。

如果系统的fieldErrors包含失败信息,Struts2会将请求转发到名为input的result。在input视图中可以通过标签失败信息。

示例如下:
validate.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>数据校验测试</title>
<style type="text/css">
form {
    width: 300px;
    margin: 0 auto;
    margin-top: 0px;
    margin-top: 40px;
}
</style>
</head>
<body>
    <s:form action="validate" theme="simple" namespace="/">
        <table>
            <tr> 
                <td>登录帐号</td>
                <td><s:textfield name="id" /></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><s:password name="pwd" /></td>
            </tr>
            <tr>
                <td>确认密码</td>
                <td><s:password name="repwd" /></td>
            </tr>

            <tr>
                <td><input type="submit" value="提交"s /></td>
                <td><s:reset value="重置" /></td>
            </tr>
        </table>
         <!--显示this.addFieldError("id","id不能为空")的信息-->
        <s:fielderror fieldName="id"/>

        <!--显示所有校验失败信息-->
        <s:fielderror/>
    </s:form>
    <br>

    <s:debug></s:debug>
</body>
</html>

struts.xml


<!-- 数据校验 --> <action name="validate" class="action.ValidateAction" method="login"> <result name="input">validate.jsp</result> <result name="success">/success.jsp</result> </action>

ValidateAction.java

/**
 * 
 */
package action;

import com.opensymphony.xwork2.ActionSupport;


/**
 * @author Administrator
 *
 */
public class ValidateAction extends ActionSupport{
    private String id;
    private String pwd;


    private String repwd;


    public String login() throws Exception {
    return SUCCESS;
    }
    public void validate() {
    System.out.println("重写validate方法校验");
    if (id == null || id.trim().equals("")) {
            this.addFieldError("id", "id不能为空");
        }
        if (pwd == null || pwd.trim().equals("")) {
            this.addFieldError("pwd", "密码不能为空");
        } else {
            if (pwd.length() < 6 || pwd.length() > 12) {
                this.addFieldError("pwdlength", "密码的长度在6~12位之间");
            }
        }
        if (!pwd.equals(repwd)) {
            this.addFieldError("pwdsame", "两次密码不一致");
        }
    }

    /**
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the pwd
     */
    public String getPwd() {
        return pwd;
    }

    /**
     * @param pwd the pwd to set
     */
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    /**
     * @return the repwd
     */
    public String getRepwd() {
        return repwd;
    }

    /**
     * @param repwd the repwd to set
     */
    public void setRepwd(String repwd) {
        this.repwd = repwd;
    }
}

重写validateXxx()方法校验

将validate方法改为

public void validateLogin() {
    System.out.println("validateLogin方法的校验");
        if (id == null || id.trim().equals("")) {
            this.addFieldError("id", "id不能为空");
        }
        if (pwd == null || pwd.trim().equals("")) {
            this.addFieldError("pwd", "密码不能为空");
        } else {
            if (pwd.length() < 6 || pwd.length() > 12) {
                this.addFieldError("pwdlength", "密码的长度在6~12位之间");
            }
        }
        if (!pwd.equals(repwd)) {
            this.addFieldError("pwdsame", "两次密码不一致");
        }

validateXxx()只会校验Action中方法名为Xxx()的方法,其中Xxx的第一个字母要大写。重写validateXxx()方法进行输入校验与重写validate()方法基本一样,唯一不同的就是校验的方法名不同。

struts2的输入校验的流程

经过前面讲解,可以知道,Struts2输入校验需要经过一下几个步骤:

1、类型转器对请求参数执行类型转换,并且把转换后的值赋给Action中的属性。
2、如果在执行转换过程中出现了异常,系统会把异常信息保存到ActionContext , conversionError拦截器将异常信息添加到fieldError里。不管类型转换是否出现异常,都会进入步骤三;
3、系统通过反射技术先调用Action中的validateXxx()方法,Xxx为方法名字。
4、再调用Action中的validate()方法;
5、经过上面的4个步骤,如果系统中的fieldError存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fileError没有任何错误信息,系统将执行Action中的处理方法。
6、检查Action同目录下是否有校验文件,有的话进行相关校验处理,校验文件格式为Action类名-validation.xxml或者Action类名-action映射名-validation.xml(一个Action类对应多个Action时)

Struts2内置的校验器

Struts2框架提供的内置校验器如下:

1、required:必填校验器,要求field的值不能为null;
2、 requiredstring:必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串去掉前后空格;
3、 stringlength:字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败;minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去掉字符串前后空格;
4、regex:正则表达式校验器,检查被校验的field是否匹配一个正则表达式。expression参数指定正则表达式, caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true;
5、int:整数校验器,要求field的整数值必须在指定范围内,mini指定最小值,max最大值;
6、double:双精度浮点数校验器,要求field的双进度浮点数必须在指定范围内,mini指定最小值,max最大值;
7、fieldexpression:字段OGNL表达式校验器,要求field满足一个OGNL表达式,expression参数指定一个OGNL表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过。该校验器只能用于;
8、email:邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址;
9、url:网址校验器,要求如果field的值非空,则必须是合法的URL地址i;
10、date:日期校验器,要求field的日期值必须在指定的范围内,mini指定最小值,max指定最大值;
11、conversion:转换校验器,指定在类型转换失败时,提示错误信息;
12、visitor:用于校验Action中的复合属性,指定一个校验文件用于校验复合中的属性;
13、expression:OGNL表达式表达式校验,expression参数指定OGNL表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不用在字段校验器的配置中,只能用于.

内置校验器的配置

校验文件放在Action类的目录下,命名规则和Action的类名有关。
ActionName-validation.xml:其中ActionName就是需要校验的Action的类名。在struts.xml文件的Action定义中,需要定义input的逻辑视图名,将input逻辑视图映射到login.jsp页面。在这种校验方式下,无需书写校验代码,只需要通过配置文件指定校验规则即可,因此提供了更好的可维护性。当校验失败时,返回input结果。

ActionName-action-validation.xml:其中ActionName就是需要校验的Action的类名;action是action的映射名,也就是在struts.xml中配置的action名字,而不是action的方法。

校验文件的配置方法

配置文件有两种方法来校验:

  • 使用<validator>
  • 使用<field-validator>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>

    <!-- 方法一 -->
    <field name="id">
        <!-- <field-validator type="requiredstring"> <message>你的用户名必须存在</message> 
            </field-validator> -->
        <field-validator type="stringlength">
            <param name="minLength">6</param>
            <param name="maxLength">12</param>

            <message>你的用户名长度必须在4到20之间</message>
        </field-validator>
    </field>

    <!-- 方法二 -->
    <validator type="requiredstring">
        <param name="fieldName">id</param>
        <param name="fieldName">pwd</param>
        <message>用户名密码必须存在</message>
    </validator>

</validators>

<validator>配置一个校验规则,适用于多个属性,type是校验规则,参数fieldName是属性名,message是fieldError的值
<field name="属性名">下可以配置多个<field-validator>,即一个属性可以配置多个校验规则

我们一般将通用的校验规则使用<validator>配置,其他的用<field-validator>配置

校验文件使用实例如下

我们用的还是上面的哪个例子,只是将validate方法和validateXxx方法注释掉

ValidateAction-validate-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>

    <!-- 方法一 -->
    <field name="id">
        <!-- <field-validator type="requiredstring"> <message>你的用户名必须存在</message> 
            </field-validator> -->
        <field-validator type="stringlength">
            <param name="minLength">6</param>
            <param name="maxLength">12</param>

            <message>你的用户名长度必须在4到20之间</message>
        </field-validator>
    </field>
    <field name="repwd">
        <field-validator type="requiredstring">
            <message>确认密码必须存在</message>
        </field-validator>
        <field-validator type="fieldexpression">
            <param name="expression"><![CDATA[pwd==repwd]]></param>
            <message>密码不一致,请重新输入</message>
        </field-validator>
    </field>
    <!-- <field name="pwd"> <field-validator type="requiredstring"> <message>你的密码必须存在</message> 
        </field-validator> </field> -->

    <!-- 方法二 -->
    <validator type="requiredstring">
        <param name="fieldName">id</param>
        <param name="fieldName">pwd</param>
        <message>用户名密码必须存在</message>
    </validator>
    <!-- <validator type="fieldexpression"> <param name="fieldName">pwd</param> 
        <param name="expression"><![CDATA[(pwd==repwd)]]></param> <message>两个密码必须相同</message> 
        </validator> -->

</validators>

注意:
1、在使用时maxLength和minLength的L是大写的,小写会不起作用
2、校验文件的头部版本需要和你的xwork中的xwork-validator-1.0.3.dtd中的头部保持一致,不然由于版本问题可能不起作用
3、required和requiredstring的不同,require只要求有该属性不为空就可以了,但是表单不填的话会是空字符串,不是空,而requiredstring要求field的值不能为null,并且长度大于0,默认情况下会对字符串去掉前后空格,这就保证了表单必填的要求

效果如下:
《Struts2之-数据校验详解》

《Struts2之-数据校验详解》

常见的各种类型校验器配置

1、类型转换检验器:

(1)非字段校验:

    <validator type="conversion">

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

        <message>类型转换错误</message>

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

    </validator>

(2)字段校验:

    <field name="myField">

        <field-validator type="conversion">

            <message>类型转换错误</message>

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

        </field-validator>

    </field>
fieldName:该参数指定检查是否存在转换异常的字段名称,如果是字段校验,则不用指定该参数。
repopulateField:该参数指定当类型转换失败后,返回input页面时,类型转换失败的表单是否保留原来的错误输入。true为保留,false为不保留。

2、日期校验器:

(1)非字段校验:

    <validator type="date">

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

        <param name="min">1990-01-02</param>

        <param name="max">2010-07-28</param>

        <message>生日数据错误</message>

    </validator>

(2)字段校验:

    <field name="birthday">

        <field-validator type="date">

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

            <param name="max">2010-07-28</param>

            <message key="error.birthday"></message>

        </field-validator>

    </field>
min:指定字段日期值的最小值,该参数为可选参数。
max:指定字段日期值的最大值,该参数为可选参数。

3、浮点数值校验器:

(1)非字段校验:

    <validator type="double">

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

        <param name="minInclusive">20.1</param>

        <param name="maxInclusive">50.1</param>

        <message>生日数据错误</message>

    </validator>

(2)字段校验:

    <field name="percentage">

        <field-validator type="double">

            <param name="minInclusive">20.1</param>

            <param name="maxInclusive">50.1</param>

            <message key="error.percentage"></message>

        </field-validator>

    </field>
minInclusive|minExclusive:指定字段的最小值,包含该值|不包含该值。
maxInclusive|maxExclusive:指定字段的最大值, 包含该值|不包含该值。

4、邮件地址校验器:

(1)非字段校验:

    <validator type="email">

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

        <message>非法的邮件地址</message>

    </validator>

(2)字段校验:

    <field name="MyEmail">

        <field-validator type="email">

           <message>非法的邮件地址</message>

        </field-validator>

    </field>

5、表达式校验器:

    <validator type="expression">

        <param name="expression">.......</param>

        <message>Failed to meet Ognl Expression...</message>

    </validator>
expression:该参数为一个逻辑表达式,该参数使用OGNL表达式,并基于值栈计算,返回一个Boolean类型值。

6、字段表达式校验器:

(1)非字段校验:

    <validator type="fieldexpression">

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

        <param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>

        <message>My credit limit should be MORE than my girlfriend</message>

    </validator>

(2)字段校验:

    <field name="myField">

        <field-validator type="fieldexpression">

            <param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>

            <message>My credit limit should be MORE than my girlfriend</message>

        </field-validator>

    </field>

7、整数校验器:

(1)非字段校验:

    <validator type="int">

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

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

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

        <message>年龄必须在在${min}到${max}之间</message>

    </validator>

(2)字段校验:

    <field name="age">

        <field-validator type="int">

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

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

            <message>年龄必须在在${min}到${max}之间</message>

        </field-validator>

    </field>

8、正则表达式校验器:

(1)非字段校验:

    <validator type="regex">

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

        <param name="expression"><![CDATA[([aAbBcCdD][123][eEfFgG][456])]></param>

    </validator>

(2)字段校验:

    <field name="myStrangePostcode">

        <field-validator type="regex">

            <param name="expression"><![CDATA[#myCreditLimit > #myGirfriendCreditLimit]]></param>

            <message>My credit limit should be MORE than my girlfriend</message>

        </field-validator>

    </field>
expression:为必选参数,指定匹配有的表达式。
caseSensitive:指明进行匹配时,是否区分大小写,为可选参数,默认为true。

9、必填校验器:

(1)非字段校验:

    <validator type="required">

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

        <message>用户名不能为空</message>

    </validator>

(2)字段校验:

    <field name="username">

        <field-validator type="required">

            <message>用户名不能为空</message>

        </field-validator>

    </field>

10、必填字符串校验器:

(1)非字段校验:

    <validator type="requiredstring">

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

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

        <message>用户名不能为空</message>

    </validator>

(2)字段校验:

    <field name="username">

        <field-validator type="requiredstring">

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

            <message>用户名不能为空</message>

        </field-validator>

    </field>
trim:可选参数,用于指定是否在校验之前对字符串进行整理,默许为true。

11、字符串长度校验器:

(1)非字段校验:

    <validator type="stringlength">

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

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

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

        <message>用户名长度在${minLength}到${maxLength}之间</message>

    </validator>

(2)字段校验:

    <field name="username">

        <field-validator type="stringlength">

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

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

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

            <message key="error.length.username"></message>

        </field-validator>

    </field>

12、网址校验器:

(1)非字段校验:

    <validator type="url">

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

        <message>Invalid homepage url</message>

    </validator>

(2)字段校验:

    <field name="myHomePage">

        <field-validator type="url">

            <message>Invalid homepage url</message>

        </field-validator>

    </field>

13、visitor校验器:

该校验器名称为:visitor,用来校验Action中定义的复合类型属性,支持简单的复合类型、数组类型、Map等集合类型。

(1)非字段校验:

    <validator type="visitor">

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

        <param name="context">myContext</param>

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

    </validator>

(2)字段校验:

    <field name="user">

        <field-validator type="visitor">

            <param name="context">myContext</param>

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

        </field-validator>

    </field>

参考

JavaWeb框架Struts2(六)—–>Struts2的输入校验
细谈struts2(五)action基础知识和数据校验
Struts2内建校验器(基于校验框架的文件校验)

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注