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

struts2输入校验

2013-10-09 00:30 387 查看
Struts输入校验

1什么是输入校验

输入校验,最常见的是对用户名和密码的输入错误的校验,实际上这个后台业务逻辑的判断而不是输入校验。输入校验是对像用户名长度,密码长度,限定的年龄值等这些信息进行判断。

2为什么要进行输入校验

输入校验是为了防止用户将错误的数据提交给服务端进行处理。通过输入校验,希望用户提交的是符合要求的数据。很多时候这种符合要求的数据是不符合用户平时使用的习惯的,或者有时候网站希望用户提交某些特殊形式的数据,这时候就必须使用输入校验来控制用户提交的数据符合要求。

3 输入校验的方式

输入校验的方式的方式有客户端校验和服务器端校验。可能有人要问,既然有了客户端校验来校验输入,为什么还需要服务器端的再次校验。实际上,在客户端我们常用的用javascript进行的校验是很容易被恶意的用户绕过去的。比如下载到网页后删掉javascript再提交数据,此时如果没有服务器端的校验,错误的数据就提交到了服务器。这样的话,那有必要再客户端进行校验码,试想一下,如果没有客户端校验,客户每提交一次数据,服务器端就立即进行校验,如果数据有错误返回给用户重写。这样不仅加重了服务器端的负担。用户在输入数据时校验也会非常的麻烦,最后可能是花长时间反复的校验后还提交不了符合要求的数据,可想而知这样的用户体验糟糕透了。所以说客户端校验与服务器端校验二者是相辅相成的。

 

4 下面用例子来展示如何运用struts2进行输入校验。

注册页面:Register.Jsp

<body>

<s:actionerror/>             //打印输入校验错误信息

<form action="register.action" method="post" id="form" onsubmit="validate()">

<!-- value="${requestScope.username 输入校验后保留用户输入的值 -->

uesrname:<input type="text" name="username" value="${requestScope.username }"  /><br/>

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

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

age:<input type="text" name="age" value="${requestScope.age }"/><br/>

birthday:<input type="text" name="birthday" value="${ requestScope.birthday}"/><br/>

email address:<input type="text" name="email" value="${ requestScope.email}"/><br/>

salary:<input type="text" name="salary" value="${ requestScope.salary}"/><br/>

url:<input type="text" name="url" value="${ requestScope.url}"/><br/>

regStr:<input type="text" name="regStr" value="${ requestScope.regStr}"/><br/>

<input type="submit" value="提交"><br/>

</form>

</body>


以下是客户端校验的代码,使用了正则表达式不懂的读者请自行查阅相关资料。

<!-- 客户端校验 -->

<script  type="text/javascript">

//使用此函数截断字符串前后的空格

function trim(str){

return str.replace(/^\s*/,"").replace(/\s*$/,"");

}

function validate(){

//定义错误字符串

var errors = "";

//取出表单中的值并使用trim截断前后空格

var username = trim(document.getElementById("form").username.value);

var password = trim(document.getElementById("form").password.value);

var repassword = trim(document.getElementById("form").repassword.value);

var age = trim(document.getElementById("form").age.value);

var birthday = trim(document.getElementById("form").birthday.value);

var email = trim(document.getElementById("form").email.value);

//判断用户名是否输入,如果输入了再判断格式是否正确

if(username == "" || username == null){

errors += "用户名必须输入";

}else if(! /^\w{6,20}$/.test(username)) {

errors += "\n用户名必须是字母和数字,长度为6到20之间"

}

//判断密码是否输入,如果输入了再判断格式是否正确

if(password == "" || password == null){

errors += "\n密码必须输入";

}else if(! /^\w{6,20}$/.test(password)) {

errors += "\n密码必须是字母和数字,长度为6到20之间"

}

//判断确认密码是否输入,如果输入了再判断格式是否正确

if(repassword == "" || repassword == null){

errors += "\n确认密码必须输入";

}else if(! /^\w{6,20}$/.test(repassword)) {

errors += "\n确认密码必须是字母和数字,长度为6到20之间"

}

//判断确认密码和密码是否相同

if(repassword != password){

errors += "\n确认密码和密码必须相同";

}

//年龄不是必须字段,只需要判断格式是否正确

if(age != "" && !/^[0-1]?[0-9]?[0-9]$/.test(age)){

errors += "\n请输入正确的年龄格式"

}

//出生日期不是必须字段,只需要判断格式是否正确

if( birth != "" && !/^19\d\d\-[0-1]\d\-[0-3]\d$/.test(birth) &&

!/^20[0-1]\d\-[0-1]\d\-[0-3]\d$/.test(birth)){

errors += "\n请输入正确的生日格式(1988-03-31)"

}

//邮箱地址不是必须字段,只需要判断格式是否正确

if(email != "" && !/^[a-zA-Z][a-zA-Z0-9._-]*@([a-zA-Z0-9-_]+.)+(com|gov|net|com.cn|edu.cn)$/.test(email)){

errors += "\n请输入正确的邮箱地址"

}

if(errors == ""){

return true;

}else{

alert(errors);

return false;

}

}

</script>


重点看服务器端的输入校验:RegisterAction中的validate方法自定义输入校验

@Override

publicvoid validate() {

//判断用户名是否输入,如果输入了再判断格式是否正确

if(username == null || "".equals(username)){

this.addActionError("自定义:用户名必须输入");

this.addFieldError("username", "用户名必须输入");

} elseif ( !Pattern.matches("\\w{6,20}", username.trim())) {

this.addActionError("用户名是字母和数字,长度在6到20之间");

this.addFieldError("username", "用户名是数字和字母在6到20之间的长度");

}

//判断密码是否输入,如果输入了再判断格式是否正确

if( password == null || "".equals(password)){

this.addActionError("密码必须输入") ;

this.addFieldError("password", "密码不能为空");

}elseif( !Pattern.matches("\\w{6,20}", password.trim())) {

this.addActionError("密码必须是字母和数字,长度为6到20之间");

this.addFieldError(
4000
"password", "密码必须是字母和数字长度6到20");

}

//判断确认密码是否输入,如果输入了再判断格式是否正确

if(repassword == null || "".equals(repassword)){

this.addActionError("确认密码必须输入") ;

this.addFieldError("repassword", "确认密码不能为空");

}elseif( !Pattern.matches("\\w{6,20}", repassword.trim())) {

this.addActionError("确认密码必须是字母和数字,长度为6到20之间");

this.addFieldError("repassword", "确认密码必须是字母和数字,长度为6到20之间");

}

//判断确认密码和密码是否相同

if(password != null && repassword != null && ! repassword.equals(password)){

this.addActionError("确认密码和密码必须相同");

this.addFieldError("repassword", "确认密码和密码必须相同");

}

//判断年龄是否合法

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

this.addActionError("请输入有效的年龄");

this.addFieldError("age", "请输入有效的年龄");

}

//判断出生日期是否合法

Calendar start = Calendar.getInstance();

Calendar end = Calendar.getInstance();

start.set(1900, 1,1);

end.set(2010, 1,1);

if(birthday != null && ( birthday.after(end.getTime()) || birthday.before(start.getTime()))) {

this.addActionError("请输入有效的出生日期");

this.addFieldError("birthday", "请输入有效的出生日期");

}

//判断邮箱地址是否合法

if(email != null && !"".equals(email) && email != "" && !Pattern.matches("[a-zA-Z][a-zA-Z0-9._-]*@([a-zA-Z0-9-_]+\\.)+(com|gov|net|com\\.cn|edu\\.cn)", email)){

this.addActionError("请输入正确的邮箱地址");

this.addFieldError("email", "请输入正确的邮箱地址");

}

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

}


在strut.xml中配置action,注册页面,输入校验后结果如下:



注意观察注意Register.jsp运行后打印出了放在actionError中的错误信息。FildError中的错误信息没有打印。

修改Register.jsp如下:

<body>

<!-- 显示actionerror:服务端校验错误

<s:actionerror/>

-->

<s:form action="register2">

<s:textfield name="username" label="username"></s:textfield><br/>

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

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

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

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

<s:textfield name="email" label="email"></s:textfield><br/>

<s:textfield name="salary" label="salary"></s:textfield><br/>

<s:textfield name="url" label="url"></s:textfield><br/>

<s:textfield name="regStr" label="regStr"></s:textfield><br/>

<s:submit value="提交"></s:submit>

</s:form>


再次运行结果如下:



这里用了strus2 的标签库,就打印出了输入校验的错误的信息,还打印了类型转换错误的信息“birthday类型转换错误”(这里自定义了类型转换错误信息,如何自定义请见下面的讲解。如果你没有这样写,错误信息会是invalid birthday …类似的形式),所以用struts的标签库给我们提供了很多方便的功能。学习struts2标签库请见我的文章struts2标签库详解。

注意:

4.1 addActionError与addFieldError

•    在前面介绍了使用actionError来保存输入校验错误提示信息。actionError其实就是一个ArrayList,将错误信息保存在actionError中,其实就是保存在一个ArrayList中。前面曾讲过类型转换的错误信息是保存在fieldError中,同样输入校验的错误信息也可以通过addFieldError方法来保存到fieldError中。fieldError和actionError不同的是,fieldError是采用Map结构来存储的,所以都是以键值对来保存信息。

•    那到底是使用fieldError来保存错误提示信息还是使用actionError好呢?这个就依据项目具体要求而定了,如果只是希望在页面中单纯的显示错误提示信息,可以使用actionError来保存错误提示信息;如果希望在相应的文本框中显示错误提示信息,则需要使用fieldError来保存错误提示信息。

•    下面来看如何将错误提示信息保存到fieldError中。首先可以使用addFieldError方法来替代addActionError方法,从而将错误提示信息保存到fieldError中。其中addFieldError方法中包含两个参数,第一个参数用来输入参数名(也可以说是Action中属性名或者说是表单元素中的name属性值),第二个参数用来输入校验错误提示信息。

 

本例中通过在validate方法中使用addFieldError来添加了错误信息。如果你没有这样做,将没有错误信息显示字输入页面上。

4.2 输入校验与类型转换的关系

观察运行结果页面知道,打印了两类错误信息,一类是输入校验错误信息,如:“用户名是数字和字母在6到20之间的长度”,“密码不能为空”等等,一类是类型转换错误信息,如“birthday类型转换错误”。这两者是何关系了。

         》用户提交数据后,首先会调用类型转换器来进行类型转换。如果转换失败,则会将错误信息保存到fieldError中,然后不管类型转换成功失败与否,都会进行输入校验,如果校验错误的话则将错误信息保存到fieldError或actionError中。最后系统判断actonError或fieldError中是否存在错误信息,如果存在,页面将跳转到啊input对应的视图资源处将错误信息打印处理。所以最后会显示出两类错误信息。

如何处理好类型转换的错误信息和输入校验的错误信息呢?记住一点:类型装转换对数据的格式进行校验,输入校验对数据的取值进行校验。

4.3 自定义类型转换错误信息

》定义局部类型转换错误信息

在对应的Action目录下定义ActonName.propertier资源文件,与定义局部类型转换器非常相似。资源文件内容如下

invalid.fieldvalue.属性名=自定义类型转换错误信息

》定义局部类型转换错误信息的中英文资源文件

分别在对应的Action目录下添加ActionName_en_US.properties和ActionName_zh_CN.properties资源文件,内容如下

invalid.fieldvalue.属性名=自定义中(英)文的类型转换错误信息

 

5 对自定义action处理方法的校验

Action默认的处理方法为execute。默认的校验方法为validate方法

》这里我们自定义处理方法myExecute,在action中指定method属性为myExecute,如何校验这个自定的这个处理方法了,只需要定义validateMyExecute方法即可,在validateMyExecute,Myexecute,validate,execute方法中分别只简单大打印一句话。运行观察控制台输出如下:



如果在action中定义validateExecute方法呢,method属性为默认值,运行:



可见,不管是对execute还是自定义的action处理方法。validate方法总会执行,自定的输入校验方法优先执行,执行顺序如图。这样做有什么意义了。

》自定义校验方法对自定义的处理逻辑方法进行校验。且validate的校验总会执行。

》struts2 允许在包含多个处理器(execute方法和自定义的execute方法),对多个处理器可分别定义其校验方法。只有当多个Action中接受的用户参数相同时,才可以考虑将多个action放到一个action中。例如在同一个表单中,为同一批请求数据,再action中可以调用不同的方法来处理。

》可以将处理逻辑中相同的校验代码放在validate方法中。不同的校验代码则放到对应的validate……()方法中。

6 struts2输入校验流程

》用户提交请求数据,客户端校验,提交数据到服务器端

》类型转换器负责将用户提交的数据进行类型转换,并将类型转换的值赋值到action中的相应属性长,如果有错误struts2将自动调用conversionError拦截器将类型转换错误信息保存到fieldError中

》不管类型转换失败与否都会执行validate……(),validate()校验方法。如果有错误则将错误信息保存到actionError或fieldError中。

》自动判断actionError或fieldError是否为空。如果不为空,则表示有错误提示信息,自动跳转到input对应的逻辑视图资源。否则执行action中的处理逻辑方法:execute或自定义的execute方法。处理完成后根据结果处理值跳转到对应的逻辑视图资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struts 输入校验