0.前言
学习过Struts的基本流程,如配置文件、Action、ActionForm等。这里和普通Action的区别就是,在配置文件中,多了一个作用域——scope,可以选择request、session。学会认识这二者的区别,对于项目的开发有着重要意义。
1.request
1.1第一次生成表单
当scope选择request的时候,以登录页面为例,第一次生成login.jsp生成表单的时候,系统会先调用ActionForm的构造方法——reset方法——getAccount方法(这里也解释了为什么当ActionForom没有写出表单元素的JavaBean会导致报错了,因为系统运行之后需要调用这个方法,没有这个方法自然就报错了。当然了,如果表单元素里面给了value,就不会调用这个方法了)
1.2提交表单
当表单被提交,系统会自动调用构造方法——reset方法——setAccount方法——validate方法
这里表示把提交的数据,传入了ActionForm之中。(validate方法是进行前端验证的)
当Action获得ActionForm的数据后,再次跳转到login.jsp,系统还是会调用以上流程,不过会多一步——getAccount,这就是与传统的表单提交不同之处。
这里就是request的作用了,当请求跳转过一次之后,系统会在request的范围之内查找getAccount,然后填充进入表单。
总之,当scope的值设置为request的时候,表单的生成和跳转都会重新生成构造方法。
2.session
2.1 第一次生成表单
构造方法——reset方法——setAccount方法——validate方法。
表单跳转后
getAccount方法——reset方法—— setAccount方法—validate方法。
session是不会重新生成构造方法的,即生成对象后会保存在session之内。
3. ActionForm应用:表单跨页
3.1 问题描述
两个表单,第一个表单内填写账号密码,提交到下一个表单;下一个表单内输入年龄,性别,要求把这些内容在一个ActionForm内保存。
3.2 思路
login1.jsp里面输入账号和密码,action跳转到"/toP2",在配置文件里面将“/toP2”设置为跳转到login2.jsp。login2.jsp的表单提交到LoginAction。
toP2的scope设置为session,这样达到login2.jsp页面后,不会将前一个页面的账号和密码丢掉。
3.3 实现
1.struts-config.xml:
<form-bean name="login1Form" type="Action.Login1Form"></form-bean>
<action name="login1Form" forward="/login2.jsp" path="/toP2" scope="session"/>
<action name="login1Form" path="/login1" type="Action.Login1Action" scope="session"/>
2.login1.jsp
<html:form action="/toP2">
account :<html:text property="account"></html:text><br/>
password:<html:text property="password"></html:text><br/>
<html:submit value="到达下一个页面"/><html:cancel/>
</html:form>
login2.jsp
<html:form action="/login1" method="post">
sex :<html:text property="sex"></html:text><br/>
age:<html:text property="age"></html:text><br/>
<html:submit value="提交"/><html:cancel/>
</html:form>
Login1Action.java:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Login1Form login1Form=(Login1Form)form;
System.out.println(login1Form.getAccount());
System.out.println(login1Form.getPassword());
System.out.println(login1Form.getSex());
System.out.println(login1Form.getAge());
return null;
}
Login1Form就是JavaBean风格的代码,把表单元素的getter和setter方法写上即可,这里不再贴出。
4 利用ActionForm进行前端验证
4.1 利用validate方法进行进行前端验证
如不允许用户的账号、密码、性别、年龄为空,在validate方法里面,对account.length()等属性进行验证,如果为空,则进行一定操作。
这里涉及到一个问题,表单有两个,但是ActionForm只有一个,如果在validate里面判断第一个表单的时候,那么第二个表单的数据就会引发空指针异常,因为null是没有length的。
所以在页面里面新增一个隐藏表单,property为page,value为1和2。
在validate里面,如果page.equal(“1”),则验证第一个表单里面内容,以此类推。
4.2 具体代码
Login1Form.jsp:
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
if(page.equals("1")) {
if(account.length()==0) {
System.out.println("不可以为空");
}
if(password.length()==0) {
}
}
else if(page.equals("2")) {
if(age.length()==0) {
}
if(sex.length()==0) {
}
}
return null;
}
page1.jsp:
<html:form action="/toP2">
account :<html:text property="account"></html:text><br/>
password:<html:text property="password"></html:text><br/>
<html:submit value="到达下一个页面"/><html:cancel/>
<html:hidden property="page" value="1" />
</html:form>
page2.jsp:
<html:form action="/login1" method="post">
sex :<html:text property="sex"></html:text><br/>
age:<html:text property="age"></html:text><br/>
<html:submit value="提交"/><html:cancel/>
<html:hidden property="page" value="2" />
</html:form>
5.利用索引属性的ActionForm
若一个人有三个电话号码,在页面定义三个电话的文本框,非常不合适。所以在ActionForm里面定义一个phone数组,这样输入的电话号码可以都被存入。
login2.jsp:
phone1<html:text property="phone"></html:text><br/>
phone2<html:text property="phone"></html:text><br/>
phone3<html:text property="phone"></html:text><br/>
但是这样会引发一个问题,前面提到过,无论scope是request还是session,每一次生成或者达到新的页面,都会获取getXXX方法,这里的phone是一个数组,返回在文本框里面的只有一连串的地址了。
想要解决这个问题,可以在文本框标签里面添加value="" ,这样每次返回,phone文本框的内容就是空的。可是如果想要实际解决这个问题,则需要利用ActionForm的索引属性。
5.1 索引规则
第一步:表单上元素的property为:属性名[i],i从0开始
第二步:在ActionForm中定义一个数组储存这些属性,增加set、get方法
Login1Form.java:
private String[] phones=new String[3];
public String getPhone(int i) {
return phones[i];
}
public void setPhone(int i,String phone) {
this.phones[i]=phone;
}
这里的ActionForm是固定写法, 有一定的规则。
login2.jsp:
<html:form action="/login1" method="post">
sex :<html:text property="sex"></html:text><br/>
age:<html:text property="age"></html:text><br/>
phone1<html:text property="phone[0]"></html:text><br/>
phone2<html:text property="phone[1]"></html:text><br/>
phone3<html:text property="phone[2]"></html:text><br/>
<html:submit value="提交"/><html:cancel/>
<html:hidden property="page" value="2" />
</html:form>
但是上述写法有一个缺陷,就是需要事先知道电话号码的个数。这个也不是很方便,因为现在大家完全可以在网页上通过点击+号,新增多个电话号,这样不便于动态生成个数。
不过说到动态生成,肯定就会想到的ArrayList了,ArrayList不需要指定个数,动态增长。所以可以利用ArrayList进行改进。
5.2 改进
Login1Form.java:
private ArrayList phones=new ArrayList();
public String getPhone(int i) {
if(i<phones.size()) {
return (String)phones.get(i);
}
return null;
}
/**
* @param phones the phones to set
*/
public void setPhone(int i,String phone) {
phones.add(phone);
}
public ArrayList getPhones() {
return phones;
}
login2.jsp:
<html:form action="/login1" method="post">
sex :<html:text property="sex"></html:text><br/>
age:<html:text property="age"></html:text><br/>
phone1<html:text property="phone[0]"></html:text><br/>
phone2<html:text property="phone[1]"></html:text><br/>
phone3<html:text property="phone[2]"></html:text><br/>
<html:submit value="提交"/><html:cancel/>
<html:hidden property="page" value="2" />
</html:form>
这样就可以了。
但是此法也有缺陷,就是在调用get方法的时候,因为我们存入的是ArrayList这个集合,是无法保证顺序的,所以在返回表单的时候,会发现电话号码被打乱了顺序了。
所以当我们不太关注顺序的时候,可以使用这种方法。
6.小结
ActionForm中的validate方法非常适合验证前端信息,因为当表单被提交的的时候,validate方法就被调用了。同时熟悉validate方法也是为validate框架打下基础。