您的位置:首页 > 编程语言 > Java开发

struts2中使用xml进行validate验证

2012-04-20 21:13 453 查看
struts2提供了使用validate框架来实现输入校验,这种方式是基于XML的验证。

文件名为XXXAction-validation.xml。

那么校验xml文件格式该如何写呢?

可以使用firefox查看此xml的DTD定义,地址为 http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd
在此列出此DTD的内容

<?xml version="1.0" encoding="UTF-8"?>
<!--
XWork Validators DTD.
Used the following DOCTYPE.
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!ELEMENT validators (field|validator)+>
<!ELEMENT field (field-validator+)>
<!ATTLIST field
name CDATA #REQUIRED
>
<!ELEMENT field-validator (param*, message)>
<!ATTLIST field-validator
type CDATA #REQUIRED
short-circuit (true|false) "false"
>
<!ELEMENT validator (param*, message)>
<!ATTLIST validator
type CDATA #REQUIRED
short-circuit (true|false) "false"
>
<!ELEMENT param (#PCDATA)>
<!ATTLIST param
name CDATA #REQUIRED
>
<!ELEMENT message (#PCDATA)>
<!ATTLIST message
key CDATA #IMPLIED
>


由此DTD的定义可知,此XML文件的根元素为validators。

在根元素下可以有若干个field或validator子元素,即分别代表着字段校验和非字段校验,它们的区别将在后面介绍。

字段校验

字段校验代表着field,标签有个name属性石必填的,它和表单中的name属性值是一样的。

这里我填入username。

<validators>
<field name="username">
</field>
</validators>
field下面有个子元素叫field-validator,代表着要用什么方式来进行校验,其有个属性叫 type,也是必填的。

<validators>
<field name="username">
<field-validator type="">
</field-validator>
</field>
</validators>


type应该填入什么内容呢?

可以查看xwork的源文件,在包 com.opensymphony.xwork2.validator.validators下有个文件default.xml,在这个文件中定义了 type属性值。

<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>

<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>

还有很多定义好的type值,这里不一一列举

在validator元素中,name属性表示可以定义的type值,class 表示用哪个类来进行校验,这是struts2默认设置好的校验器,我们可以直接使用。

在这个例子中,我们将type设置为requiredstring

<validators>
<field name="username">
<field-validator type="requiredstring">
</field-validator>
</field>
</validators>


在field-validator下面有两个子元素,param和message

param可以任意个,可有可无,但是message有且只有一个。

param表示传入的参数,message表示出错时显示的信息。也就是说message可以是任意的字符串,但是param却是特定的。

在继续之前还是看看 com.opensymphony.xwork2.validator.validators.RequiredStringValidator这个类的源代码。首先确定已经下载了源代码,并且在MyEclipse中关联了源代码,这是一个好习惯。

在这个类中有一个成员变量

private boolean doTrim = true;

因此,我们在param中要做的就是,将param元素的name属性设置为doTrim,值为true。

<validators>
<field name="username">
<field-validator type="requiredstring">
<param name="trim"<true>/param>
<message<username should not be blank!</message>
</field-validator>
</field>
</validators>
trim表示是否忽略空格,默认是true,因此在此也可以省略掉param元素。

其实在 field-validator元素中还有一个属性short-circuit,其默认值是false,表示的意思是短路,即前面验证失败,后面就不做验证了。

然而这仅仅只是一个校验条件,还是以 username为例,在上次的例子中,还要求username的长度要在6到10之间,因此,继续看default.xml文件

在其中找到这样一个元素

<validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>

从字面上可以看出是限制字符串长度的,因此查看这个实现类

它有3个成员变量:

private boolean doTrim = true;

private int maxLength = -1;

private int minLength = -1;

其中最主要的是maxLength和minLength分别代表最大长度和最小长度

因此在这个校验器中内容应该如下:

<field name="username">
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">10&lr;/param>
<message>username should be between ${minLength} and ${maxLength}</message>
</field-validator>
</field>


有个问题就是

<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>

<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>

required和requiredstring有什么区别吗?

requiredstring是指这个字符串是必须的,而required表示这个字段是必须的,而没有指明这个字段是否必须是字符串。

因此对于字符串,可以使用requiredstring,而对于非字符串类型就必须使用required了。如在这个示例中的age,birthday。注意birthday是Date类型的,不是String。

还是回顾一下register2.jsp的页面内容。

body中的内容为:

<s:actionerror />

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

……

……

</s:form>

但是输入数据提交后,仍然显示的是以前的出错信息,并不是今天所设置的信息。

这就涉及到一些知识点了,因为校验框架产生的错误是fielderror,不会在actionerror中显示。

因此,需要将 theme="simple"去掉,并把那些表格标签页去掉,然后执行时会看到在username上方的错误信息。

还有一个问题就是validate校验框架和Action中validate方法是否冲突。

实际上虽然会使用框架验证,但是也会调用Action的validate方法,通过上面的显示结果应该可以清楚的看到,在表单上面集中的显示了actionerror。

但是如果把Action中的validate方法的出错信息add到field中会有什么效果呢??

修改RegisterAction中validate方法,将 addActionError改为addFieldError。

当没有输入用户名时,会显示如下错误信息:

username should not be blank!

username invalid

为什么会显示这样的结果呢???

首先肯定的是在validate中增加的fielderror,和xml中不会冲突

即错误信息不会被覆盖,而是两者都有,而且先显示xml中定义的错误信息,然后才是validate中定义的错误信息。实际上是所有的xml执行完毕后,在执行validate。

为什么会产生这样的效果呢???那么你就必须知道fielderror到底是什么!继续查看源代码。

因为RegisterAction是继承的 ActionSupport,addFieldError是继承自ActionSupport,所以先看看ActionSupport中 addFieldError的实现方法。

在 ActionSupport中addFieldError是这么实现的,

public void addActionError(String anErrorMessage) {

validationAware.addActionError(anErrorMessage);

}

即通过调用validationAware对象的addActionError,而validationAware是 ValidationAwareSupport的一个实例,在ValidationAwareSupport中定义了fielderror是什么。

private Map>String, List<String>> fieldErrors;
public synchronized void addFieldError(String fieldName, String errorMessage) {
final Map<String, List<String>> errors = internalGetFieldErrors();
List<String> thisFieldErrors = errors.get(fieldName);
if (thisFieldErrors == null) {
thisFieldErrors = new ArrayList<String>();
errors.put(fieldName, thisFieldErrors);
}
thisFieldErrors.add(errorMessage);
}


通过源代码,可以看到fieldErrors实际上是一个Map>String, List<String>>。key是String类型的,而value是List<String>

而实际上这个List是通过ArrayList<String>来实现的,也就是说,key是String类型的,而value是ArrayList<String>。

虽然一个key只能对应一个value,但是在这里value并不是一个字符串,而是一个数组。所以错误信息不会被覆盖掉。

在ActionSupport类中存在一个方法getFieldErrors,按照方法名可以猜的出该方法返回的是fieldError这个数组,既然如此那么是否可以通过 getFieldErrors直接添加呢??

List<String> list = new ArrayList<String>();
list.add("username should be between 6 and 10");
this.getFieldErrors().put("username",list);


虽然编译器没有报错,但是实际上是不行的。查看API文档:

getFieldErrors,其解释如下:

public Map<String,List<String>> getFieldErrors()

Description copied from interface: ValidationAware

Get the field specific errors associated with this action. Error messages should not be added directly here, as implementations are free to return a new Collection or an

Unmodifiable Collection.

注释:

这个方法返回与这个action相关的具体的fielderrors,错误信息不能直接从这里添加,执行结果返回一个新的集合或一个不可修改的集合

这是什么意思呢?看源代码,这个方法同样是在 ValidationAwareSupport中实现的。

public synchronized Map<String, List<String>> getFieldErrors() {
return new LinkedHashMap<String, List<String>>(internalGetFieldErrors());
}
由此可以看到该方法返回的是一个新的LinkedHashMap,只是一个拷贝,而不是原集合,所以这样直接添加是无法显示出来的。

那么何时使用validate验证框架,什么时候使用action中的 validate方法呢?

一般来说,简单验证可以使用 xml,复杂时用validate

前面讲到了 struts2的数据校验,那么为什么要有服务器校验??拥有了客户端校验不是也行吗??

服务端校验是必须的,即使有客户端校验。因为可以不通过browser访问web服务器!!强健的web应用要有客户端和服务器端的验证。

当然,struts2同样支持客户端验证。

要使用struts2的客户端校验,必须满足一下条件:

1.form的主题(theme)一定不能设置为simple

2.将struts2 form标签中validate属性设置为true

但是看到小时效果后就会发现,struts2生成的也是js代码,但是效果却很差,所以一般来说,使用struts2的服务器端校验,而客户端校验自己写。

struts2标签支持事件,可以像使用html标签一样使用。

同样用validate校验框架也应该可以使用局部校验:

当action中有多个方法时,需要在和action同目录下新建文件 XXXAction-XXX(方法名)-validation.xml

在实例化子类对象时,会先执行父类的全局校验,然后是局部校验,接着是子类的全局校验,然后是子类的局部校验,因此不要提供全局校验。

字段校验和非字段校验的区别

通俗点讲:

字段校验:校验谁,用什么方法

非字段校验:用什么校验,校验谁

非字段校验示例:

<validator type="requiredstring">

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

<message></message>

</validator>

其中tyoe="fieldName"是不变的。至于其他细节不在这里详细叙述。

但还是建议使用字段校验器。

下面用一个简单的实例演示下xml验证:

本例子实现简单的登陆输入验证:

在myeclipse10下,创建web project,添加struts2.1支持,引入必要的jar包,其中包含commons-validator-xxxx.jar提供validate支持。

首先创建JavaBean:Student.java,位于com.neuq.student包下:

package com.neuq.student;

public class Student {
private Integer studentid;
private String password;
private Integer age;
public Integer getStudentid() {
return studentid;
}
public void setStudentid(Integer studentid) {
this.studentid = studentid;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}


之后创建Action:CheckAction.java,位于com.neuq.check包下:

package com.neuq.check;

import com.neuq.student.Student;
import com.opensymphony.xwork2.ActionSupport;

public class CheckAction extends ActionSupport{
private Student student;

public Student getStudent() {
return student;
}

public void setStudent(Student student) {
this.student = student;
}

public String execute() {
return "toIndex2";
}
}


之后,在该包(com.neuq.check)下,添加validate文件CheckAction-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="student.studentid">
<field-validator type="requiredstring">
<message>request studentid</message>
</field-validator>
</field>

<field name="student.password">
<field-validator type="requiredstring">
<message>request password</message>
</field-validator>
</field>

<field name="student.age">
<field-validator type="required">
<message>request age</message>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">130</param>
<message>should between ${min} and ${max}</message>
</field-validator>
</field>
</validators>


之后修改struts.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
<action name="aCheck" class="com.neuq.check.CheckAction">
<result name="toIndex2">/index2.jsp</result>
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
最后实现前台jsp设计:

index.jsp:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<body>
<s:form action="aCheck">
<s:textfield name="student.studentid" label="studentid"></s:textfield>
<s:password name="student.password" label="password"></s:password>
<s:textfield name="student.age" label="age"></s:textfield>
<s:submit></s:submit>
</s:form>
</body>
</html>
index2.jsp:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<body>
Validate Success!
</body>
</html>
在tomcat下部署运行,提交信息,会看到提示信息。

方法二:

在之前的基础上,修改CheckAction-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="student">
<field-validator type="visitor">
<param name="context">student</param>
<param name="appendPrefix">true</param>
<message key="appendPrefix">user''s </message>
</field-validator>
</field>
</validators>
student指定了action中变量的名字,visitor是固定写法,student是JavaBean所在包下validate文件名的中间部分。

在com.neuq.student包下创建Student的验证Student-student-validation.xml,命名方式为“class名+context参数指定的值+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="studentid">
<field-validator type="requiredstring">
<message>request studentid</message>
</field-validator>
</field>

<field name="password">
<field-validator type="requiredstring">
<message>request password</message>
</field-validator>
</field>

<field name="age">
<field-validator type="required">
<message>request age</message>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">130</param>
<message>should between ${min} and ${max}</message>
</field-validator>
</field>
</validators>
注意,studentid,password,age不需要加JavaBean前缀。

重新部署运行,成功!

总结:

第一种validation方式,把验证集中action的验证文件中。当验证的内容少或者不同的action验证的内容重复性小的时候适用。

第二种validation方式,把验证集中在bean的验证文件中。当多个action都需要对相同bean的内容进行验证时,比较方便。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息