第7章 Struts 与MVC 设计模式.docx
- 文档编号:8498103
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:87
- 大小:688.02KB
第7章 Struts 与MVC 设计模式.docx
《第7章 Struts 与MVC 设计模式.docx》由会员分享,可在线阅读,更多相关《第7章 Struts 与MVC 设计模式.docx(87页珍藏版)》请在冰豆网上搜索。
第7章Struts与MVC设计模式
第7章Struts与MVC设计模式
7.1.Struts与JavaWeb应用
JavaWeb应用的核心技术是JavaServerPage和Servlet。
此外,开发一个完成的JavaWeb应用还设计以下概念和技术:
●JavaBean组件
●EJB组件
●自定义JSP标签
●XML
●Web服务器和应用服务器
图7-1:
JavaWeb应用的结构
7.1.1.Web组件的三种关联
Web应用程序如此强大的原因之一是他们能彼此链接和聚合信息资源。
Web组件之间存在三种关联关系:
●请求转发
●URL重定向
●包含
存在以上关联关系的Web组件可以是JSP或Servlet,对于Struts应用,则还包含Action。
这些Web组件都可以访问HttpServletRequest和HttpServletResponse对象,具有处理请求、生成响应结果的功能。
7.1.1.1.请求转发
请求转发允许把请求转发给同一应用程序中的其他Web组件。
这种技术通常用于Web应用控制层的Servlet流程控制器,它检查Http请求数据,并讲请求转发到合适的目标组件,目标组件执行具体请求处理操作,并生成响应结果。
下图显示了一个Servlet把请求转发给另一个JSP组件的过程。
图7-2:
请求转发
Sevlet类使用javax.servlet.RequestDispatcher.forward()方法来转发它所收到的HTTP请求。
转发目标组件将处理该请求并生成响应结果,或者将请求继续转发到另一个组件。
最初请求的ServletRequest和ServletResponse对象被传递给转发目标组件,这使得目标组件可以访问整个请求上下文。
值得注意的是,只能把请求转发给同一Web应用中的组件,而不能转发给其他Web应用组件。
如果当前的Servlet组件要把请求转发给一个JSP组件,如hello.jsp,可以在Servlet的service()方法中执行以下代码:
RequestDistpatherrd=request.getRequestDispather(“hello.jsp”);
//ForwardtorequestedURL
rd.forward(request.response);
在JSP页面中,可以使用 forward>转发请求,例如: forwardpage=“hello.jsp”/> 对于请求转发,转发的资源组件和目标组件共享request范围内的共享数据。 7.1.1.2.请求重定向 请求重定向类似请求转发,但也有一些重要区别: ●Web组件可以将请求重定向到任一URL,而不仅仅是统一应用中的URL。 ●重定向的资源组件和目标组件之间不共用一个HttpServletRequest对象,因此不能 ●共享request范围内的共享数据。 下图显示了一个Serlet把请求重定向给另一个JSP组件的过程。 图7-3: 请求重定向 如果当前应用的Servlet组件要把请求转发给URL“http: //jakarta.apache.org/struts”,可 以在Servlet的service()方法中执行以下代码: response.sendRedirect(“http: //jakarta.apache.org/struts”);从上图中可以看出,HttpServletResponse的sendRedirect()方法向浏览器返回包含重定向 信息,浏览器根据这一信息发送出一个新的HTTP请求,请求访问重定向目标组件。 7.1.1.3.包含 包含关系允许一个Web组件聚集来自同一个应用中其他Web组件的输出数据,并使用被聚集的数据来创建响应效果。 这种技术通常用于模板处理器,它可以控制网页的布局。 模板中每个页面区域的内容来自不同的URL,conger组成单个页面。 这种技术能够为应用程序提供一致的外观和感觉。 包含关系的源组件和目标组件共用同一个HttpServletRequest对象,因此他们共享request范围内的共享数据。 下图显示了一个Servlet包含另一个JSP组件的过程。 图7-4: Web组件的包含关系 Servlet类使用javax.servlet.RequestDispather.include()方法包含其他Web组件。 例如,如果当前的Servlet组件包含了3个JSP文件: header.jsp、main.jsp和footer.jsp,则可以在Servlet的service()方法中执行以下代码: …… RequestDispatcherrd; rd=req.getRequestDispatcher(“/header.jsp”); rd.include(req,res); rd=req.getRequestDispatcher(“/main.jsp”); rd.include(req,res); rd=req.getRequestDispatcher(“/footer.jsp”); rd.include(req,res); …… 在JSP文件中,可以通过 <%@includefile=“/header.jsp”%> <%@includefile=“/main.jsp”%> <%@includefile=“/footer.jsp”%> 7.1.2.MVC概述 模型-视图-控制器(MVC)是80年代Smalltalk-80出现的一种软件设计模式,现在已经被广泛的使用。 开发模式上采用Model-View-Controller(MVC)模式,MVC模式将程序代码整理切割为三部份,Model部分是业务与应用领域(Businessdomain)相关逻辑、管理状态之对象,Controller部分接收来自View所输入的资料并与Model部分互动,是业务流程控制(FlowControl)之处,View部分则负责展现资料、接收使用者输入资料。 ●模型(Model)模型是应用程序的主体部分。 模型表示业务数据,或者业务逻辑. ●视图(View)视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。 ●控制器(controller)控制器工作就是根据用户的输入,控制用户界面数据显示和更新model对象状态。 图7-5: MVC设计模式 7.1.2.1.MVC的优点 可以为一个模型在运行时同时建立和使用多个视图。 变化-传播机制可以确保所有相关的视图及时得到模型数据变化,从而使所有关联的视图和控制器做到行为同步。 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态的打开或关闭、甚至在运行期间进行对象替换。 模型的可移植性。 因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。 需要做的只是在新平台上对视图和控制器进行新的修改。 潜在的框架结构。 可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。 7.1.2.2.MVC的不足之处 增加了系统结构和实现的复杂性。 对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。 视图与控制器间的过于紧密的连接。 视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。 视图对模型数据的低效率访问。 依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。 对未变化数据的不必要的频繁访问,也将损害操作性能。 目前,一般高级的界面工具或构造器不支持MVC模式。 改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。 7.1.2.3.MVC的应用范围 使用MVC需要精心的计划,由于它内部原理比较复杂,所以需要花费一些时间去理解它。 将MVC运用到应用程序中会带来额外的工作量,增加应用的复杂性,所以MVC部适合小型应用程序。 但是对于开发存在大量用户界面上,并且业务逻辑复杂的大型应用程序,MVC将会使软件在健壮性、代码重用喝结构方面上一个新台阶。 尽管在最初构建MVC框架时会花费一定工作量,但从长远的角度来看,它会大大提供后期软件开发效率。 7.1.3.JSPModel1和JSPModel2 SUN在JSP出现早期制定了两种规范,称为Model1和Model2。 图7-6: JSPModel1 Model1它是以页面为中心的。 适用于完成简单的应用程序。 实现这个模式的应用程序有一系列的Jsp页面,在这些页面里用户程序运行从一个页面到另一个页面。 因为它的简单容易。 Model1应用的主要问题是难以维护,并且毫无灵活性可言。 另外,由于开发人员已经同时被卷入到了页面开发和商业逻辑的编码中,这个架构模式在页面设计人员和web开发人员之间很难实现劳动分工。 图7-7: JSPModel2 JSPModel1和JSPModel2的本质区别在于处理用户请求的位置不同。 在Model1体系中,JSP页面负责响应用户请求并将处理结果返回用户。 JSP既要负责具体业务流程控制,又要负责提供表示层数据,同时充当视图和控制器,未能实现这两个模块之间的独立和分离。 尽管Model1体系十分适合简单应用的需要,它却不适合开发复杂的大型应用程序。 不加选择的使用Model1,会导致JSP页内嵌入大量Java代码。 尽管这对Java程序员不是多大的问题,但如果JSP页面由网页设计人员开发并进行维护的(大量的实际项目中情况确实是这样的),这个问题就会变得十分突出。 从根本上讲,将导致角色定义不清和职责分配不明,会给项目管理带来很大的麻烦。 JSPModel2体系结构是一种联合使用JSP和Servlet来提供动态内容服务的方法。 它吸取了JSP和Servlet两种技术各自的突出优点,用JSP生成表示层的内容,让Servlet完成深层次的处理任务。 在这里,Servlet充当控制器的角色,负责处理用户请求,创建JSP页需要使用的JavaBean对象,根据用户请求选择使用的JSP页返回给用户。 在JSP页内没有处理逻辑,它仅负责检索原先由Servlet创建的JavaBean对象,从Servlet中提取动态内容插入静态模板。 这是一种有突破性的软件设计方法,它清晰地分离了表达和内容,明确角色定义以及开发者与网页设计者的分工。 事实上,项目越复杂,使用Model2的好处越大,越容易体现。 7.1.4.Struts概述 Struts实质上就是在JSPModel2的基础上实现一个MVC框架。 在Struts框架中,模型由实现业务逻辑的JavaBean或EJB组件构成,控制器由ActionServlet和Action来实现,视图由一组JSP文件构成。 图7-8: Struts实现的MVC框架 7.1.4.1.Model Struts没有定义具体的Model层的实现,Model层通常是和业务逻辑紧密相关的,还通常有持续化的要求,Struts目前没有考虑到这一层,但是,不管在开源世界还是商业领域,都有一些都别优秀的工具可以为Model层次的开发提供便利,例如优秀的O/RMapping开源框架Hibernate。 7.1.4.2.View 通常,Web应用的UI由以下文件组成: ●HTML ●JSP 而JSP中通常包含以下组件: ●自定义标签 ●DTO(DataTransferObject数据传输对象) 在Struts中,还包含了以下两种常用的组件: ●StrutsActionForms ●资源绑定(javaresourcebundles),例如将标签的显示内容,错误提示的内容通 过配置文件来配置,这样可以为实现国际化提供基础。 由此可见,Struts对于传统的WebUI所作的扩充就是StrutsActionForms和资源绑定,接下来对其进行进一步描述。 7.1.4.3.Controller J2EE的前端控制器(FrontController)设计模式中利用一个前端控制器来接受所有客户请求,为应用提供一个中心控制点,在该控制点上,可以很方便地添加一些全局性的,如加密、国际化、日志等通用操作。 Controller的实现机制正是建立在前端控制器的设计模式基础上。 前面我们介绍过,Struts的控制器拥有一些职责,其中最主要的是以下几个: 1.1.接收客户请求。 2.2.映射请求到指定的业务操作。 3.3.获取业务操作的结果并以有效的方式提供给客户。 4.4.根据业务操作的结果和当前的状态把不同的UI推向给客户。 在Struts框架中,控制器中不同的组件负责不同的控制职责,下图是Struts框架中关于控制器部分的一个组件图: 图7-9: 控制器组件 在上图中,很明显地可以看出,ActionServlet处于核心位置,那么,我们就先来了解一下ActionServlet。 org.apache.struts.action.ActionServlet在Struts应用程序中扮演接收器的角色,所有客户端的请求在被其它类处理之前都得通过ActionServlet的控制。 当ActionServlet的实例接收到一个HTTP请求,不管是通过get方法或post方法,ActionServlet的process()方法被调用并用以处理客户请求。 process()方法实现显示如下: protectedvoidprocess(HttpServletRequestrequest,HttpServletResponseresponse) throwsIOException,ServletException{ RequestUtils.selectApplication(request,getServletContext()); getApplicationConfig(request).getProcessor().process(request,response);} 该方法的实现很简单,RequestUtils.selectApplication(request,getServletContext());语句是用来根据用户访问的上下文路径来选择处理的应用,如果你只有一个Struts配置文件,就表示你只有一个Struts应用。 getApplicationConfig(request).getProcessor().process(request,response);语句用来获取一个处理器,并将客户请求提交给处理器处理。 7.1.4.4.Struts初始化处理流程 根据在web.xml中配置的初始化参数,Servlet容器将决定在在容器的第一次启动,或第一次客户请求ActionServlet的时机加载ActionServlet,不管哪种方式加载,和其它Servlet一样,ActionServlet的init()方法将被调用,开始初始化过程。 让我们来看看在初始化过程中将发生些什么,理解了这些,对于我们debug和扩展自己的应用更加得心应手。 5.1.初始化框架的内部消息绑定,这些消息用来输出提示,警告,和错误信息到日志文件中。 org.apache.struts.action.ActionResources用来获取内部消息; 6.2.加载web.xml中定义的不同参数,用以控制ActionServlet的不同行为,这些参数包括config,debug,detail,andconvertNull; 7.3.加载并初始化web.xml中定义的servlet名称和servlet映射信息。 通过初始化,框架的各种DTD被注册,DTD用来在下一步校验配置文件的有效性; 8.4.为默认应用加载并初始化Struts配置文件,配置文件即初始化参数config指定的文件。 默认配置文件被解析,产生一个ApplicationConfig对象存于ServletContext中。 可以通过关键字org.apache.struts.action.APPLICATION从ServletContext中获取ApplicationConfig; 9.5.Struts配置文件中指定的每一个消息资源都被加载,初始化,并存在ServletContext的合适区域(基于每个message-resources元素的key属性),如果key属性没有设置,则为org.apache.struts.action.MESSAGE; 10.6.Struts配置文件中声明的每一个数据源被加载并且初始化,如果没有配置数据源,这一步跳过; 11.7.加载并初始化Struts配置文件中指定的插件。 每一个插件的init()方法被调用; 当默认应用加载完成,init()方法判断是否有应用模块需要加载,如果有,重复步骤4—7步成应用模块的加载。 7.1.4.5.Struts工作流程 图7-10: Struts工作流程 上图是Struts的工作流程,前边我们提到,所有的请求都提交给ActionServlet来处理。 ActionServlet是一个FrontController,它是一个标准的Servlet,它将request转发给RequestProcessor来处理。 ActionMapping是ActionConfig的子类,实质上是对struts-config.xml的一个映射,从中可以取得所有的配置信息。 RequestProcessor根据提交过来的url,如*.do,从ActionMapping中得到相应的ActionForn和Action。 然后将request的参数对应到ActionForm中,进行form验证。 如果验证通过则调用Action的execute()方法来执行Action,最终返回ActionFoward。 ActionFoward是对mapping中一个foward的包装,对应于一个url。 ActionForm使用了ViewHelper模式,是对HTML中form的一个封装。 其中包含有validate方法,用于验证form数据的有效性。 ActionForm是一个符合JavaBean规范的类,所有的属性都应满足get和set对应。 对于一些复杂的系统,还可以采用DynaActionForm(Struts1.1)来构造动态的Form,即通过预制参数来生成Form。 这样可以更灵活的扩展程序。 ActionErrors是对错误信息的包装,一旦在执行action或者form.validate中出现异常,即可产生一个ActionError并最终加入到ActionErrors。 在Form验证的过程中,如果有Error发生,则会将页面重新导向至输入页,并提示错误。 Action是用于执行业务逻辑的RequsestHandler。 每个Action都只建立一个instance。 Action不是线程安全的,所以不应该在Action中访问特定资源。 一般来说,应改使用BusinessDelegate模式来对Businesstier进行访问以解除耦合。 Struts提供了多种Action供选择使用。 普通的Action只能通过调用execute执行一项任务,而DispatchAction可以根据配置参数执行,而不是仅进入execute()函数,这样可以执行多种任务。 如insert,update等。 LookupDispatchAction可以根据提交表单按钮的名称来执行函数。 当ActionServlet接收到一个客户请求时,将执行如下流程: 图7-11: Struts响应用户请求的工作流程 1)检索和用户请求匹配的ActionMapping实例,如果不存在,就放回用户请求路径无效的信息。 2)如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中。 3)根据配置信息决定是否需要表单验证。 如果需要验证,就调用ActionForm的 validate()方法。 4)如果ActionForm的validate()方法返回null或者一个不包含ActionMessage的 ActionErrors对象,就表示表单验证成功。 验证不成功则发送给用户提交表单的 JSP组件,或者转向其他组件。 这样Action对象不会被创建。 5)ActionServlet根据ActionMapping实例包含的映射信息决定将请求转发给哪个 Action。 如果相应的Action实例不存在,就先创建这个实例,然后调用Action的execute()方法。 6)Action的execute()方法返回一个ActionForward对象,ActionServlet再把客户 请求转发给ActionForward对象只想JSP组件。 7)ActionForward对象指向JSP组件生成动态网页,返回给客户。 7.2.从helloapp开始Struts应用 7.2.1.helloapp的需求 helloapp的需要非常简单,主要是体验Struts开发过程,其内容如下: ●接收用户输入姓名 ”。 ●如果用户没有输入姓名就提交表单,将返回错误信息,提示用户首先输入姓名。 ●如果用户输入姓名为“Monster”,将返回出错信息,拒绝向“Monster”sayhello。 ●为了演示模型组件的功能,本应用使用模型组件来保护用户输入的姓名。 7.2.2.组建Struts框架 Helloapp应用的各个模块组成: JavaBean组件: PersonBean,有一个userName属性,代表用户输入的名字。 提供了get/set方法。 这里可以预留save()方法,将数据保存到数据库中(JavaBean组件可以作为EJB或者Web服务前端组件)。 视图: hello.jsp,提供用户界面,接收用户输入的姓名。 视图还包括一个ActionFormBean,它用来存放表单数据,并进行表单验证。 控制器: Action类HelloAction,主要任务有,一、进行业务逻辑验证,如果用户输入姓名为“Monster”,将返回错误消息;二、调用模型组件PersonBean的save()方法,保存用户输入的名字;三、决定将合适的视图组件返回给用户。 除了以上的模块,我们还要创建Struts
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第7章 Struts 与MVC 设计模式 MVC 设计 模式