1、杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 1/11 页第 4 章 Web 系统架构设计及 MVC 模式(第 1/4 部分)在早期的软件开发实现中,人们把软件设计的重点放在数据结构和算法的选择上,如Knuth 提出了数据结构+算法= 程序。而对于大规模的复杂软件系统来说,软件系统本身的体系架构设计比起对程序的算法和数据结构的选择和设计已经变得明显更重要得多。因此,人们逐渐认识到软件体系架构设计的重要性,但什么是好的软件体系架构设计?“高内聚、低藕合”是系统设计的主要目标,但如何能够达到这样的设计目标?本章系统地介绍 Web 系统架构设计、 MV
2、C 模式及在项目中的应用;另外,也还介绍几种常见的分离系统中的类之间关系的设计方法,如利用 JSTL 标签封装业务处理逻辑代码,利用JavaBean 组件分离表现逻辑和业务处理逻辑的代码,利用 AOP 分离系统中的核心和横切关注点实现代码。1.1 Web 系统架构设计及 MVC 架构模式1.1.1 以页面为中心的 Web 系统架构1、直接使用 JSP 页面构建 Web 系统对于小型的 Web 应用系统,在设计和开发实现中,可以直接使用 JSP 页面实现技术构建,这样的设计方案也称为以页面为中心(Page Centric)的设计方案。因为在小型的 Web 应用系统中,动态功能实现比较简单,因此可
3、以将所有的动态处理和功能实现都由 JSP 页面中的 Java 脚本代码(Scriptlet)实现,如图 4.1 所示为其工作原理示图。图 4.1 以页面为中心的 Web 系统架构示图2、该架构设计方案的优缺点以页面为中心的设计方案的主要优点就是技术实现比较简单,对开发人员的技术能力的要求比较低,不需要系统地掌握 J2EE Web 开发技术就能够开发实现。但其缺点也是比较明显的,各个 JSP 页面中的 HTML 标签和 Java 脚本代码强耦合在Web浏览器JSP页面 数据库系统Http 请求Http 响应修改数据库查询数据库杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,
4、版权所有,盗版必究 , 2/11 页一起,如【例 4-2】所示的页面代码。这样的设计方案将导致 JSP 文件的实现者不仅要熟悉 Web 页面设计和实现相关的技术,也还要熟悉与 JSP 及 Java 相关的编程技术;直接在页面中内嵌与业务处理逻辑有关的功能实现代码,不利于 JSP 页面及系统的整体维护和功能扩展。开发人员因为要理解应用系统的整体流程,必须要浏览相关的各个 JSP 页面文件;各个页面之间存在强耦合和紧密相关,更改业务逻辑或数据处理相关的 Java 脚本代码,可能就需要修改相关的多个不同的 JSP 页面文件。另外,系统的整体调试也非常困难,Java 脚本代码难以阅读也无法重用,将原本
5、由Servlet 组件处理的业务流程逻辑都由 JSP 页面文件承担。3、该设计方案的主要应用场合以页面为中心的设计方案主要适用于小型的以静态页面为主的 Web 应用系统。第 2 章中的各个示例基本上都是基于这样的设计思想实现的,如【例 2-2】中的响应登录请求的responseUserLogin.jsp 页面中的代码示例、【例 2-3】中的读写 Cookie 信息的代码示例、【例 2-11】中的 利用 application 对象实现系统访问总数的计数器代码示例等。4、以页面为中心的 Web 系统架构实现示例下为以一个 Web 应用系统中的用户登录功能实现为示例,说明如何直接使用 JSP 页面
6、实现技术构建 Web 应用系统。1)实现用户登录功能的请求页面【例 4-1】为本示例中的用户登录请求的 JSP 页面代码示例,其中设计有一个登录表单,该表单向服务器端的 userLogin.jsp 页面发送 Http 请求(黑体标识的属性)。【例 4-1】用户登录请求的 JSP 页面代码示例用户登录功能的请求页面 您的名称: 您的密码:杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 3/11 页2)构建响应请求的服务器端 userLogin.jsp 页面【例 4-2】所示为响应登录请求的服务器端 userLogin.jsp 页面中的代码示例,在其中
7、利用 JSP 中的内置对象 request 获得表单中的各个请求参数;然后再识别所输入的请求参数是否满足系统中所要求的参数值(也就是登录的业务逻辑),但为了简化示例的功能实现,没有利用 JDBC 技术访问数据库表;最后,根据处理的结果显示输出不同的状态信息。【例 4-2】响应登录请求的服务器端 userLogin.jsp 页面代码示例响应请求的服务器端 userLogin.jsp 页面从【例 4-2】的示例中,明显地了解到以页面为中心的 Web 系统架构实现中,请求和杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 4/11 页响应处理都采用 JSP
8、 页面组件实现,并且直接将处理的 Java 脚本代码内嵌到 JSP 页面中。3)测试本示例的功能实现效果在浏览器中输入 http:/127.0.0.1:8080/J2EEWebApp/index.jsp 的请求 URL 地址,如图4.2(a)所示。在表单中输入登录的请求参数,用户名为 admin、密码为 1234,并提交表单后,将出现如图 4.2(b)所示的结果信息。图 4.2(a) 登录功能请求页面表单 图 4.2(b) 响应请求的结果信息如果在登录表单中输入错误的身份信息,如错误的密码登录系统,如图 4.3(a)所示。提交登录表单后,将出现如图 4.3(b)所示的处理结果信息。图 4.3(
9、a) 输入错误的密码登录系统 图 4.3(b) 响应登录失败请求的结果信息1.1.2 JSP Model One Web 系统架构1、利用 JSP Model One 模式架构 Web 应用系统该构架模式的主要实现方式是利用“JSP + JavaBeans(或者 JSP+Servlet)”等标准的J2EE Web 组件技术构建出 Web 应用系统,其核心思想是将完成业务功能处理的 Java 脚本程序代码从表现层中的各个 JSP 页面分离出,并包装到 Java 组件(JavaBean)类程序中。在 JSP 页面中通过 动作标签创建 Java 组件的对象实例,并利用和标签操作对象中的属性。但仍然还
10、需要应用 Java 脚本对业务组件中的方法进行调用和根据处理的结果转发到不同的目标页面中。2、JSP Model One 模式的工作原理图 4.4 所示为 JSP Model One 模式系统构架的工作原理图,用户在浏览器端的请求页面中发出 Http 请求,该 Http 请求一般是向应用服务器端的某个 JSP 页面发出;JSP 页面再调用具体完成业务功能的 JavaBean 组件程序中的业务功能方法,由该业务功能方法实杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 5/11 页现最终的业务功能操作(如访问数据库表中的数据等);然后业务功能组件再将处
11、理后的结果数据返回到某个显示结果的 JSP 页面中,响应请求的 JSP 页面则将处理后的结果发送到显示结果的 JSP 页面中以实现结果的显示输出。Web 应用服务器端Web浏览器客户端请求页面 响应请求的JSP 页面JavaBean 组件程序数据库系统显示处理结果 JSP 页面图 4.4 JSP Model One 模式系统构架的工作原理显示结果3、该架构模式的主要技术特性在此架构设计中的各个 JSP 页面不仅要承担系统中的各种数据输入和输出等视图(View)表现部分的功能,也还要承担系统中的请求和响应的控制调度(Control)的职责。因此,在职责分配方面体现为多重!不符合面向对象类设计中的
12、单一职责原则。另外,该设计方案也还会导致在 JSP 页面中出现大量的 Java 脚本代码,因为在 JSP 页面中还需要对业务功能组件中的业务方法进行调用,这可以参考【例 4-3】中所示的利用JSP Model One 模式构架的 Web 站点中的某个功能页面的代码示例。4、该设计方案的主要应用场合该架构模式一般适用于中型 Web 应用系统,其中的业务逻辑处理和数据访问功能实现代码并不复杂。5、JSP Model One Web 系统架构实现示例第 2 章中的【例 2-1】和【例 2-2】示例其实是以页面为中心的 Web 系统架构实现示例,现对该示例进行重构(Refactor )和扩展为采用 J
13、SP Model One 的 Web 系统架构实现。1)在项目中添加业务功能处理 UserInfoManageImple 类【例 4-3】所示为实现用户登录业务功能处理的 UserInfoManageImple 类代码示例,其中利用 UserInfoBaseVO 实体类(该类中的详细代码请参考【例 2-7】示例)包装用户登录的基本信息,并在 doUserLogin()方法中识别登录的请求参数是否为指定的值(用户名为yang、密码为 1234),注意其中黑体所标识的语句。杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 6/11 页【例 4-3】实现用
14、户登录业务功能处理的 UserInfoManageImple 类代码示例package com.px1987.webcrm.model.imple;import com.px1987.webcrm.model.vo.UserInfoBaseVO;public class UserInfoManageImple public UserInfoManageImple() public boolean doUserLogin(UserInfoBaseVO oneUserInfoBaseVO) String userName=oneUserInfoBaseVO.getUserName();String
15、 userPassWord=oneUserInfoBaseVO.getUserPassWord();if(userName.equals(“yang“) elsereturn false;2)修改【例 2-2】响应登录请求的 responseUserLogin.jsp 页面代码在【例 4-4】所示的 responseUserLogin.jsp 页面中创建业务实体类及业务类的对象实例,并利用标签直接将表单中的请求参数包装到业务实体对象中;然后再调用业务功能方法处理登录的请求,并获得和识别登录后的处理结果;如果登录成功,则保存用户的身份信息到会话 HttpSession 对象中,实现会话跟踪。如果
16、登录失败,则构建错误信息并保存到 request 请求对象中;最后分别转发跳转到不同的目标 JSP 页面中显示登录结果的状态信息,修改后的最终页面代码如【例 4-4】所示。【例 4-4】修改后的响应登录请求的 responseUserLogin.jsp 页面代码示例杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 7/11 页响应登录请求的页面 杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 8/11 页对比【例 4-4】和【例 4-2】两个示例页面中的代码,可以了解到 JSP Model One Web
17、系统架构是对以页面为中心的 Web 系统架构的设计方案的优化,但在 【例 4-4】的示例中仍然会出现 Java 脚本代码,只是比 【例 4-2】示例中的 Java 脚本代码量相对减少了,并将业务功能处理和逻辑判断等方面的代码分离到业务功能类中。3)测试本示例的最终实现效果是否正确部署本示例中的各个页面和业务功能程序类到 Tomcat 服务器中,然后在浏览器中按照图 4.5 所示的 URL 地址执行用户登录的功能页面 userLogin.jsp,并在登录表单中输入有效的身份信息,如图 4.5 所示。图 4.5 在登录表单中输入有效的身份信息单击表单中的【提交】按钮后,将出现如图 4.6(a)所示
18、的响应结果信息。而如果在图 4.5所示的登录表单中输入错误的信息,将出现如图 4.6(b)所示的响应结果信息。图 4.6(a) 响应登录成功请求的结果信息 图 4.6(b) 响应登录失败请求的结果信息1.1.3 JSP Model Two Web 系统架构1、利用 JSP Model Two 模式架构 Web 应用系统JSP Model Two Web 系统架构虽然已经具备了使用 MVC 模式实现 Web 应用系统架构的雏形,但并非严格意义上的 MVC 架构,该构架模式其实是 MVC 构架模式在 J2EE Web组件技术上的具体应用,也称为 Web MVC 架构。在 JSP Model Two
19、 Web 系统架构模式中,仍然应用 MVC 构架模式中的模型(M)视图(V)控制器(C)三种不同形式的组件来构建 Web 应用系统。其中的模型层组件(Model )由 JavaBean 组件承担,并完成业务功能和数据处理等方面的功能;而视图杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究 , 9/11 页(View)层组件由 JSP 页面承担,并实现人机交互的前台界面和处理后的结果的显示输出;而控制(Control)调度方面的功能则由系统中的 Servlet 组件承担,主要实现调度 JSP 页面和 JavaBean 组件和转发目标页面等方面的功能。2、J
20、SP Model Two 模式的工作原理如图 4.7 所示为 JSP Model Two 模式的系统构架的工作原理图,用户在浏览器端的请求页面中发出 Http 请求,该 Http 请求向应用服务器端的某个控制器 Servlet 组件发出;该Servlet 组件将根据请求的类型相应地再调用具体完成业务功能的 JavaBean 组件类中的业务功能方法,由该业务功能方法实现最终的业务功能操作和数据访问(如访问数据库表中的数据等);然后业务功能组件再将处理后的结果数据返回到该控制器 Servlet 组件中,控制器 Servlet 组件将根据处理后的结果状态的不同分别转发到对应的目标页面中显示结果,其中
21、对处理结果的显示输出和请求采用两个不同的 JSP 页面。图 4.7 JSP Model Two 模式系统构架的工作原理Web 应用服务器端Web浏览器客户端请求页面JavaBean 数据库系统显示处理结果JSP 页面显示结果响应请求的Servlet 组件3、该架构模式的主要技术特性在此架构设计中将系统中的表现层中的功能组件和业务逻辑处理功能组件彻底地分离,JSP 页面只承担输入和输出方面的功能,而业务逻辑处理和数据访问都由 JavaBean 组件程序承担。因此,各自的职责相互分离;而表现层和业务层之间的通讯,则由控制层 Servlet组件承担。整个系统中的表现、业务和控制调度三者的程序代码彻底
22、分离,各自职责单一,但有相互配合。4、该设计方案的主要应用场合该构架模式可以应用于复杂的大型 Web 应用系统的开发实现中,同时也是 J2EE 技术平台中的许多 MVC 框架如 Struts/Struts2 框架的基础架构。5、JSP Model Two Web 系统架构实现示例下面通过对【例 4-3】和【例 4-4】所示的 JSP Model One Web 系统架构实现的示例进一步完善,并重构和扩展为 JSP Model Two Web 系统架构实现。1)修改 userLogin.jsp 页面向控制层 Servlet 组件发送 Http 请求杨教授工作室 精心创作的优秀程序员 职业提升必读
23、系列资料杨教授工作室,版权所有,盗版必究, 10/11 页在 JSP Model Two Web 系统架构实现中,所有的页面请求(通过表单或者超链接)都应该要向控制层 Servlet 组件程序发送,而不再向 JSP 页面发送。因此,需要修改第 2 章【例 2-1】示例中的 userLogin.jsp 页面内的表单标签内的 action 属性为如下黑体标识的值,其中利用 EL 表达式动态获得 Web 应用系统的 Context 名称(Web 应用上下文名),并向控制层 Servlet 程序发送 Http 请求:. 其他标签,在此省略对于显示登录成功后的状态信息继续采用第 2 章【例 2-20】所
24、示的动态获得HttpServletRequest 对象中的数据的 showOneOnLineUserInfo.jsp 页面代码示例。2)设计和开发实现控制层 Servlet 组件本示例中的控制层 Servlet 组件采用第 3 章中的【例 3-1】实现用户登录功能处理的Servlet 程序类代码示例,在此不再重复地附录。3)设计和开发实现业务层业务功能处理组件本示例中的业务层中的业务功能处理组件采用【例 4-3】中的代码示例,在此不再重复地附录。4)测试本示例的最终功能效果是否正确部署本示例中的各个页面文件和业务功能类、控制层 Servlet 组件到 Tomcat 服务器中,然后在浏览器继续按
25、照图 4.5 所示的 URL 地址执行项目中的用户登录的功能页面userLogin.jsp,并在登录表单中输入有效的身份信息,如图 4.5 所示。单击表单中的【提交】按钮后,将出现如图 4.8(a)所示的响应结果信息。而如果在图 4.5所示的登录表单中输入错误的信息,将出现如图 4.8(b)所示的响应结果信息。图 4.8(a) 响应登录成功请求的结果信息 图 4.8(b) 响应登录失败请求的结果信息对比图 4.8(a)和图 4.6(a)中的浏览器 URL 地址栏中的信息,在图 4.8(a)示图中的 URL地址为请求的目标 Servlet 程序的 URL 地址,但在浏览器窗口中所显示的信息来自于
26、【例2-20】 所示的 showOneOnLineUserInfo.jsp 页面文件,因为在 Servlet 程序中采用请求转发杨教授工作室 精心创作的优秀程序员 职业提升必读系列资料杨教授工作室,版权所有,盗版必究, 11/11 页的方式跳转到目标页面中。而在图 4.6(a)示图中的 URL 地址为请求的目标 JSP 页面的URL 地址,没有经过 Servlet 程序的处理。6、理解 MVC 架构模式中所倡导的“表现”与“业务”分离的思想在 JSP Model Two Web 系统架构实现的示例中,在其中的请求页面 userLogin.jsp 中并没有包含任何的“Java 脚本 ”程序代码,如图 4.9 所示的页面标签。图 4.9 在请求页面中没有包含任何的脚本代码同样在该示例的响应输出页面中也没有包含任何的“Java 脚本”程序代码,如图 4.10所示的页面标签。图 4.10 在响应输出页面中也没有包含任何的脚本代码因此,在 JSP Model Two Web 系统架构实现中,所有与业务功能处理和请求/ 响应等调度方面的功能程序都由对应的 JavaBean 组件和 Servlet 组件承担。页面设计者美工和程序开发者程序员分工明确,Java 程序员可以集中精力创建可重用的代码,而 HTML 设计者可以集中精力于页面内容的表现实现。