动作映射
这个时候,你可能会问自己:“当控制器接受到一个请求的时候,它如何知道调用哪个Action实例?”控制器要通过查看请求消息并使用一组动作映射(action mapping)来做出决定。动作映射是Struts配置信息(配置一个特殊的XML文件中)的一部分。这个配置信息会在启动时加载到内存中,让Struts框架得以在运行时加以利用。每个action元素在内存中都被表示为org.apache.struts.action.ActionMapping类的实例。ActionMapping对象包含一个path属性,用来与外部请求的URI部分匹配。如下:
<action
path="/login"
type="com.oreilly.struts.banking.action.LoginAction"
scope="request"
name="loginForm"
validate="true"
input="/login.jsp"
<forward name="Success" path="/action/getaccountinformation" redirect="true"/>
<forward name="Failure" path="/login.jsp" redirect="true"/>
</action>
这里的登录动作映射把路径"/login"映射到了com.oreilly.struts.banking.LoginAction这个Action类。无论何时,当控制器接受到一个URI路径中包含"/login"字符串的请求时,就会调用LoginAction实例的execute()方法。Struts框架还会使用映射来指出“动作"完成后要让用户转向哪个资源。
使用Struts ActionForm
Struts框架的ActionForm对象可用来在用户和业务层之间传输客户的输入数据。Struts框架会自动从请求中收集输入数据,再将这些数据交给一个使用表单bean(form bean)的Action对象,接着表单再交给业务层。为了把表示层和业务层分离开来,你不应该直接把ActionForm对象交给业务层,而是应该使用由ActionForm对象得到的数据创建适当的DTO。下面的步骤说明了Struts框架如何处理每个请求相应的ActionForm对象:
1.检查该项动作的相应设置,查看是否已经有某个ActionForm得到配置。
2.如果对应这个动作配置了某个ActionForm,则使用action元素中的name属性来查找表单bean的配置信息。
3.查看是否已经创建了一个ActionForm的一个实例。
4.如果在适当的作用域内已经存在一个ActionForm实例,而且这个实例的类型正是这个请求所需要的类型,则重用这个实例。
5.否则,创建所需ActionForm的一个新实例,并存储在适当的作用域中(由action元素的scope属性设置)。
6.调用ActionForm实例的reset()方法。
7.反复处理请求参数,如果参数名在ActionForm实例中具有对应的设置方法(setter method),就为它填上该请求参数的值。
8.最后,如果validate属性的值设置为true,则调用ActionForm实例的validate()方法,并返回所出现的任何误。
对任何HTML页面而言,如果表单数据是以POST方法传输的,就应该使用ActionForm。必要时,相同的ActionForm可以同时给多个页面使用,只要HTML字段能和ActionForm对象的属性(property)匹配就可以了。
Struts框架所提供的ActionForm类实现了多个方法,但到目前为止,最重要的两个方法就是reset()和validate():
public void reset(ActionMapping mapping,HttpServletRequest request);
public ActionErrors validate(ActionMapping mapping,HttpServletRequest request);
在Struts ActionForm类中,这两个方法的默认实现是不完成任何的逻辑。你必须在自己的ActionForm类中覆盖这两个方法。控制器以请求中的值来填写ActionForm实例之前,会先调用reset()方法。reset()方法给了ActionForm一个机会,可将其属性设置为原来默认的状态。这一点非常重要,因为表单bean实例可能会由多个请求共享或者由好几个不同的线程所存取。不过,如果你是让好几页共享一个ActionForm实例,可能
不会去想去实现reset()方法,这样一来只要这个实例还在,属性的值就不会被重新设置。另一种做法就是实现你自己的resetFields()方法,在成功更新业务之后,就从这个Action类来调用此方法。当请求中所携带的值已经插入到ActionFrom实例之后,控制器就回调用validate()方法。ActionForm应该对输入数据完成必要的验证工作,然后向控制器返回所检测到的任何错误。业务逻辑验证应该在业务对象中而不是在ActionForm中来完成。在ActionForm中所进行的验证工作,只是表示的验证而已。一旦写好ActionForm类后,你必须通知Struts应用程序有这些ActionForm存在,告诉Struts应用程序哪个动作映射应该使用哪个ActionForm。这是在配置文件中设置的。第一步是为你的应用程序在配置文件中的form-beans段里配置所有的ActionForm。看下面的一个例子:
<form-beans>
<form-bean
name="loginForm"
type="com.oreilly.struts.banking.form.LoginForm"/>
<form-bean
name="accountInformationForm"
type="org.apache.struts.action.DynaActionForm">
<form-property name="accounts" type="java.util.ArrayList"/>
</form-bean>
</form-beans>
每个表单bean的name属性必须都是独一无二的,而且其type属性必须定义一个Java类(扩展了Struts ActionForm类)的完全限定名。下一步是在一个或多个action元素中使用在form-benas段里的某个form-bean名。如下:
<action
path="/login"
type='com.oreilly.struts.banking.action.LoginAction"
scope="request"
name="loginForm"
validate="true"
input="/login.jsp">
<forward name="Success" path="/action/getaccountinformation" redirect="ture>
<forward name="Failure" path="/login.jsp" redirect="true"/>
</action>
注意:登录动作映射的name正好和前面form-beans段里某个name属性相匹配。