用actionmapping构建漂亮的struts应用程序
在本系列指南的第四部分,你可以学习如何运用actionmapping来改进你的struts应用程序。
阅读本系列指南的前三部分:
第一部分:“你的第一个struts应用程序”
第二部分:“struts应用程序中的流程控制”
第三部分:“用actionforward优化你的struts应用程序”
邱吉尔曾经说过他喜欢学习新东西,但他觉得没有必要让别人教他。不管你是否喜欢学习新知识,也不管有人教你还是你自学,学习java通常意味着仔细研究许多特殊的类。学习struts也是如此。
这就是我写本系列第四部分的初衷,在本文中,我将详述org.apache.struts.action.actionmapping类,它是从org.apache.struts.config.actionconfig派生的。actionmapping将一个请求路径映射到一个action类,它是struts应用程序中最常用的类之一。在你深入学习这个类时,你会重新用到在该系列第1、2和3部分创建的两个login应用程序,从而了解如何运用actionmapping来重写应用程序。
当然,你可能不记得以前用过任何actionmapping实例了。这是因为控制器servlet实际上为你创建了它们。你只需要配置在struts配置文件(struts-config.xml)中创建的每个actionmapping实例就行了(通过给它的属性赋值)。了解这些属性对正确运用actionmapping类很重要,因此我将讲述这些属性以及如何定义它们。
首先,让我们回想一下,struts配置文件的根元素是<struts-config>。<struts-config>元素可以包含一个可选的<action-mappings>元素,同样<action-mappings>元素可以包含<action>元素。例如,下面就是本系列第三部分的login应用程序配置文件中的<struts-config>元素及其子元素:
<struts-config> <action-mappings> <action path="/login" type="com.javapro.struts.loginaction"/> <action path="/logout" type="com.javapro.struts.logoutaction"/> <action path="/viewsecret" type="com.javapro.struts.viewsecretaction"/> </action-mappings></struts-config> |
<action-mapping>中的每个<action>都代表控制器servlet创建的一个actionmapping实例。一个<action>元素可以包含多个特性,每个特性都和actionmapping实例中的一个属性相应。
作为例子,我们来看前面的struts配置文件中的这个<action>元素:
<action path="/login" type="com.javapro.struts.loginaction"/> |
这个<action>将路径“/login”映射到action类com.javapro.struts.loginaction。换句话说,一个以“/login.do”结尾的用户请求将被传递到loginaction类。然而,actionmapping也有其它的用途。你(struts程序员)可以通过给它的属性赋值来给actionmapping实例下达action指令。(有些属性与action forms相关,我将在本系列的第五部分讲述。)
actionmapping类的属性
actionmapping有许多属性。首先,它从actionconfig类继承了一些属性――如type、forward、include和unknown。它们与action forms是无关的。前三个属性是actionmapping类最重要的属性。你只能指定其中的一个,所以,如果一个<action>元素已经定义了一个type属性,它就不能有forward属性或include属性了。
type属性的值是路径所映射的action类的完全限定的java类的名称。(你曾在前面的login应用程序中的struts配置文件中用过这个属性。)如果运用了type属性,那么控制器servlet就可以调用action实现类的execute方法,传递恰当的actionmapping实例。注意,org.apache.struts.action.actionclass类的execute方法有如下的定义(第一个参数是一个actionmapping实例):
public actionforward execute(actionmapping mapping, actionform form, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception |
forward属性代表的是满足该请求的context-relative资源(通过调用requestdispatcher.forward()),而不是实例化type属性指定的action类。(更多关于如何运用这个属性的信息,参见后面的‘修改login应用程序’部分。)
我们给include属性赋的值是满足该请求的context-relative资源路径(通过调用requestdispatcher.include()),而不是实例化type属性指定的action类。
注意,<action>元素包含的forward属性与可能出现在<action>元素下的<forward>元素是不同的。这就是说,一个<action>元素可以有一个type属性,以及一个或多个<forward>子元素,如下面这个<action>元素所示(我马上会讲述<forward>元素):
<action path="/login" type="com.javapro.struts.loginaction"> <forward name="success" path="/mainmenu.jsp"/> <forward name="failure" path="/login.jsp"/> </action> |
我们用<path>属性来指定这个actionmapping将处理的请求路径。最后,用unknown属性来处理未知的路径。在一个action元素中,将这个属性设置为true,使这个action成为该应用程序缺省的action。换句话说,它处理所有其它的action不能处理的请求。在一个单独的应用程序中,只有一个action可以被定义成是缺省的。
例如,下面这个<action>元素将unknown属性设置为true,使该action成为缺省的:
<action path="/login" type="com.javapro.struts.loginaction" unknown="true"/> |
<forward>元素
<forward>元素描述了一个逻辑名称与一个context-relative uri路径识别的资源之间的映射。它有以下这些属性:
| ? classname 这是你想运用的actionforward实现类的完全限定的java类的名称。缺省情况下,它的值是作为“forward”初始化参数给struts控制器servlet配置的。 |
| ? contextrelative 在一个模块化应用程序中,如果路径属性是以一个斜线(“/”)开头的,并且是相对于整个web应用程序的,而不是相对于该模块的,我们就将这个属性设置为true。缺省情况下是false。 |
| ? name 这是forward的唯一标识符,用来在应用程序的action类中引用它。 |
| ? path 被映射资源的context-relative路径。 |
| ? redirect 设置成true,运用sendredirect()引导到该资源;或者设置成false,运用requestdispatcher.forward()作为替代。 |
运用<action>下的<forward>元素意味着你不必在你的actionforward对象中写死路径名。例如,我们来看前面的login应用程序中loginaction类的execute方法中的代码:
public actionforward execute(actionmapping mapping, actionform form, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception { string username = request.getparameter("username"); string password = request.getparameter("password"); if (username!=null && password!=null && username.equals("john") && password.equals("123")) { httpsession session = request.getsession(); session.setattribute("loggedin", "1"); return (new actionforward("/mainmenu.jsp")); } else { return (new actionforward("/login.jsp")); }} |
注意,最后的两个return语句写死了mainmenu.jsp和login.jsp页面。如果任意一个文件名发生改变,你都必须重新编译loginaction类。但是如果你用<forward>元素,你可以用一个名称映射mainmenu.jsp页面,用另一个名称映射login.jsp页面。现在,如果你需要改变文件名,你就可以在配置文件中进行改变,而不需要重新编译了。要这么做,你需要在struts-config.xml文件中声明这个<action>元素:
<action path="/login" type="com.javapro.struts.loginaction"> <forward name="success" path="/mainmenu.jsp"/> <forward name="failure" path="/login.jsp"/> </action> |
现在,mainmenu.jsp就与“success”这个名称联系在一起了,login.jsp与“failure”联系在一起了。你可以通过调用actionmapping类的findforward方法,传入相关的名称从一个action实现类的内部得到actionforward实例:
mapping.findforward(name); |
例如,要得到包含路径“/mainmenu.jsp”的actionforward对象,我们可以用下面的方法:
mapping.findforward("success"); |
同样,要得到包含路径“/login.jsp”的actionforward对象,可以用:
writemapping.findforward("failure"); |
接下来,我们该用<forward>方法重写login应用程序了。
修改login应用程序
注意,你在第三部分创建的login应用程序发生了怎样的变化。首先,我们来看原应用程序中viewsecretaction类的execute方法:
public actionforward execute(actionmapping mapping, actionform form, httpservletrequest request, httpservletresponse response) throws ioexception, servletexception { return (new actionforward("/viewsecret.jsp")); } |
除了返回一个路径是“/viewsecret.jsp”的actionforward对象外,该execute方法没有做任何的处理。通过运用struts-config.xml文件中<action>元素的forward属性,我们就不需要viewsecretaction类了。要实现这一点,我们可以将下面的<action>代码:
<action path="/viewsecret" type="com.javapro.struts.viewsecretaction"/> |
替换成:
<action path="/viewsecret" forward="/viewsecret.jsp"/> |
现在,我们就用forward属性替换了type属性。然后,通过添加unknown属性并将它设置成true,我们就可以使login页面成为缺省的页面。实际上,任何未知路径(以.do结尾)都会被引导到loginaction实例。处理“/login”的<action>元素如下所示:
<action path="/login" type="com.javapro.struts.loginaction" unknown="true"> |
对loginaction和logoutaction类所做的最后的修改运用了actionmapping类的findforward方法来得到适当的actionforward对象。在struts-config.xml文件中声明映射(见列表1)。另外,我们也来看看修改过了的loginaction类(见列表2)和修改过了的logoutaction类(见列表3)。
注意,该版本运用了很少的action实现类,因为我们不再需要viewsecretaction了。另一个好处是:这种方法避免了在action实现类中写死路径名。另外,/login路径现在是缺省的了。结果就是:你的struts代码最终看上去像一个真正的struts应用程序了。你在学习了第五部分(关于action forms)后,这个程序会变得更好
闽公网安备 35060202000074号