第五章 struts动态ActionForm,struts数据校检,stuts中的Token(令牌),struts异常处理
struts动态ActionForm
1)什么是动态ActionForm
动态ActionForm是struts从1.1版本开始引入一项新的技术,即在创建ActionForm时
可以不用通过编程的方式而只要通过struts-config.xml文件中进行配置,以后在 struts运行时,会自动根据struts-config.xml中配置的DynaActionform来生成一个
Action实例
2)为什么要使用DynaActionform
很显然随着应用程序的变大,数百个ActionForm 这样不仅编程起来麻烦,以后维护 起来也麻烦,比如:某个属性变化了,则需要修改源代码,然后重新编译,但是如果
使用DynaActionform则只需要修改struts-config.xml配置文件就行了。这样提高了
应用程序的开发效率与应用程序的可维护性
3)如何使用DynaActionform
1)在struts-config.xml中创建一个DynaActionform
<form-beans >
<form-bean name="dynaActionForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="num1" type="java.lang.String"/>
<form-property name="num2" type="java.lang.String"/>
</form-bean>
</form-beans>
2)从上面的配置可以看出,动态ActionForm的配置必须增加forms-property元素
且每个forms-property包含两个属性
A:name 属性的名字,该属性必须与jsp页面的表单元素的名字一致
B:type 属性的类型。强烈建议把类型都设置为String,以后在Action中再去转换
C:类型不能直接写String一定要写上java.lang.String
D:动态ActionForm的type必须要写org.apache.struts.action.DynaActionForm
它是struts中内置的一个用于创建动态ActionForm的一个父类
3)如何使用DynaActionForm
在与之对应的Action中的Excute中写上代码,然后通过其get方法就行了
DynaActionForm frm=(DynaActionForm)form; //取出动态ActionForm
frm.get("在struts-config.xml为动态Action配置的属性名");
比如:
int num1=Integer.parseInt(frm.get("num1").toString());
String userName=frm.get("userName").toString();
double price=Double.parseDouble(frm.get("price").toString());
4)通过"initial"给DynaActionForm增加默认值:
<form-bean name="dynaActionForm" type="org.apache.struts.action.DynaActionForm">
<form-property initial="1" name="num1" type="java.lang.String"/>
<form-property initial="2" name="num2" type="java.lang.String"/>
</form-bean>
5)如何在DynaActionForm中配合checkBox使用数组属性:
A:配置:
<form-bean name="dynaActionForm" type="org.apache.struts.action.DynaActionForm">
<form-property name="love" type="java.lang.String[]"/>在String后面加上"[]"
</form-bean>
B:使用:
DynaActionForm frm=(DynaActionForm)form;
String love[]=frm.getStrings("love");//通过getStrings方法会返回一个数组
6)什么时候用动态ActionForm。实事上配置动态ActionForm的工作量与通过MyEclipse去生 成一个ActionForm的工作量相当。所以如果一个表单中只有一到两个元素需要传值则考虑
DynaActionForm,但是如果超过两个以上时,建议还是使用ActionForm
举例:
1)使用动态ActionForm来求出让用户输入两个数与一个操作符来求出运算结果
注意在同一个页面中显示结果,注意操作符使用单选按钮,并提供默认值.
2)使用动态ActionForm实现商品的添加功能。注意使用oracle中触发器与sequences
实现自动编号功能
CREATE TABLE table1
(id NUMBER PRIMARY KEY,
username VARCHAR2(50)
);
--建序列
CREATE SEQUENCE table1_seq
START WITH 1
INCREMENT BY 1
--建触発器
CREATE OR REPLACE TRIGGER table1_tg
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
SELECT table1_seq.NEXTVAL INTO :NEW.id FROM DUAL;
END;
--執行
INSERT INTO table1 (username) VALUES ('張三');
3)使用dynaActionForm配合checkbox实现让用户选择商品类型,查询出对应的
商品,然后用户选择商品,求出应付款
struts数据校检
1)struts数据的检验分成客户端检验与服务器检验。客户端检验是避免用户输入非法的的数据
而服务器端检验通常是把用户输入的正确数据与数据库的数据进行对比,然后依然业务逻辑 进行检验
2)如果要进行服务器端检验可以在Action中进行,如果要进行客户端检验则可以利用
js或struts中的commons-validator的检验框架进行检验
3)利用commons-validator的检验框架的步骤:
A:编写一个ActionForm,此ActionForm类由于参与commons-validator的检验框架所以一定 要继承自org.apache.struts.validator.ValidatorForm,注意不是 org.apache.struts.validator.DynaValidatorActionForm;
B:去掉该ValidatorForm中自动生成的validate,和reset方法(一定要去掉否则不会生效)
C:在WebRoot下面找到validator-rules.xml文件,打开。把其中的
<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.xml到文件的message-resources节点下面
<message-resources parameter="aptech.hotelManager.struts.ApplicationResources" />
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
D:把validator-rules.xml文件中下面内容复制到ApplicationResources.properties里面
# Struts Validator Error Messages
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.
errors.byte={0} must be a byte.
errors.short={0} must be a short.
errors.integer={0} must be an integer.
errors.long={0} must be a long.
errors.float={0} must be a float.
errors.double={0} must be a double.
errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.
errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.
E:如果想转换成为中文,可以利用native2ascii -encoding gb2312 源文件进行转换
但是关键字与参数一定不要变动
F:在Action元素中增加validate="true" 与input="/检验末通过的目的页面"
F:编写validation.xml文件,该文件一定要放在WebRoot下面
<?xml version="1.0" encoding="UTF-8"?>
<!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> //这里面可以放置多个ActionForm
<form name="ruleActionForm"> //ActionForm的名字,此名字一定要与struts-config中定义的文件名一致
<field property="uid" depends="required,maxlength">//要检证的字段名,depends指定要检验的检验器
//检验器可以有多少之间用逗号隔开
<arg0 name="required" key="用户名" resource="false"/>
<arg0 name="maxlength" key="用户名" resource="false"/>
<arg1 name="maxlength" key="5" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>5</var-value> 说明:
</var> A:arg0..argn用来给末通过检验时的出错信息提供参数值,该出错信息将 使用默认的validator-rules.xml中定义的错误信息。如果想要自己定 义错误信息可以使用msg格式。比如:<msg name="检验器名" key="出 错信息 resource="false"/>
</field> B:name:用来指定该参数将对应的那个检验器,一定要与检验器同名
</form> C:key:用来指定参数的值,resource="false"说明不通过资源文件 直接指定值
</formset> D:var用来为检验器指定检验的规则,大多数检验器都需要用户自己定义
规则
</form-validation> E:其中的var-name一定要与检验器同名,var-value用来指定规则值
F:<arg>参数可以省略name属性此时多个检验器共享arg中提供的参数值
比如:
<field property="uid" depends="required,mask">
<arg0 name="required" key="用户名" resource="false"/>
<arg0 name="mask" key="用户名" resource="false"/>
可以改成:
<field property="uid" depends="required,mask">
<arg0 key="用户名" resource="false"/>表示当
required检验失败时,会把"用户名"填充{0}
errors.required={0} is required
而mask检验指失败时,同样会把"用户名"填充{0}
errors.invalid={0} is invalid
G:常见的检验器:
1:required必填。出错提示对应于errors.required={0} is required
不需要用户指定检验规则,一般配置如下
<field property="uid" depends="required">
<arg0 name="required" key="用户名" resource="false"/>
2:mask。正则表达式。出错提示对应于errors.invalid={0} is invalid.
需要用户指定检验规则,一般配置如下
<form name="ruleActionForm">
<field property="uid" depends="required,mask">
<arg0 name="required" key="用户名" resource="false"/>
<arg0 name="mask" key="用户名" resource="false"/>//指定出错信息
<var> //指定规则,注意规则名一定要写mask
<var-name>mask</var-name>
<var-value>^[a-zA-Z0-9]{5,8}$</var-value>
</var>
</field>
</form>
3:email。检查邮箱。出错提示对于 errors.email={0} is an invalid e-mail address
不需要指定检验规则。一般配置如下
<field property="email" depends="required,email">
<arg0 name="required" key="邮箱" resource="false"/>
<arg0 name="email" key="你输入的邮箱" resource="false"/>
</field>
4:intRange。检查一个数在某个范围之内。出错提示对应于:errors.range={0} is not in the range {1} through {2}
需要用户指定规则。由于规则中涉汲到有多个值,所以需要用${var:变量名}的 形式进行分别指定。一般配置如下:
<field property="age" depends="intRange">
<arg0 name="intRange" key="年龄" resource="false"/>
<arg1 name="intRange" key="${var:max}" resource="false"/>
//${var:max}表示引用规则中的值。也可以直接写成
//<arg1 name="intRange" key="50" resource="false"/>
<arg2 name="intRange" key="${var:min}" resource="false"/>
<var> //规则名一定要与max与min。
<var-name>max</var-name>
<var-value>50</var-value>
</var>
<var>
<var-name>min</var-name>
<var-value>20</var-value>
</var>
</field>
5:validwhen。validwhen主要用于关联验证,即为了验证某个域的值,可能会参考其它域的值 来进行综合判断,以确定该域的值是否符合要求.出错提示对应errors.required={0} is required.
需要用户指定规则.一般配置格式:
<field property="surePwd" depends="validwhen">
<msg name="validwhen" key="两次输入的密码必须一致" resource="false"/>
<var>
<var-name>test</var-name>
<var-value>(*this*==pwd)</var-value>
</var>
</field>
说明:
1)在此使用<msg>用来自定义出错信息。因为默认情况下validwhen对应的出错信息是 errors.required={0},不能表达错误提示信息,
2)<msg>中的name表示检验器名,key表示自定义的出错信息,resource="false"表示不
从资源文件中加载错信息
3)输入给validwhen的是一个布尔型表达式(对该表达式的解析使用了antlr),其引用名为 test,即形如:
<var>
<var-name>test</var-name>
<var-value>(expression)</var-name> //注意表达式一定要加括号
</var>
即,当expression为真(true)时,该域验证通过,其中,expression可以使用的元素包括:
A:表单中其它域属性的名称,例如:
<var>
<var-name>test</var-name>
<var-value>(color=="red")</var-name>
</var>
例子中color为表单中其它某个域的属性名。
B:*this*,用于表示该域的属性名称,即对正在验证的属性自身,其变量的引用为*this*
C:可以使用一些常规运算符,如 >、<、==、>=、<=、!=、+、-、*、/、%等等
6:date。判断是否是合法的日期.出错提示对应于errors.date={0} is not a date。需要自己定义规 则.一般配置格式:
<field property="dtm" depends="date">
<arg0 name="date" key="日期" resource="false"/>
<var>
<var-name>datePatternStrict</var-name> //规则名一定要是datePatternStrict
<var-value>yyyy-MM-dd</var-value>
</var>
</field>
H:如何显示错误信息:
<logic:messagesPresent> //如果存在错误
<html:messages id="error">//依次遍历每个错误
<li><bean:write name="error"/></li>
</html:messages>
</logic:messagesPresent>
H:让struts在客户端进行验证:
A:为jsp中的form元素增加onsubmit="return validate.XxxForm(this);"其中的XxxForm就是在
struts-config.xml中配置的ActionForm的名字
B:在</html:form>的后面增加<html:javascript formName="xxxForm" />
C:但是validwhen不支持在客户端进行验证
应用举例:
1)让用户填写一个注册页面。
2)用两种方法
A:弹出对话框
B:直接在注册页面的上面来显示末通过的提示
通过stuts中的Token(令牌)阻止页面重复提交
1)原理:
当客户端每次请求一个页面之前,服务器端会产生一个令牌,同时把这个令牌传给客户端
之后再进行处理。处理完毕之后,马上更新旧的令牌,同时传送旧的令牌给客户端。
这样如果客户端提交表单一次之后,按IE上的后退按钮再次提交时,就会发出客户端的
令牌(因为是以前的令牌)与现在服务器的令牌不一致。通过这个就能判断是否重复提交
表单
2)步骤:
1.jsp页面放一个超链接.<a href="prepareAction.do">发表留言</a>
2)点击超链接之后跳转到prepareAction,在prepareAction里面去添加一个令牌
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
{
this.saveToken(request);
return mapping.findForward("2");//跳到2.jsp页面
}
prepareAction实际上过度作用的一个Action目的是为了添加令牌
3)在2.jsp里面一般是一个表单用来填写数据,并提交到另外一个insertTalkAction里面
实现真正的插入
<html:form action="insertTalkAction.do">
留言id<html:text property="uid"/><br>
内容<html:text property="content"/><br>
<html:submit>提交</html:submit>
</html:form>
4)在insertTalkAction里面的代码是关键代码
======================================================================================
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
{
if (this.isTokenValid(request,true)) //没有重复提交
{
Random rnd=new Random();
int n=rnd.nextInt(2000)+900;
request.setAttribute("msg", "没有重复提交,将插入数据..");
String sql=String.format("insert into emp(empno,ename) values(%d,'小上')", n);
dbManager.RunNoneResultSql(sql);
}
else //重复提交了
{
request.setAttribute("msg", "重复提交!!!!");
this.saveToken(request);
}
return mapping.findForward("msg");
}
==================================一般的格式===============================================
if (isTokenValid(request, true)) //表单不是重复提交
{
这里是保存数据的代码
}
else //表单重复提交
{
saveToken(request);
其它的处理代码
}
=============================================================================================
struts异常处理
1)当Java在执行Web应用程序的某个方法时如果遇到了异常,java就会把这种异常所产生的信息抛给客户,以便向客户通报程序在运行中出了问题。这时如果不进行异常处理,用户将会看到一大莫名的错误信息,这是一种相当不负责任的做法。为了增加Web应用程序的友好性,应该屏蔽掉这些异常所产生的错误信息,以一种更加友好的方式去提法。于是Struts异常处理就出现了
2)步骤:
A:在struts-config.xml定义全局的异常
<global-exceptions >
<exception key="errors.exception" type="java.lang.Exception" path="/ex.jsp"/>
</global-exceptions>
其中的key是在资源文件中定义的关键字。path是用来定义出现异常之后的错误
处理页面。这样当异常出现之后,会自动跳到该页面显示错误提示
B:在Action的Excute事件里面调用业务层,如果出现了异常则会自动触发
struts框架中的异常
评论