在表现层的数据处理方面主要分为两种类型,一种是类型转换,这点我们上篇已经简单介绍过,另外一种则是我们本篇文章将要介绍的:数据校验。对于我们的web应用,我们经常需要和用户进行交互收集用户信息,那么无论是用户误操作还是恶意攻击,这些错误的信息一旦被传入到后台,小则导致程序异常关闭,大则导致整个系统瘫痪。数据校验就是对用户的输入做一层过滤,保护我们的系统免受侵入。下面我们开始介绍本篇的内容,主要包括以下几小节:

  • 一个简单的例子(用于全局把握整个校验过程)
  • 两种校验配置风格
  • 为不同Action处理逻辑配置不同的校验配置
  • 详解struts2框架内置的几种校验器
  • 自定义校验器

一、一个简单的例子

     在详细介绍数据校验的每一步骤之前,我们先通过一个简单的例子从全局范围把握下整个数据校验流程都需要哪些文件,各个步骤执行的顺序。强调的是从全局粗略的感受下,不用在意具体的代码。

//登录表单页面,信息提交到loginAction
<html>
<head>
<title></title>
</head>
<body>
<s:form method="POST" action="/login">
<s:textfield name="name" label="姓名"/>
<s:textfield name="age" label="年龄"/>
<s:submit value="提交"/>
</s:form> </body>
</html>
//定义一个action
public class LoginAction extends ActionSupport { private String name;
private int age;
public void setName(String n){
this.name= n;
}
public String getName(){
return this.name;
}
public void setAge(int a){
this.age = a;
}
public int getAge(){
return this.age;
} public String execute(){
return SUCCESS;
}
}
//创建校验文件并键入以下内容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.2//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>姓名不能为空</message>
</field-validator>
</field>
<field name="age">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>年龄不能为空</message>
</field-validator>
</field>
</validators>

我们首先从login这个表单页面提交表单信息到loginAction中的属性,然后框架会查找是否有校验规则文件,如果有则执行它。在校验的过程中,如果校验失败会跳转到处理结果为 input 视图页面,这里和上篇介绍的类型转换是一样的,我们也一般是需要为其指定一个input视图页面的。在我们上述的校验文件中,我们规定两个属性的值不能为空,如果为空则该数据不符合要求,框架会封装错误信息并跳转到input视图页面。下面我们看看上述代码的运行截图:



至此我们简单了解了数据校验整个过程大致需要的文件及其作用,当然该例中还有很多细节之处没有展现出来,因为目的只是从整体上直观感受下,详细的内容将在下面的小节中展现。

二、两种校验配置风格

     下面我们从校验文件开始看起。首先一点,校验文件的命名是有要求的并且一般一个校验文件只服务一个Action,所以该文件的命名规则如下:

<ActionName>-validation.xml

所以上述我们为LoginAction创建的校验文件名为:LoginAction-validation.xml。该文件有个根元素 validators ,我们的属性校验元素是其子元素。下面我们介绍第一种配置校验文件的方式,上述的例子就是这种方式,该种方式使用field 作为一级子元素,该元素将对应于Action实例中实际的属性,它有一个name属性,该属性就是用于指定此field元素配置的是Action的哪个实例属性,有几个实例属性就应该有几个field元素。

我们由field元素可以定位到Action实例中具体的某个属性,使用field-validator元素为给属性指定校验器(Struts默认提供的检验器,具体有关内置的校验器后文详细介绍),param 元素用于指定校验的参数,message元素用于指定不符合校验规则时输出的信息。我们可以根据不同的处理需要为Action实例属性指定不同的校验器,当然我们也是可以自定义校验器来校验属性的数值的。

上面介绍的是用field元素来配置的数据校验规则。下面我们介绍第二种配置风格,使用validator取代field作为一级子元素,用fieldName属性指定对应的Action实例属性,对于上面的配置,我们也可以改写为:

<validators>
<validator type="requiredstring">
<param name="fieldName">name</param>
<param name="trim">true</param>
<message>姓名不能为空</message>
</validator>
<validator type="requiredstring">
<param name="fieldName">age</param>
<param name="trim">true</param>
<message>年龄不能为空</message>
</validator>
</validators>

我们看到该方式的配置每个属性用一个validator元素表示,通过param元素的fieldName属性对应实际的Action实例属性,其余内容和第一种方式类似。他们之间的区别相信大家对比之后也能明白,只是书写方式不同,都能达到效果,大家可以根据自己喜好选择使用哪种方式,由于个人喜好,下文都会采用第一种方式进行介绍。

三、为不同Action处理逻辑配置不同的校验配置

     我们的某个具体的Action类在很多情况下是可以用于多个不同的处理逻辑的,例如某个action既可以处理用户注册请求也可以处理用户登录请求,但是对于这两种截然不同的请求,我们的数据校验却不尽相同,下面看个例子:

public class LoginAction extends ActionSupport {

    private String name;
private String pass1;
private String pass2;
public void setName(String n){
this.name= n;
}
public String getName(){
return this.name;
}
public void setPass1(String p1){
this.pass1 = p1;
}
public String getPass1(){
return this.pass1;
}
public void setPass2(String p2){
this.pass2 = p2;
}
public String getPass2(){
return this.pass2;
} public String execute(){
return SUCCESS;
}
}
//Struts.xml中指定该类用于响应两个请求
<struts>
<package name="my" extends="struts-default" namespace="/">
<action name="login" class="MyPackage.LoginAction">
<result name="success">/index.jsp</result>
<result name="input">/input.jsp</result>
</action>
<action name="regist" class="MyPackage.LoginAction">
<result name="success">/index.jsp</result>
<result name="input">/input.jsp</result>
</action>
</package>
</struts>

此时我们需要创建两个数据校验文件,一个用于校验请求login,一个用于校验请求regist。当然为了框架能够快速搜索到,这里两个文件的命名也是有要求的,规则如下:

<ActionName>-<ActionAliasName>-validation.xml

对应于上述的两个文件名为:LoginAction-login-validation.xml和LoginAction-regist-validation.xml。下面给出此例中上述两个文件的内容:

//LoginAction-login-validation.xml局部内容
<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>姓名不能为空</message>
</field-validator>
</field>
<field name="pass1">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>密码不能为空</message>
</field-validator>
</field>
</validators>
//LoginAction-regist-validation.xml局部内容
//该校验文件为pass1属性添加了一个fieldexpression校验器,用于校验是否和pass2相等
<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>姓名不能为空</message>
</field-validator>
</field>
<field name="pass1">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>密码不能为空</message>
</field-validator>
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[(pass1==pass2)]]></param>
<message>两次密码不同</message>
</field-validator>
</field>
<field name="pass2">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>密码不能为空</message>
</field-validator>
</field>
</validators>

上述的两个文件依然是需要存放在和Action相同目录下,框架会根据不同的请求而去检索相应的校验文件,下面我们看表单页面:

//注册页面
<body>
<s:form method="POST" action="/regist">
<s:textfield name="name" label="姓名"/>
<s:textfield name="pass1" label="密码"/>
<s:textfield name="pass2" label="密码"/>
<s:submit value="提交"/>
</s:form>
</body>



而对于login登录逻辑来说,

  <body>
<s:form method="POST" action="/login">
<s:textfield name="name" label="姓名"/>
<s:textfield name="pass1" label="密码"/>
<s:submit value="提交"/>
</s:form>
</body>



只需要用户名和密码不为空即可,并没有别的校验逻辑,可能上述的例子并不是十分恰当,但是却很清晰的展示了这种校验分离的处理过程。对于校验文件中的内容,我们将在下文详细介绍,此处不必纠结。最后需要强调一点的是,当我们为每个不同的处理逻辑配置相对应的校验文件时,原来的那个LoginAction-validation.xml文件则会被作为默认的校验文件,当LoginAction-login-validation.xml或者LoginAction-regist-validation.xml执行之后,会自动继续执行该校验文件,也就会导致校验了两遍,所以一般会在该文件中添加该Action的通用校验代码。

四、详解struts2框架内置校验器

     有关框架的内置校验器,我们在上文中一直都使用,但是没有详细的介绍,本小节就专门介绍这些内置校验器的使用,下一小节将介绍如何自定义一个校验器。首先解压xwork-core-2.3.32.jar,从com\opensymphony\xwork2\validator\validators中找到default.xml并打开:

这是框架内建立的所有校验器,我们会介绍其中的部分, 剩余的一些校验器由于某些局限性不经常使用,所以此处就不在介绍。

下面看第一种校验器,必填校验器。该校验器要求指定字段的值非空(null)。该校验器的使用比较简单,此处不再演示。

第二种校验器,必填字符串校验器。该校验器要求字段的值非空并且长度要大于0。即字段不能是""。该校验器要求比第一种必填校验器严格一点。它还具有一个参数:trim。该参数用于剔除字段中前后的空白,默认值为true。这一点也是比较容易理解的,此处不再赘述。

第三种校验器,整数校验器。对于Action中字段类型为int,long,short的情况,我们可以使用该校验器来要求该字段的值必须存在于指定的范围内。它有两个参数,min,max,一个是指定该字段的值可能出现的最小值,一个则是指定该字段的值可能出现的最大值。下面看个例子:

//LoginAction中添加age属性的代码并未贴出
//此处指定了该age属性必须在0-100之间
<validators>
<field name="age">
<field-validator type="int">
<param name="min">0</param>
<param name="max">100</param>
<message>输入的年龄必须在指定0-100之间</message>
</field-validator>
</field>
</validators>



第四种校验器,日期校验器。该校验器用于规定日期类型的属性值可能出现的范围。有两个参数,min和max。两者分别指定日期最小值和最大值。下面看一个例子:

//LoginAction中添加属性date
<validators>
<field name="date">
<field-validator type="date">
<param name="min">1990-01-01</param>
<param name="max">2017-5-19</param>
<message>日期范围为:1990-01-01到2017-5-19</message>
</field-validator>
</field>
</validators>



第五种校验器,字段表达式校验器,fieldexpression。它要求该字段满足一个基于ognl的表达式。该校验器具有一个参数,expression,该参数指定了一个表达式。下面我们看一个具体的例子:

//表达式要写在 <![CDATA[....]]> 内
<validators>
<field name="pass1">
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[(pass1 == pass2)]]></param>
<message>无法匹配表达式</message>
</field-validator>
</field>
</validators>



需要注意一点的是我们可以使用ognl表达式从ValueStack中取数据进行比较,但是ognl表达式本身必须被写在<![CDATA[....]]>中。至于为什么,作者还没参透。

第六种校验器,字符串长度校验器。该校验器比较简单,和之前介绍的几种很是类似,主要有几个参数,maxLength,minLength,trim。相信大家也都知道他们什么意思,此处不再赘述。

第七种校验器,正则表达式校验器。该校验器有两个参数,regex代表正则表达式内容,caseSensitive指定校验时是否考虑大小写。具体使用情况比较容易,此处不再赘述。下面我们看自定义校验器。

五、自定义校验器

     相比于使用Struts2内置校验器,自定义一个校验器反而简单些。我们只需要重写ActionSupport类中的一个方法即可:

  public void validate() {}

下面我们看一个例子:

//在LoginAction中添加如下一个方法
public void validate(){
if(name.isEmpty()){
addFieldError("name","用户名不能为空");
}
if (!pass1.equals(pass2)){
addFieldError("pass1","两次输入的密码必须相同");
}
}

该方法用于判断字段name是否为空,如果为空打包错误信息添加到FieldError中,判断两次输入的密码是否一致,如果不一致打包错误信息添加到FieldError中。在方法结束时,框架会去查看FieldError是否为空,如果不为空说明校验出错,跳转视图input页面。下面我们看上述代码的运行截图:



从运行的结果看,自定义校验器和使用框架内置校验器都能完成数据校验的工作,但是个人认为自定义校验方式反而显得过程简单。对于之前介绍的一个Action类响应多个请求时候对数据校验的不同形态,在我们自定义校验器中也是可以实现的,只是定义的方法名有所区别,例如:

响应login处理逻辑的自定义校验方法命名为:validateLogin()
响应regist处理逻辑的自定义校验方法命名为:validateRegist()

至此,我们简单介绍完了有关Struts2框架的数据校验部分的内容,总结的粗糙,望大家多多评论指点!

深入理解Struts2----数据校验的更多相关文章

  1. Struts2数据校验

    Struts2数据校验 1.常见数据校验方法 表单数据的校验方式: 表单中的数据必须被效验以后才能够被使用,常用的效验方式分为两种: 前台校验:也称之为客户端效验,主要是通过JS编程的方式进行表单数据 ...

  2. struts2 数据校验

    通过struts2中延续自xwork框架的validation.xml配置方式进行数据校验,因struts2 下存在三种请求参数的注入方式,固按照不同注入方式对validation.xml的配置进行总 ...

  3. 第六章、Struts2数据校验

    一.三种实现方式 ① 用validate()方法实现数据校验 继承ActionSupport类,该类实现了Validateable接口,该接口中定义了一个validate()方法,在自定义的Actio ...

  4. 06章 Struts2数据校验

    一.三种实现方式 ① 用validate()方法实现数据校验 继承ActionSupport类,该类实现了Validateable接口,该接口中定义了一个validate()方法,在自定义的Actio ...

  5. struts2 之 struts2数据校验

    1. 数据校验一般分为2类:前端的校验(js校验),后端的校验(java代码):实际开发中大部分情况下都是采用js校验.在对数据安全要求较高的情况下可能会采用后端验证. 2.  Struts2提供了后 ...

  6. struts2数据校验与国际化

    数据校验: Action里的validate()方法能校验action类所有的方法,如果有错,如:addFieldError,会自动返回到workflow校验拦截器不向下继续进行,不用return i ...

  7. Struts2数据校验方法

    方法: 1.在Action类中execute()方法中进行校验. 优点:Action类无需继承框架中的类. 缺点:(1)当有多个校验时,代码重复,违反高内聚,低耦合. 2.重写框架ActionSupp ...

  8. Struts2 数据校验之四兄弟

    现在是科技的时代,大多数人都在网上购物了, 我们都碰到过相同的问题,各大网站弄的那些各种各样的注册页面,相信大家都深有体会. 有了这验证就很好的保证了我们的信息的准确性和安全性. 接下来我给大家讲解一 ...

  9. Struts2 数据校验流程

  10. Struts2第十篇【数据校验、代码方式、XML配置方式、错误信息返回样式】

    回顾以前的数据校验 使用一个FormBean对象来封装着web端来过来的数据 维护一个Map集合保存着错误信息-对各个字段进行逻辑判断 //表单提交过来的数据全都是String类型的,birthday ...

随机推荐

  1. 关于压缩jar包时提示*.*没有这个文件或目录的问题以及解决办法:

    关于压缩jar包时提示.没有这个文件或目录的问题以及解决办法: 问题描述: 我在打包jar时,CMD中进入到包的上一层目录. 在命令提示符中输入 提示如下: 从提示中可知没有找到我们想要打包的clas ...

  2. BinarySearch的一些注意事项

    BinarySearch原理比较简单,不过在处理实际问题的过程中需要注意几个小问题: 1. 找出有序数组中第一个为某特定值的数,以及没找到则返回-1 2. 找出有序数组中最后一个为某特定值的数,以及没 ...

  3. Java第二章 变量

    1.什么是变量? 存储数据的基本单位. 2.数据类型分为: 基本类型和引用数据 3.基本数据类型和引用数据类型的区别: 基础数据:不同的变量会分配不同的存储空间,改变一个变量不会影响另一个变量 引用数 ...

  4. Java环境----JDK开发环境搭建及环境变量配置

    1.啥是jdk? jdk的是java development kit的缩写,意思是java程序开发的工具包. jdk的版本,一共有三种,标准版(j2se),企业版(j2ee),移动设备版(j2me). ...

  5. POST与GET

    面试如果被问到这个问题,相信很多人都是会心一笑,答案随口而来: 1.GET在浏览器回退时是无害的,而POST会再次提交请求. 2.GET请求会被浏览器主动cache,而POST不会,除非手动设置. 3 ...

  6. JavaScript基础学习(六)—函数

    一.函数的定义 1.function语句形式 //1.function语句式 function test1(){ alert("I am test1"); } test1(); 2 ...

  7. Windows入门基础:1.关于CreateWindow()函数使用中遇到的问题

    我在实现显示窗口的程序中,遇到一个问题:首先程序没有任何语法错误,编译能够通过,但是就是不能弹出窗口. 后来在MSDN中查询CreateWindow()函数,发现了下面这句话: "If lp ...

  8. 嵌入javascript脚本的位置

    JavaScript脚本可以放在HTML文档任何需要的位置.一般来说,可以在<head>与</head>.<body>与</body>标记对之间按需要放 ...

  9. CTF 字符统计1

    题目地址:http://sec.hdu.edu.cn/question/web/1047/ 题目如下: 给你2秒钟的时间,告诉我下面这坨字符中有多少个s,多少个e,多少个c,多少个l,多少个a和多少个 ...

  10. MVC实现SSO

    近来工作无事,想做个SSO, 之前做过一个项目用到SSO,自己也没有看明白是个什么东西.现在正好有时间,所以想研究下. 先是从网上看到了SSO的思路: 三个站点:SiteA,SiteB,SiteMai ...