StrutsMVC 的一种开放源码实现.docx

上传人:b****5 文档编号:7712862 上传时间:2023-01-25 格式:DOCX 页数:20 大小:97.94KB
下载 相关 举报
StrutsMVC 的一种开放源码实现.docx_第1页
第1页 / 共20页
StrutsMVC 的一种开放源码实现.docx_第2页
第2页 / 共20页
StrutsMVC 的一种开放源码实现.docx_第3页
第3页 / 共20页
StrutsMVC 的一种开放源码实现.docx_第4页
第4页 / 共20页
StrutsMVC 的一种开放源码实现.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

StrutsMVC 的一种开放源码实现.docx

《StrutsMVC 的一种开放源码实现.docx》由会员分享,可在线阅读,更多相关《StrutsMVC 的一种开放源码实现.docx(20页珍藏版)》请在冰豆网上搜索。

StrutsMVC 的一种开放源码实现.docx

StrutsMVC的一种开放源码实现

本文介绍Struts,它是使用servlet和JavaServerPages技术的一种Model-View-Controller实现。

Struts可帮助您控制Web项目中的变化并提高专业化水平。

尽管您可能永远不会用Struts实现一个系统,但您可以将其中的一些思想用于您以后的servlet和JSP网页的实现中。

简介

小学生也可以在因特网上发布HTML网页。

但是,小学生的网页和专业开发的网站有质的区别。

网页设计人员(或者HTML开发人员)必须理解颜色、用户、生产流程、网页布局、浏览器兼容性、图像创建和JavaScript等等。

设计漂亮的网站需要做大量的工作,大多数Java开发人员更注重创建优美的对象接口,而不是用户界面。

JavaServerPages(JSP)技术为网页设计人员和Java开发人员提供了一种联系钮带。

如果您开发过大型Web应用程序,您就理解变化这个词的含义。

“模型-视图-控制器”(MVC)就是用来帮助您控制变化的一种设计模式。

MVC减弱了业务逻辑接口和数据接口之间的耦合。

Struts是一种MVC实现,它将Servlet2.2和JSP1.1标记(属于J2EE规范)用作实现的一部分。

尽管您可能永远不会用Struts实现一个系统,但了解一下Struts或许使您能将其中的一些思想用于您以后的Servlet的JSP实现中。

在本文中,我将以一个JSP文件为起点讨论该网页的优缺点,该文件中使用的元素可能是您所熟悉的。

随后我将讨论Struts,并说明它是如何控制您的Web项目中的变化并提高专业化水平的。

最后,我将重新开发这个简单的JSP文件,在开发过程中我已顾及到网页设计人员和变化。

一个JSP文件就是一个Javaservlet

JavaServerPage(JSP)文件只是审视servlet的另一种方式。

JSP文件的概念使我们能够将Javaservlet看作一个HTML网页。

JSP消除了Java代码中经常出现的讨厌的print()语句。

JSP文件首先被预处理为.java文件,然后再编译为.class文件。

如果您使用的是Tomcat,则可以在work目录下查看预处理后的.java文件。

别的容器可能将.java和.class文件存储在其他位置;这个位置与容器有关。

图1说明了从JSP文件到servlet的流程。

图1.从JSP文件到servlet的流程

(这与Microsoft的ActiveServerPage(ASP)明显不同。

ASP被编译到内存中,而不是编译到一个单独的文件中。

简单的独立JSP文件

在小型JSP应用程序中,经常会看到数据、业务逻辑和用户界面被组合在一个代码模块中。

此外,应用程序通常还包含用来控制应用程序流程的逻辑。

清单1和图2展示了允许用户加入一个邮件列表的一个简单JSP文件。

清单1.join.jsp--一个简单的请求和响应JSP文件

<%@pagelanguage="java"%>

<%@pageimport="business.util.Validation"%>

<%@pageimport="business.db.MailingList"%>

<%

Stringerror="";

Stringemail=request.getParameter("email");

//是否有电子邮件地址

if(email!

=null){

//验证输入...

if(business.util.Validation.isValidEmail(email)){

//存储输入...

try{

business.db.MailingList.AddEmail(email);

}catch(Exceptione){

error="Erroraddingemailaddresstosystem."+e;

}

if(error.length()==0){

%>

//重定向到欢迎页...

forwardpage="welcome.html"/>

<%

}

}else{

//设置错误消息并重新显示网页

error=email+"isnotavalidemailaddress,pleasetryagain.";

}

}else{

email="";

}

%>

JoinMailingList

<%=error%>

Enteryouremailtojointhegroup

>

图2.在简单的请求和响应中,JSP文件设置数据、控制到下一个网页的流程并创建HTML

这个邮件列表JSP文件是一个独立的、自主完成所有任务的模块。

未包含在这个JSP文件中的仅有代码是包含在isValidEmail()中的实际验证代码和将电子邮件地址存入数据库的代码。

(将isValidEmail()方法分离到可重用的代码中似乎是当然的选择,但我曾见过直接嵌入网页中的isValidEmail()代码。

单页方法的优点是易于理解,并且最初也易于构建。

此外,对于各种图形化开发工具,入门也很容易。

join.jsp的活动

1.显示打开的输入网页。

2.从表单参数中读取email的值。

3.验证email地址。

4.如果email地址有效:

o将该地址添加到数据库中。

o重定向到下一个网页。

5.如果email地址无效:

o设置错误消息。

o重新显示含有错误消息的join.jsp。

单页方法的后果

∙HTML和Java强耦合在一起

JSP文件的编写者必须既是网页设计者,又是Java开发者。

其结果通常要么是很糟的Java代码,要么是难看的网页,有时甚至Java代码和网页都很糟。

∙Java和JavaScript的不足

随着网页逐渐变大,很容易想到实现一些JavaScript。

当网页中出现JavaScript时,这种脚本就可能与Java代码产生混淆。

可能产生混淆的一个例子是使用客户端的JavaScript来验证email域。

 

∙内嵌的流程逻辑

要理解应用程序的整个流程,您必须浏览所有网页。

试想一下拥有100个网页的网站的错综复杂的逻辑。

∙调试困难

除了很糟的外观之外,HTML标记、Java代码和JavaScript代码都集中在一个网页中还使调试变得相当困难。

∙强耦合

更改业务逻辑或数据可能牵涉相关的每个网页。

∙美学

在很大的网页中,这编码样式看起来杂乱无章。

我过去进行MicrosoftASP开发时,我经常看到有1000行的网页。

即使有彩色语法显示,阅读和理解这些代码仍然比较困难。

请别在我的HTML中加入太多的Java代码

在清单1中,不是Java代码中有大量的HTML,而是在HTML文件中有大量的Java代码。

从这个观点来看,除了允许网页设计人员编写Java代码之外,我实际上没做什么。

但是,我们并不是一无所有;在JSP1.1中,我们获得一种称为“标记”的新特性。

JSP标记只是将代码从JSP文件中抽取出来的一种方式。

有人将JSP标记看作是JSP文件的宏,其中用于这个标记的代码包含在servlet中。

(宏的观点在很大程度上是正确的。

)出于同样的原因,我不希望在Java代码中看到HTML标记,我也不希望在JSP文件中看到Java代码。

JSP技术的整个出发点就是允许网页设计人员创建servlet,而不必纠缠于Java代码。

标记允许Java程序员将Java代码伪装成HTML来扩展JSP文件。

图3显示了从JSP网页中抽取代码并将它们放入JSP标记中的一般概念。

图3.JSP标记

清单2是用来说明Struts标记的功能的一个例子。

在清单2中,正常的HTML

标记被用Struts

form>标记替换。

清单3显示了浏览器接收到的结果HTML。

浏览器获得HTML标记,但带有附加代码,如JavaScript。

附加的JavaScript激活email地址域。

服务器端的

form>标记代码创建适当的HTML,并使网页设计人员不再接触JavaScript。

清单2.Struts的form标记

formaction="join.do"focus="email">

textproperty="email"size="30"maxlength="30"/>

submitproperty="submit"value="Submit"/>

form>

清单3.发送给浏览器的结果HTML

--

document.joinForm.email.focus()

//-->

有关JSP标记的注意事项:

∙JSP标记需要一个运行JSP1.1或更高版本的容器。

∙JSP标记在服务器上运行,而不像HTML标记那样由客户机解释。

∙JSP标记提供了适当的代码重用机制。

∙可以使用一种称为include的JSP机制将HTML和JavaScript添加到网页中。

但是,开发人员常常会创建巨大的JavaScript库文件,这些库文件被包含在JSP文件中。

结果返回给客户机的HTML网页要比必需的HMTL网页大得多。

include的正确用法是仅将它用于生成诸如页眉和页脚这类内容的HTML代码段。

∙通过抽取出Java代码,JSP标记使开发角色更加专业化。

模型-视图-控制器(MVC)

JSP标记只解决了部分问题。

我们还得处理验证、流程控制和更新应用程序的状态等问题。

这正是MVC发挥作用的地方。

MVC通过将问题分为三个类别来帮助解决单一模块方法所遇到的某些问题:

∙Model(模型)

模型包含应用程序的核心功能。

模型封装了应用程序的状态。

有时它包含的唯一功能就是状态。

它对视图或控制器一无所知。

∙View(视图)

视图提供模型的表示。

它是应用程序的外观。

视图可以访问模型的读方法,但不能访问写方法。

此外,它对控制器一无所知。

当更改模型时,视图应得到通知。

 

∙Controller(控制器)

控制器对用户的输入作出反应。

它创建并设置模型。

MVCModel2

Web向软件开发人员提出了一些特有的挑战,最明显的就是客户机和服务器的无状态连接。

这种无状态行为使得模型很难将更改通知视图。

在Web上,为了发现对应用程序状态的修改,浏览器必须重新查询服务器。

另一个重大变化是实现视图所用的技术与实现模型或控制器的技术不同。

当然,我们可以使用Java(或者PERL、C/C++或别的语言)代码生成HTML。

这种方法有几个缺点:

∙Java程序员应该开发服务,而不是HTML。

∙更改布局时需要更改代码。

∙服务的用户应该能够创建网页来满足它们的特定需要。

∙网页设计人员不能直接参与网页开发。

∙嵌在代码中的HTML很难看。

对于Web,需要修改标准的MVC形式。

图4显示了MVC的Web改写版,通常也称为MVCModel2或MVC2。

图4.MVCModel2

 

Struts,MVC2的一种实现

Struts是一组相互协作的类、servlet和JSP标记,它们组成一个可重用的MVC2设计。

这个定义表示Struts是一个框架,而不是一个库,但Struts也包含了丰富的标记库和独立于该框架工作的实用程序类。

图5显示了Struts的一个概览。

图5.Struts概览

Struts概览

∙Clientbrowser(客户浏览器)

来自客户浏览器的每个HTTP请求创建一个事件。

Web容器将用一个HTTP响应作出响应。

∙Controller(控制器)

控制器接收来自浏览器的请求,并决定将这个请求发往何处。

就Struts而言,控制器是以servlet实现的一个命令设计模式。

struts-config.xml文件配置控制器。

 

∙业务逻辑

业务逻辑更新模型的状态,并帮助控制应用程序的流程。

就Struts而言,这是通过作为实际业务逻辑“瘦”包装的Action类完成的。

 

∙Model(模型)的状态

模型表示应用程序的状态。

业务对象更新应用程序的状态。

ActionFormbean在会话级或请求级表示模型的状态,而不是在持久级。

JSP文件使用JSP标记读取来自ActionFormbean的信息。

∙View(视图)

视图就是一个JSP文件。

其中没有流程逻辑,没有业务逻辑,也没有模型信息--只有标记。

标记是使Struts有别于其他框架(如Velocity)的因素之一。

详细分析Struts

图6显示的是org.apache.struts.action包的一个最简UML图。

图6显示了ActionServlet(Controller)、ActionForm(FormState)和Action(ModelWrapper)之间的最简关系。

图6.Command(ActionServlet)与Model(Action&ActionForm)之间的关系的UML图

ActionServlet类

您还记得函数映射的日子吗?

在那时,您会将某些输入事件映射到一个函数指针上。

如果您对此比较熟悉,您会将配置信息放入一个文件,并在运行时加载这个文件。

函数指针数组曾经是用C语言进行结构化编程的很好方法。

现在好多了,我们有了Java技术、XML、J2EE,等等。

Struts的控制器是将事件(事件通常是HTTPpost)映射到类的一个servlet。

正如您所料--控制器使用配置文件以使您不必对这些值进行硬编码。

时代变了,但方法依旧。

ActionServlet是该MVC实现的Command部分,它是这一框架的核心。

ActionServlet(Command)创建并使用Action、ActionForm和ActionForward。

如前所述,struts-config.xml文件配置该Command。

在创建Web项目时,您将扩展Action和ActionForm来解决特定的问题。

文件struts-config.xml指示ActionServlet如何使用这些扩展的类。

这种方法有几个优点:

∙应用程序的整个逻辑流程都存储在一个分层的文本文件中。

这使得人们更容易查看和理解它,尤其是对于大型应用程序而言。

∙网页设计人员不必费力地阅读Java代码来理解应用程序的流程。

∙Java开发人员也不必在更改流程以后重新编译代码。

可以通过扩展ActionServlet来添加Command功能。

ActionForm类

ActionForm维护Web应用程序的会话状态。

ActionForm是一个抽象类,必须为每个输入表单模型创建该类的子类。

当我说输入表单模型时,是指ActionForm表示的是由HTML表单设置或更新的一般意义上的数据。

例如,您可能有一个由HTML表单设置的UserActionForm。

Struts框架将执行以下操作:

∙检查UserActionForm是否存在;如果不存在,它将创建该类的一个实例。

 

∙Struts将使用HttpServletRequest中相应的域设置UserActionForm的状态。

没有太多讨厌的request.getParameter()调用。

例如,Struts框架将从请求流中提取fname,并调用UserActionForm.setFname()。

 

∙Struts框架在将UserActionForm传递给业务包装UserAction之前将更新它的状态。

 

∙在将它传递给Action类之前,Struts还会对UserActionForm调用validation()方法进行表单状态验证。

注:

这并不总是明智之举。

别的网页或业务可能使用UserActionForm,在这些地方,验证可能有所不同。

在UserAction类中进行状态验证可能更好。

 

∙可在会话级维护UserActionForm。

注:

∙struts-config.xml文件控制HTML表单请求与ActionForm之间的映射关系。

∙可将多个请求映射到UserActionForm。

∙UserActionForm可跨多页进行映射,以执行诸如向导之类的操作。

Action类

Action类是业务逻辑的一个包装。

Action类的用途是将HttpServletRequest转换为业务逻辑。

要使用Action,请创建它的子类并覆盖process()方法。

ActionServlet(Command)使用perform()方法将参数化的类传递给ActionForm。

仍然没有太多讨厌的request.getParameter()调用。

当事件进展到这一步时,输入表单数据(或HTML表单数据)已被从请求流中提取出来并转移到ActionForm类中。

注:

扩展Action类时请注意简洁。

Action类应该控制应用程序的流程,而不应该控制应用程序的逻辑。

通过将业务逻辑放在单独的包或EJB中,我们就可以提供更大的灵活性和可重用性。

考虑Action类的另一种方式是Adapter设计模式。

Action的用途是“将类的接口转换为客户机所需的另一个接口。

Adapter使类能够协同工作,如果没有Adapter,则这些类会因为不兼容的接口而无法协同工作。

”(摘自Gof所著的DesignPatterns-ElementsofReusableOOSoftware)。

本例中的客户机是ActionServlet,它对我们的具体业务类接口一无所知。

因此,Struts提供了它能够理解的一个业务接口,即Action。

通过扩展Action,我们使得我们的业务接口与Struts业务接口保持兼容。

(一个有趣的发现是,Action是类而不是接口)。

Action开始为一个接口,后来却变成了一个类。

真是金无足赤。

Error类

UML图(图6)还包括ActionError和ActionErrors。

ActionError封装了单个错误消息。

ActionErrors是ActionError类的容器,View可以使用标记访问这些类。

ActionError是Struts保持错误列表的方式。

图7.Command(ActionServlet)与Model(Action)之间的关系的UML图

ActionMapping类

输入事件通常是在HTTP请求表单中发生的,servlet容器将HTTP请求转换为HttpServletRequest。

控制器查看输入事件并将请求分派给某个Action类。

struts-config.xml确定Controller调用哪个Action类。

struts-config.xml配置信息被转换为一组ActionMapping,而后者又被放入ActionMappings容器中。

(您可能尚未注意到这一点,以s结尾的类就是容器)

ActionMapping包含有关特定事件如何映射到特定Action的信息。

ActionServlet(Command)通过perform()方法将ActionMapping传递给Action类。

这样就使Action可访问用于控制流程的信息。

ActionMappings

ActionMappings是ActionMapping对象的一个集合。

再访邮件列表样例

下面我们看一下Struts是如何解决困扰join.jsp的这些问题的。

改写后的方案由两个项目组成。

第一个项目包含应用程序的逻辑部分,这个应用程序是独立于Web应用程序的。

这个独立层可能是用EJB技术实现的公共服务层。

为了便于说明,我使用Ant构建进程创建了一个称为business的包。

有几个原因促使我们使用独立的业务层:

∙划分责任

单独的包使管理人员能够在开发小组内委派责任。

这也有助于提高开发人员的责任心。

∙通用件

我们设想开发人员将这个包看作一个商业软件。

将它放在另外的包中使它更像通用件。

这个包可能是通用件,也可能是由组织内部的另一个小组开发的。

∙避免不必要的构建和单元测试。

分开的构建进程有助于避免不必要的构建和单元测试。

∙使用接口开发

在进行开发和避免不必要的耦合时,它有助于从接口的观点来思考问题。

这是极重要的一个方面。

当开发您自己的业务包时,这些业务类不应该关心到底是Web应用程序执行调用,还是独立应用程序执行调用。

因此,应该避免在业务逻辑层使用对servletAPI或StrutsAPI调用的任何引用。

∙稳定性

并不是每个组

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 研究生入学考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1