ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 研磨Struts2 之 第十四章 验证器框架【私塾在线原创】

研磨Struts2 之 第十四章 验证器框架【私塾在线原创】

原创 Linux操作系统 作者:不知道010 时间:2012-02-28 16:29:53 0 删除 编辑
对于企业级的应用而言,服务器端验证是必不可少的。在任何一个真实的业务逻辑被调用之前,都需要验证用户提交的数据是否满足要求,比如是否填写、是否符合格式要求、数据的相关性是否正确等等。
那么,一个好的验证框架都需要考虑些什么呢?
验证功能的复用性。
验证功能的可扩展性。
验证与业务逻辑分离。
Struts2作为一套优秀的web框架,已经为我们内置了一套非常棒的验证框架,完全满足以上的要求。接下来就来具体学习Struts2的验证框架。
初会验证框架
现在来加入验证框架,非常简单,只需要添加一个xml,这个xml命名为Action类名-validation.xml,放在需要验证的Action类同包下,其内容为这个Action的execute方法运行前要对用户的输入进行的各种验证。

java代码:


  


请填入姓名




18
年龄必须在18岁以上


验证的时机。验证发生在execute方法运行之前,在Struts2的params拦截器已经把请求的参数反射的设置到Action的属性之后。所以,验证框架实际上验证的是值栈内的值。
验证的结果。如果用户输入的参数完全满足验证条件,则会继续执行execute方法,如果用户输入的参数不满足验证条件,注意:三个验证条件只要有一个验证通不过,就会跳转到这个Action所配置的名为input的Result。
 
可以看到,这与 validate() 方法一模一样。
在验证文件中引用值栈

java代码:


18
年龄必须在18岁以上,您输入的是${user.age}

在验证文件中引用国际化框架

java代码:


18


 
 
可以把验证器类型分为两种:字段验证器和动作验证器。其中,字段验证器就像前面演示的那样,只验证提交的表单内的单个字段;而动作验证器一般验证提交的表单内的多个字段的关系,比如,录入产品信息的时候,产品的进价不能高于售价。
无论是哪种验证器,都需要考虑以下几个问题:
验证谁?
使用什么条件验证?
不满足条件显示什么结果?
不满足验证条件时显示的结果出现在页面的什么位置?

java代码:



18
年龄必须在18岁以上,您输入的是${user.age}



--------------------------------------------------------------------


user.age
18
年龄必须在18岁以上,您输入的是${user.age}



=user.account]]>
年龄必须在${user.account}岁以上,您输入的是${user.age}
 
可以使用标签来引用。
Struts2的验证框架已经为我们建立了足够多的内建验证器,以满足不同的验证要求。
1  类型转换错误验证器 (conversion)
conversion验证器用来验证类型转换时是否出错。如果一个类型为int的参数接到了“18a”这个字符串,conversion验证器就会报错。
2  整数验证器 (int)
int验证器用来验证一个整数型参数是否在指定的范围内。如果一个已经被成功转换为int的属性不在验证器指定的范围内,int验证器就会报错。
int验证器可以有两个参数:
nmin用来指定可接受范围的最小值。
nmax用来指定可接收范围的最大值。
3、 短整数验证器 (short) 和长整数验证器 (long)
short验证器和long验证器与int验证器非常相似,都是用来验证参数是否在指定范围之内,就不去赘述了。
4  日期验证器 (date)
date验证器用来验证一个日期型参数是否在指定的范围内。如果一个已经被成功转换为date的属性不在验证器指定的范围内,date验证器就会报错。
date验证器可以有两个参数:
min用来指定可接受范围的最小值。
max用来指定可接收范围的最大值。
注意:指定日期范围的时候,需要使用统一的格式,比如用MM/DD/YYYY的格式等。
5  双精度浮点验证器 (double)
double验证器用来验证一个双精度浮点型参数是否在指定的范围内。如果一个已经被成功转换为double的属性不在验证器指定的范围内,double验证器就会报错。
double验证器可以有四个参数:
minInclusive用来指定可接受范围的最小值,包含给定值。
maxInclusive用来指定可接收范围的最大值,包含给定值。
minExclusive用来指定可接受范围的最小值,不包含给定值。
maxExclusive用来指定可接收范围的最大值,不包含给定值。
6  邮件验证器 (email)
7  URL 验证器 (url)
8  必填验证器 (required)
9  必填字符串验证器 (requiredstring)
requiredstring验证器用来验证一个字符串参数是否非空,既不为null,且长度大于0。
requiredstring验证器只有一个参数:
ntrim:是否去掉字符串两边的空白,默认为true。
10  字符串长度验证器 (stringlength)
stringlength验证器用来验证一个字符串的长度是否在指定范围内。
stringlength验证器有三个参数:
nmaxLength:字符串长度的最大值。
nminLength:字符串长度的最小值。
ntrim:是否去掉字符串两边的空白,默认为true。
11  正则表达式验证器 (regex)
regex验证器用来验证一个字符串是否符合一个正则表达式的要求。
regex验证器有三个参数:
nexpression:必填参数,正则表达式。
ncaseSensitive:是否检查大小写。
ntrim:是否去掉字符串两边的空白,默认为true。
12  字段表达式验证器 (fieldexpression) 和表达式验证器 (expression)
fieldexpression验证器中必须指定一个返回布尔值的ognl表达式,根据这个表达式的值来确定是否符合条件。
fieldexpression验证器只有一个参数:
nexpression:返回布尔值的ognl表达式,可以在这个ognl表达式中访问当前的值栈。
regex验证器既可以用于字段验证器,又可以用于动作验证器。
表达式验证器(expression)与字段表达式验证器(fieldexpression)类似,同样使用expression参数来指定返回布尔值的ognl表达式,但是,只能用于动作验证器。
13  访问者验证器 (visitor)
visitor验证器用于验证Action中的复合属性,可以直接把验证信息放到域对象中去注册,这样就使得同包内的不同Action在验证同一个域对象时,不用注册重复的验证信息。
vistior验证器有两个属性:
ncontext:引用的域对象验证信息文件上下文名。
nappendPrefix:是否在错误信息中添加元素指定的前缀。
修改一下原来的验证信息文件,示例如下:

java代码:



c1
true
用户


接下来新添一个上下文验证文件,其文件名为“字段的简单类名-上下文名-validation.xml”,比如现在要为user属性指定一个名为c1的上下文,所以文件名为UserModel-c1-validation.xml,放在与域对象同级的包内,即UserModel所在的包内,注意:不再是与Action同级的包内了,其内容示例为:

java代码:


 



18
年龄要大于等于18


它的本质也是一个验证文件,与之前直接在RegisterAction-validation.xml直接写出对user.age的验证相比,没有本质上的区别,只是这个文件以UserModel类为验证的根,所以元素的name属性直接写age就可以了,而不再是原来的user.age。
虽然Struts2的内建验证器可以完成绝大多数的验证需求,但是,有的时候还是需要个性化定制一些自定义的验证器。
以一个示例来说明吧。来实现一个不接受中文字符的验证器,比如,在一个网站上进行注册,在填入账号的时候,必须填入英文字符或者是数字等,而不接受中文字符,同时还要求验证器可以分辨以下三种情况:
全是非中文字符
全是中文字符
既有非中文字符又有中文字符
该怎么实现呢?通常在做自定义验证器的时候,需要考虑如下几个问题:
如何编写自定义验证器的代码。
如何注册自定义验证器。
程序中如何引用自定义验证器。
要实现自定义得验证器的基本方式是:写一个类来继承FieldValidatorSupport 这个类,它提供很多方法来供我们调用,其中比较重要的是:
getFieldName方法用来获取被验证的字段名;
getFieldValue方法用来获取用户输入的参数;
还有一个抽象方法validate等待我们来实现,在这个方法中,如果我们调用了addFieldError,说明发生了字段验证错误,如果我们调用了addActionError,说明发生了动
作验证错误。

java代码:
public class ChineseValidator  extends FieldValidatorSupport{
/**
 * 表示是否包含有中文。现在有三种模式:
 * none 没有中文字符
 * some 含有中文字符,默认值
 * all 全是中文字符
 */
private String mode = "some";
public void setMode(String mode) {
this.mode = mode;
}
public void validate(Object object) throws ValidationException {
//获取字段名
final String fieldName = this.getFieldName();
//获取字段值
final String fieldValue = (String) this.getFieldValue(fieldName, object);
//字节数
final int bytes = fieldValue.getBytes().length;
//字符数
final int chars = fieldValue.length();
if (mode.equals("none")){
//现在要求全是非中文字符
//所以字节数和字符数,两个数字必须相等,不相等则出错
if (chars!=bytes){
this.addFieldError(fieldName, object);
}
}
…
}
}
自定义的验证器,只需要在classpath的根路径上,即放在src文件夹下(会被Eclipse自动拷贝到classpath的根下去),仿照default.xml的声明方式,写一个validators.xml即可。示例如下:

java代码:


 

    
在应用中引用自定义验证器的时候,和引用内建验证器的方式是完全一样的。修改RegisterAction-validation.xml中验证用户填入的账号(user.account)属性的验证器,设置为上面配置的“chinese”,示例代码如下:

java代码:



none
用户账号,只能输入非中文的字符


在以前的学习中,已经接触到了如何引用验证器返回的错误信息,现在来全面的整理一下如何引用验证器返回的错误信息。
引用字段验证错误有两种方式:
对于字段验证错误来说,在使用xhtml风格的时候,标签会将这个字段的错误信息显示在这个文本框的上边。还可以用标签来将字段验证错误的错误信息显示在指定位置,如果不指定其fieldName属性则会显示所有的错误,如果指定了fieldName属性则会显示指定字段的错误。
对于动作验证错误,可以使用标签,它会把所有的动作验证错误显示在指定的位置。
Struts2的验证框架为了使验证信息通用,指定了较为复杂的验证继承关系,当验证框架需要验证一个Action的时候,会按照以下的优先级收集验证信息:
父类-validation.xml
父类-别名-validation.xml
接口-validation.xml
接口-别名-validation.xml
Action类名-validation.xml
Action类名-别名-validation.xml
别名其实对应的就是元素的method属性的值,因此,虽然看着很多,其实我们只需要记住基本的顺序是:父类 > 接口 > Action类 就可以了。
这里还需要强调一点,接口-validation.xml优先于Action类名-validation.xml的含义,并不是找到了接口-validation.xml就不管Action类名-validation.xml,而是对于同名的字段验证器来说,两个验证都要进行,不过接口-validation.xml中的验证先于Action类名-validation.xml中的验证进行。
当一个字段有多个验证条件的时候,在第一次出现验证错误后,就立即终止验证,后续对这个字段的验证就不再进行了,这就叫验证器短路。
上设置short-circuit属性的值为true,示例代码如下:

java代码:





15
年龄要大于等于15岁


这里要注意一点,就是DOCTYPE里面用的版本是Validator1.0.2,以前的版本是1.0,一定要注意,只有1.0.2的版本才能正确执行验证器短路。
在前面的章节中,已经学习了Struts2的绝大多数核心知识。在这一章中,将使用一个简单的用例,来对前面的知识进行综合运用,好让大家融会贯通这些知识。
用例功能:做一个用户管理的模块,功能就是最基本的增删改查的功能。为了示例的简洁,用户的基本信息仅仅包含:用户编号、姓名、性别、年龄。
示例用4个页面来实现增删改查的功能:
•列表页面:用来显示所有的数据或查询的结果。在这个页面上有一个链接用于跳转到增加页面,有一个链接用于跳转到查询条件页面。对于每一条查询出来的结果,有一个链接跳转到这条记录的修改页面,有一个链接用于删除这条记录,删除功能就在列表页面完成,在删除之前弹出对话框来让用户确认。
•添加页面:用来添加一个新的用户。
•修改页面:用来修改一个原有用户,页面初始化的时候要把这个用户的原有信息填入各个表单项作为页面显示的数据。
•查询条件页面:用来收集一次查询用的组合条件。
1、建立Model
2、建立组合查询条件QueryModel
3、使用JDBC编写数据层
4、准备页面的框架
1、搭建Struts2工程
2、实现最简单的增删改查功能
Action:如何传接值
jsp:使用典型的各种s标签。
struts.xml
3、加入国际化信息,使得软件可以同时支持中文和英文
4、加入验证框架,验证用户的输入是否符合条件
在开发基于Web的应用的时候,经常会碰到需要实现文件上传、下载的功能,比如编辑某个商品,需要给它上传一个图片等等。
不使用Struts2的话,可以有很多种方式来实现文件上传,比如使用Apache的Common-FileUpload等。但是这些传统的方式,实现起来非常麻烦,需要写很多代码来进行控制。
现在使用Struts2来实现文件上传的功能,会更加简单和方便,事实上,Struts2的文件上传功能,默认就是基于Common-FileUpload来实现的,只不过比直接使用Common-FileUpload来得更简单。
1、使用Struts2来实现文件上传,需要使用Struts2预定义的fileUpload拦截器。
2、文件上传页面

java代码:

文件名称:
文件:
3、实现文件上传Action public class UploadAction extends ActionSupport{ private String fileName; private File myFile; ... public String execute()throws Exception{ //先把上传过来的文件存放到e盘temp目录下,以传入的fileName为名字 OutputStream utput = null; InputStream input = null; try{ utput = new FileOutputStream("e:/temp/"+fileName); //建立一个1k大小的缓冲区 byte[] bs = new byte[1024]; //将上传过来的文件输出到output中 input = new FileInputStream(myFile); int length = 0; //length=input.read(bs)这句话中,length=-1代表了读到文件结尾 while ((length=input.read(bs))>0){ output.write(bs, 0, length); } }finally{ input.close(); output.close(); } return SUCCESS; } }
Struts2支持用更多的属性来获取有关上传文件的真实文件名和文件类型。
比如:表单中包含了一个叫xyz的文件域,也就是类似于
File类型的属性xyz用来获取文件内容。
String类型的属性xyzFileName用来获取文件的真实文件名。
String类型的属性xyzContentType属性用来获取文件的类型。
在文件上传的时候,有可能需要对文件的大小和类型做出限制。Struts2支持直接在fileUpload拦截器上设置参数来进行限制。
在引用fileUpload拦截器的时候,可以指定三个参数(指定子元素):
allowedTypes:指定允许上传的文件的类型,如果存在多种类型,以逗号隔开。注意:这里添的不是文件的扩展名,而是对应的ContentType,如果不知道某种文件的ContentType可以先上传一下试试,在后台输出ContentType来。
maximumSize:指定允许上传的文件的最大字节数。
allowedExtensions:指定允许上传的文件的扩展名。
如果上传的文件不满足以上的参数指定的条件,则会跳转到一个叫input的上,一般input都会指回到提交之前的页面,也就是文件上传页面。
Struts2在实现文件上传的时候,还有一个小问题,那就是默认上传文件的大小是不能超过2097152字节的。
只要覆盖默认设置就可以了,有两种方式,一种是在Struts.properties里面配置,另外一种就是在struts.xml里面配置。这里就以在struts.xml来配置为例,只要在struts.xml中加入如下的常量定义,示例代码如下:

java代码:
在实际开发中,经常会碰到需要在一个表单中上传多个文件的情况,比如为某文档添加附件,就可能要求在一个表单上添加多个附件。
对于在一个表单中上传多个文件的功能,使用Struts2也能轻松实现。只需要在提交页面上添加同名的多个文件输入域,然后在Action中对应使用File类型的数组去接收这些参数即可。
修改上传文件页面:

java代码:
文件:
文件:
文件:
文件:
修改Action: public class UploadAction extends ActionSupport{ private File[] myFile; private String[] myFileFileName; … }
前面学习了文件上传的实现,接下来看看如何实现文件下载的功能。实现文件下载功能的方式也很多,这里只具体看看如何使用Struts2来实现文件下载。
使用Struts2来实现文件下载,会用到它的stream类型的Result,这种Result最终会返回一个InputStream,只需要让这个InputStream能读到用户想要下载的文件即可。
观察可知,stream是struts-default包中声明的一种内置结果类型,因而只要我们的包继承自struts-default包就可以使用这种结果类型了。
使用stream类型作为Result的Action和普通的Action有很大的不同,它不需要execute方法;而是需要一个公有的,返回InputStream的getInputStream方法,这个方法用来返回文件的内容。示例代码如下:

java代码:
public class DownloadAction extends ActionSupport{
public InputStream getInputStream() throws Exception{
File file = new File("e:/temp/测试.doc");
return new FileInputStream(file);
}
}
在struts.xml中,需要配置这个Action的后继页面为一个stream类型的Result。

      
         
attachment;filename="test.doc“
        



上面配置中,元素只有一个子元素,其类型为stream;但是元素有一个子元素指定了contentDisposition的值为attachment;filename="test.doc",这指明了在访问这个Result的时候,会弹出一个下载框,其中的默认文件名为test.doc。
stream类型的结果共可以指定7个参数:
contentType:下载文件的类型。
contentLength:下载文件的长度,用于浏览器的进度条显示。
contentDisposition:指定文件下载的默认名字,如果不指定则使用Action名.action。
inputName:Action中用于返回InputStream的get方法的名字,默认为inputStream,因此,我们的Action中定义了getInputStream的方法。
bufferSize:缓冲区大小,默认为1k。
allowCaching:是否允许浏览器进行缓存。
contentCharSet:HTTP响应头信息中的编码方式。
在以上7个参数中,最常用的是使用contentDisposition来指定默认的文件下载名,其他的使用默认即可。
文件下载的链接只需要指向对应的action即可。

java代码:
下载文件
1  Action 实现

java代码:
public String getDownloadFileName() throws UnsupportedEncodingException {
        String downFileName = "好的.doc";   
        downFileName = new String(downFileName.getBytes("gb2312"), "ISO-8859-1"); 
        return downFileName;   
    }
 
public InputStream getInputStream() throws Exception{
File file = new File("e:/temp/一二三四.doc");
return new FileInputStream(file);
}
2 、配置文件

java代码:

attachment;filename="${downloadFileName}“
 
 视频配套PPT,视频地址【 研磨Struts2视频课程

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26715408/viewspace-717299/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论