JavaEE高级框架学习笔记(七)Struts高级ActionForm

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框架打下基础。

上一篇:编译wxWidgets


下一篇:centos mysql 安装