目录:
一、摘要
二、挑两个,早上呼我
三、现在,我将表格放在哪里?
四、再说一次,我们是怎样关联的?
一、摘要
建立和维护企业应用程序非常困难。而为这些应用设计出上乘的、易于维护的用户界面则是所有工作中最让人畏惧的任务。来自Apache Jakarta 项目的Struts框架为J2EE(Java2平台企业版)带来了Model 2 结构。在本文中,两位作者讨论了开发者在使用Struts 的过程中所遇到的问题,以及简化这些问题的相应方法。
除非你过去几年内潜居于石洞之中,否则你不可能没听说过Struts framework。Struts是由Apache软件基金会最初发起的开源,主要是为了促进Web应用演示层内的模型-视图-控制器(MVC)设计范例。truts 提供了使用Service的MVC模式给Worker 模式。一个设计优秀的结构总是力争耦合宽松、结合性高。Struts为在多捆绑的企业Web应用的演示层实现这个目标提供了一个机制。 实现企业应用结构所面对的最让人望而生畏的任务之一就是演示层的创建和维护。用户期望得到非常功能化的、坚固的、和优雅的灰土用户界面。因此,演示层的代码库使得应用层超负荷运行。另外,不同的显示平台如无线电话和PDAs 的出现使得原本复杂的状况更加复杂的多。
各种不同的书和文章已经讲述了Struts的内部工作原理并且教我们如何使用这个框架。本文详细阐述了使用Struts 的Web应用开发者所遇到的问题,以及如何解决这些问题。下列方法中有许多可以应用到不同的MVC框架中如即将上市的JavaServer Faces 规范。 Craig R. McClanahan,Struts的创始人之一,造就了这个规范。
本讨论的主题包括:在使用Struts框架,用BEA WebLogic Server建立J2EE(Java2平台企业版)应用的过程中出现最多问题的所有区域。我们将讨论下列专题:
?创建/维护 struts-config.xml
?表格/会话期管理
?Struts 映射和用户界面的关系
?管理Back按钮
?用户认证
?用户界面控制流程
? 异常处理
?测试
二、挑两个,早上呼我
Struts框架毫无疑问,减轻了企业应用程序的用户界面的开发和维护。但是,即使只是在一个简单的应用中使用了Struts ,开发者也会迅速的认识到struts-config.xml这个恶魔。 这个文件很有可能迅速变得难于处理。在建立企业应用时,struts-config.xml 能够多出 500个动作映射,使得自身变得真正地难于管理。
我们推荐两个工具来帮助治理这个头疼的问题。首先,使用来自Alien-Factory 的Microsoft Visio 和StrutsGUI 文档化你的用户界面流程。StrutsGUI是一个Visio 模版,它对使用Struts 术语描述用户流程图有帮助。在Struts 模版内有一个隐藏的功能:只要右键点击该项,选择Edit Title Properties,然后选择Tools项,你就能够在该图的基础上生成struts-config.xml 文件。例如,图1中显示的简单应用生成了如下列代码所示的struts-config.xml :
Figure 1. StrutsGUI model. Click on thumbnail to view full-size image.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- Struts Config XML - Sample Struts App -->
<!-- ===================================== -->
<!-- AutoGenerated from : c:\dev\javaworld\app\sample.vsd -->
<!-- AutoGenerated on : 02-18-2003 23:05:47 -->
<!-- AutoGenerated by : Struts GUI v2.11 (c)2002 Alien-Factory -->
<!-- : See 'http://www.alien-factory.co.uk' for details -->
<!-- GET YOUR STICKY FINGERS OFF! i.e. Do not edit. -->
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<struts-config>
<!-- ====================== Form Bean Definitions =================== -->
<form-beans>
</form-beans>
<!-- ================= Global Forward Definitions =================== -->
<global-forwards>
</global-forwards>
<!-- ======================= Action Definitions ===================== -->
<action-mappings>
<action path="/Login"
type="com.agilquest.onboard.presentation.actions.LoginAction">
<description>Authenticates and authorizes a user.</description>
</action>
</action-mappings>
</struts-config>
为了使你的用户界面流程图更加复杂,我们推荐在使用StrutsGUI 时增加一个步骤。在你的StrutsGUI Visio 文档内,你可以轻易的将每个JSP (JavaServer Pages)页链接到它在应用中的实际屏幕快照。创建这个界面不但确实有助于应用程序的文档化,更重要的是,它成为了培训新的从事用户界面设计的开发者的一件极好的工具。
另一个帮助管理Struts应用的工具就是由James Holmes 发明的Struts Console。本质上,这个工具提供了一组设备,这些设备使你能够得到与StrutsGUI 相同的终点,但是它们在途径和长度上有区别。这两个工具都执行良好,其中任何一个都可以增强基于Struts的企业应用的可维护性。
三、现在,我将表格放在哪里?
ActionForm 会话期管理有点棘手。ActionForm的周期怎样?它在请求周期内或者会话期周期内吗?为了得到它所代表的功能周期,方案之一就是将ActionForm置于会话期之内。在这种情况下,你通常怎样维护这些ActionForm 对象呢?谁知道不再需要他们时删除他们要承担什么责任呢?典型的情况是:用户通过菜单从一个功能转为使用另一个功能。在这种情况下,原来的ActionForm 对象就应该从会话期删除,并且创建新的ActionForm 对象。这时还应该出现一个集中的Action类,MenuAction,它只处理菜单切换。这个Action 类从会话期删除多余的ActionForm 对象。然后将用户前进到创建新ActionForm 对象所在的新页面。
在这种情况下,站在用户的立场上或者基于用户权限,我们应该如何显示不同的菜单项呢?这个菜单也应该国际化,并且它修改时应该以用户权限为基础;也就是说,如果许可修改了,菜单也要相应的修改。有一种方法可以持续用户的权限。当用户注册时, MenuFactory根据这些权限创建菜单,为了增加安全性, MenuAction类在允许用户进行到他所选择的功能之前需要认证用户。命名struts-config.xml 中的ActionForm 对象的首要规则是对象名以Form 结束,从而简化了会话期内这些表格的维护。例如: ReservationForm, SearchUserForm, BankAccountForm, UserProfileForm,等等。
下列代码描述了一个具有Action 映射的普通菜单切换动作,它进一步阐明了ActionForm(s)管理:
public class MenuAction {
public ActionForward perform(ActionMapping _mapping,
ActionForm _form,
HttpServletRequest _request,
HttpServletResponse _response)
throws IOException, ServletException {
// Check end-user permissions whether allowed into the requested
// functionality
checkIfUserAllowedToProceed(_mapping, _form, _request, _response);
// Clean up the session object (this logic is in its own method)
String formName = null;
HttpSession session = _request.getSession();
Enumeration e = session.getAttributeNames();
while(e.hasMoreElements()) {
formName = (String)e.nextElement();
if (formName.endsWith("Form")){
session.removeAttribute(formName);
}
}
// Now find out which functionality the end-user wants to go to
String forwardStr = _request.getParameter("nextFunctionality");
if (forwardStr != null && forwardStr.trim().length() > 0){
return _mapping.findForward(forwardStr);
}
else {
return _mapping.findForward("index");
}
}
}
下列Action映射就是一个阐述如何以菜单选择为基础实现动作的例子:
<!-- A generic menu action that forwards the user from one
functionality to another functionality (after checking permissions)
-->
<action path="/menuAction"
type="x.y.z.MenuAction"
input="/menu.jsp">
<forward name="create_reservation" path="/actionResv.do"/>
<forward name="index" path="/menu.jsp"/>
<forward name="add_person" path="/actionPerson.do"/>
<forward name="logout" path="/actionLogout.do"/>
</action>
例子和映射都是可以自我解释的。
四、再说一次,我们是怎样关联的?
任何JSP页的许多输入点与许多现有点之间都有一个关系,这取决于页面本身的复杂程度。认识到这些关系对于理解和维护用户界面是至关重要的。我们已经将JSP页和Action 类之间的关系定义为:
?1:1 关系
?1:N 关系
?N:N关系
1:1 关系 在1:1 关系中,用户通过Action类从一个JSP页切换到另一个页面;这就使得JSP页和Action 之间容易形成一个紧密的耦合。唯一的额外开销就是struts-config.xml 中有一个Action映射。这