程序中验证分为:
服务器端验证(ActionForm)
客户端验证(js)(测试人员会绕过js验证),因为Action是业务控制器,所以主要的后台验证应该在ActionForm中。
Struts的校验主要有:
1、ActionForm的代码校验;
2、Action的代码校验,因为Action是业务控制器,所以后台主要还是在ActionForm中;
3、结合commons-validatot.jar的动态校验;
ActionForm验证:
思想:
ActionForm校验是最基本的校验方式,这种校验方式主要是通过重写ActionForm中的validate方法,在该方法内对所有的字段进行基本校验,如果出现不符合要求的输入,则将出错提示封装在ActionError对象里,最后将多个ActionError组合成ActionErrors对象,该对象里面封装了全部的错误提示;
1、首先在struts-config.xml中配置;
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="personForm" type="org.lxh.forms.LoginForm"></form-bean> </form-beans> <action-mappings> <action path="/login" name="personForm" type="org.lxh.action.LoginAction" input="/login.jsp"> <forward name="success" path="/success.jsp" /> </action> </action-mappings> <!-- 相当于ResourceBundle.getBundle("myResource", Locale.getDefault()); --> <message-resources parameter="myResource"></message-resources> </struts-config>
说明:
在使用ActionForm的校验时,应为对应的Action元素增加input属性,该属性指定当校验失败后的返回页面,否则不通过;
login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %> <%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <title>Insert title here</title> </head> <body> <html:errors property="errorName" /> <html:form action="login.do" method="get"> <bean:message key="name" /><html:text property="userName"></html:text> <html:submit value="登陆"></html:submit> </html:form> </body> </html>
说明:
在jsp页面使用<html:errors />标签输出出错提示,但是出错提示并没有采用硬编码的方式直接定义,而是使用资源文件的key,这样可以实现出错提示的国际化;
myResource_zh_CN.properties:
name=\u7528\u6237\u540D\uFF1A error.name={0} please login again!
LoginForm.java:
package org.lxh.forms; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; /** * @author xudongwang 2011-5-5 * */ public class LoginForm extends ActionForm { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if (userName == null || userName.trim().equals("")) { errors.add("errorName", new ActionMessage("error.name", "<font color='red'>用户名为空! </font>")); } return errors; } }
说明:
1、errorName为jsp页面上<html:errors property="errorName" />的属性值
2、error.name为资源文件中的key
3、<font color='red'>用户名为空!</font>表示在资源文件中key为error.name的第一个参数
4、validate方法中应该不涉及到相应的业务逻辑判断,在实际中经常用于判断ActionForm的属性值是否为空,长度是否符合要求等等;
总结:
因为ActionErrors和ActionError都是Struts不再推荐使用的类,因此,应该尽量避免使用这种校验方式;
Action验证:
在Action里完成校验实际上就是在execute方法的前面增加数据校验的部分代码,如果通过校验,则开始调用业务逻辑,所以说Action中的校验较为灵活,但是有如下几个不便之处:
用户需要书写大量的校验代码,使程序变得繁琐;
数据校验应该在填充ActionForm里完成,最好能在客户端完成校验,而不是推迟到Action里才完成数据校验;
在实际开发中,这种校验方式不仅程序开发复杂,且性能也不高;
Struts动态验证
借助于commons-validator.jar的支持,Struts的校验功能非常强大,几乎不需要书写任何代码,不仅可以完成服务器端校验,同时还可以完成客户端校验,即基于javaScript的校验
使用commons-validator.jar校验框架时,有如下几个通用配置:
增加校验资源
利用ValidatorPlugin加载校验资源
ActionForm使用ValidatorForm的子类
动态验证:
1、将ActionForm改为:
public class UserForm extends ValidatorActionForm { private String userName; private String password; private String age; private String job; private String birth; private String email;
说明:
1、注意这里继承的是ValidatorActionForm而不是ValidateActionForm
2、如果使用ValidatorActionForm,则在validation.xml的<form name="/user">中的name必须写为struts-config.xml中action的path属性;
3、如果使用ValidateActionForm,则在validation.xml的<form name="UserForm">
4、注意这里的日期和年龄用Stirng
5、继承ValidatorActionForm是因为这个类下有属性ActionErrors和方法addActionErrors
2、将Struts中的核心包下的validator-rules.xml拷贝到web-inf下
3、添加validation.xml:
<!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <!-- 这个文件属于该项目的校验文件 --> <form-validation> <!-- formset说明可以对多个表单进行验证 --> <formset> <!-- form这里说明是对userForm表单进行验证 --> <form name="/user"> <!-- field说明是对form表单下的userName字段进行验证 --> <field property="userName" depends="required"> <!-- <arg0 key="username"/> --> <arg key="username" position="0"/>//其中的position为资源文件中的{n} </field> <field property="password" depends="required,minlength,maxlength"> <!-- 首先先检验是否为空,然后再一级一级向下检验 --> <!-- <arg key="password" position="0"></arg>中默认就有name=required --> <arg key="password" position="0"></arg> <!-- resource为false表示使用自己定义的var范围,而如果为ture,则使用validator-rules.xml中默认的var --> <arg name="minlength" key="${var:minlength}" resource="false" position="1"/> <arg name="maxlength" key="${var:maxlength}" resource="false" position="1"/> <var> <var-name>minlength</var-name> <var-value>2</var-value> </var> <var> <var-name>maxlength</var-name> <var-value>6</var-value> </var> </field> <field property="age" depends="required,integer,intRange"> <arg key="age" position="0"></arg> <arg name="intRange" position="1" key="${var:min}" resource="false" /> <arg name="intRange" position="2" key="${var:max}" resource="false" /> <var> <var-name>min</var-name> <var-value>1</var-value> </var> <var> <var-name>max</var-name> <var-value>150</var-value> </var> </field> <field property="job" depends="required"> <arg key="job" position="0"/> </field> <field property="birth" depends="required,date"> <arg key="birth" position="0"/> </field> <field property="email" depends="required,email"> <arg key="email" position="0"></arg> </field> </form> </formset> </form-validation>
说明:
1、该配置文件为用户自定义配置文件,是该项目的校验文件,负责定义每个表单域必须满足的规则,以及规则的详细说明
4、struts-config.xml,在action中添加
<!-- validate="true"找到这里说明会去找配置规则 --> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="userForm" type="org.lxh.forms.UserForm"></form-bean> </form-beans> <action-mappings><!-- input属性为当检校失败后返回的页面 --> <!-- validate="true"找到这里说明会去找用户自定义的配置进行验证 --> <action path="/user" name="userForm" type="org.lxh.action.UserAction" input="/user.jsp" validate="true" scope="request"> <forward name="success" path="/success.jsp" /> </action> </action-mappings> <!-- 相当于ResourceBundle.getBundle("myResource", Locale.getDefault()); --> <message-resources parameter="myResource"></message-resources> <!-- plug-in加载验证资源文件是固定的格式 --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" /> </plug-in> </struts-config>
说明:
1、注意其先后顺序,如果出错了,看看Eclipse提示的信息说的先后顺序
2、这里需要指定如果不满足校验规则时,系统将返回到哪个页面,即input属性值,同时还要增加validate="true"属性
3、标签plug-in加载验证的资源文件和自定义的资源文件,其是固定的
5、myResource.properties:
username=\u7528\u6237\u540D password=\u5BC6\u7801 age=\u5E74\u9F84 job=\u5DE5\u4F5C birth=\u51FA\u751F\u65E5\u671F email=\u90AE\u4EF6 errors.required={0} \u4E0D\u80FD\u4E3A\u7A7A\uFF01\uFF01\uFF01 errors.maxlength={0}\u957F\u5EA6\u6700\u957F\u4E3A{1} errors.minlength={0}\u957F\u5EA6\u6700\u77ED\u4E3A{1} errors.integer={0}\u5FC5\u987B\u4E3A\u6574\u6570\uFF01 errors.range={0}\u4ECE{1}\u5230{2} errors.email={0}\u683C\u5F0F\u4E0D\u6B63\u786E\uFF01 errors.date={0}\u683C\u5F0F\u4E0D\u6B63\u786E\uFF01
在Eclipse中可以通过properties中的自带的编译器
6、UserAction.java:
package org.lxh.action; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.lxh.forms.UserForm; public class UserAction extends Action { @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { UserForm userForm = (UserForm) form; System.out.println("用户名:" + userForm.getUserName() + ",年龄:" + userForm.getAge() + ",邮箱:" + userForm.getEmail()); return mapping.findForward("success"); } }
common-validate中常用的校验规则有如下几种:
required:必填
validwhen:必须满足某个有效条件
minlength:输入必须大于最小长度
maxlength:输入必须小于最大长度
mask:输入匹配正确的正则表达式
byte、short、integer、long、float、double:表示只能输入特定类型的变量
date:输入必须是一个日期
intRange:输入的数字必须在整数范围内
floatRange、doubleRange
email:输入的必须是有效的email地址
url:输入的必须是有效的url地址
添加客户端验证:
1、在form元素增加onsubmit="return validateXxxForm(this);"属性,其中的XxxForm就是需要校验的form名,也struts-config.xml中配置的form-bean的name属性一致,也与validation.xml文件中需要校验的form的name属性一致;
2、增加<html:javascript formName="XxxForm"/>其中XxxForm是需要校验的form名
jsp页面代码如下:
<html:javascript formName="loginForm"/> <html:form action="login.do" onsubmit="retrun validateLogin(this)"> <html:text property="username"></html:text> </html:form>
这样就可以增加javaScript校验,注意的是即使使用了javaScript校验,也不要删除页面的html:errors标签,因为该标签会在客户端校验通过,而在服务器端校验并未通过时输出提示,同时例如密码和重复密码两个输入框的输入不相同,但javaScript校验提示并为弹出,这是因为,并不是所有的校验规则都可以“转换”客户端的javaScript校验语法
ValidateForm: 基于Form name的校验
ValidateActionForm:基于Form path的校验
ValidatorForm ValidatorActionForm 区别收藏
注意DynaValidatorform(Validatorform)和DynaValidatorActionform(ValidatorActionform)的区别。前者主要的视角是formbean,而后者的视角是action。当formbean被不同的action使用时,对于不同的action而言,使用的formbean的属性集合有大有小。此时如果仍然以formbean为主体,会造成其他action的不正常使用。因此,struts中提出了DynaValidatorActionform(ValidatorActionform)。此时在validation.xml中的form标签的name属性改为action的path属性,又由于action中有attribute和name属性,validation框架就可根据这个action得到对应的formbean。例子:
<formset> <form name=/createAddress> <field property=city depends=required> <arg0 key=prompt.city/> </field> </form> <form name=/editAddress> <field property=state depends=required> <arg0 key=prompt.state/> </field> </form> </formset>
首先,struts的actionServlet接收到一个请求,然后根据struts-config.xml的配置定义到相应的mapping(映射);接下来如果form的范围是request 或者在定义的范围中找不到form创建一个新的form实例;取得form实例以后,调用器reset()方法,然后将表单的参数放在form中,如果validate的属性不为fasle;调用validate()方法;如果validate()返回非空的actionerror,将会转到intput属性指定的url,如果返回空的actionerror,那么执行action的execute()方法,根据返回的actionForward确定目标url;