1、第11章 理解MVC,11.1 表示层的两种架构模式,11.2 MVC的基础,11.3 Struts2框架的MVC实现机制,11.4 Spring框架的MVC实现机制,11.1 两种架构模式,11.1.1 Model1架构模式,11.1.2 Model2架构模式,Model1架构模式的工作原理如图所示,Model1架构模式(1),Model1架构模式的工作流程:,(1)客户端发出请求,该请求由JSP页面接收。 (2)JavaBean用于实现业务模型,JSP根据请求与不同Java Bean进行交互。 (3)业务逻辑操作指定Java Bean并改变其模型状态。 (4)JSP将改变后的结果信息转发给
2、客户端。,4,Model I 体系结构,本示例演示 Model I 体系结构。客户输入产品ID时,显示相关产品信息,public class ProductBean public void setProductName(String prodName) this.productName=prodName; public String getProductName() return productname; public void setProductType(String prodType) this.productType=prodType; public String getProduct
3、Type() return productType;,这是一个 JavaBean,它为产品名称和类型定义了各种方法,建立产品模型,5,Model I 体系结构,public class ColProduct . private ConnBean cBean = ConnBean.newInstance();public Collection getProduct(String sql) Collection col = new ArrayList();try con = cBean.getConnDB();stmt = con.createStatement();rs = stmt.execu
4、teQuery(sql);while (rs.next() ProductBean product = new ProductBean();product.setProductname(rs.getString(2);product.setProducttype(rs.getString(3);product.setProductprice(rs.getInt(4);product.setBrand(rs.getString(5);product.setDescription(rs.getString(6);col.add(product); .,这个 JavaBean将数据通过Product
5、Bean放入集合ArrayList,数据处理,6,Model I 体系结构,public class ConnBean Connection con = null;private static ConnBean me = new ConnBean(); . public static ConnBean newInstance() return me;public Connection getConnDB() try Class.forName(“com.jdbc.mysql.Driver“).newInstance();con = DriverManager.getConnection(“jd
6、bc:mysql:/localhost/test“, “, “); .return con; ,这个 JavaBean实现数据库连接,数据处理,Model I 体系结构,这个 JSP 页面包含各业务操作,可以用来访问 JavaBean 组件对象,业务处理,Model I 体系结构,Model I 体系结构用于开发简单的应用程序,Model I 体系结构包括多个用户可与之交互的页面,客户端能够直接访问加载到服务器上的页面,Model I Web 应用程序由复杂的 Web 逻辑组成,并链接至Web应用程序的其他页面,Model1架构模式的实现过程是比较简单的,在这种架构模式中JSP集控制和显示于一
7、体。使用Model1模式能够快速开发一些小型项目。但是在大型应用中,这种架构模式会为应用程序的开发设计带来负面影响:,Model1架构模式,JSP页面中既包含HTML标签,又包含JavaScript代码,同时 还包含了大量Java代码,增加了JSP页面的维护难度以及程 序调试难度。 业务逻辑分布在各个JSP页面中,要想理解整个应用的执行 流程,必须明白所有JSP页面的结构。 各个组件耦合紧密,修改某一业务逻辑或者数据,需要同 时修改多个相关页面。,Model2架构模式,Model2架构模式的工作原理如图所示,Model2架构模式的工作流程:,(1)Servlet接收客户端发出的请求。 (2)S
8、ervlet根据不同的请求调用相应的JavaBean。 (3)业务逻辑操作指定JavaBean并改变其模型状态。 (4)Servlet将改变后JavaBean的业务模型传递给JSP视图。 (5)JSP将后台处理结果呈现给客户端。,与Model1架构模式相比,Model2引入了一个新的组件Servlet,将控制逻辑分离出来,降低JSP和JavaBean之间的耦合,从而提高了程序的可维护性。,11.2 MVC的基础,11.2.1 MVC的发展史,11.2.2 MVC的基本构成,11.2.3 MVC的优点及缺点,MVC,MVC是一种架构模式,也是一种设计模式。模式:针对一类问题归纳出的一种可以重复利
9、用的解决方案。MVC的最大的好处:MVC 减弱了业务逻辑接口和数据接口之间的耦合,模型-视图-控制器(MVC)是80年代Smalltalk-80出现的一种软件设计模式,现在已经被广泛的使用 在WEB应用上,J2EE平台最先应用MVC架构模式,并成为一个事实上的标准。 taobao,baidu的架构模式:数据与显示分离,MVC,MVC的基本构成,MVC设计模式将一个完整的应用分为3个组件:Model(模型),View(视图)以及Controller(控制器)。,Model(模型):该组件是对软件所处理问题逻辑的一种抽象,封装了问题的核心数据,逻辑和功能实现,独立于具体的界面显示以及I/O操作。,
10、View(视图):该组件将表示模型数据,逻辑关系以及状态信息,以某种形式展现给用户。视图组件从模型组件获得显示信息,并且对于相同的显示信息可以通过不同的显示形式或视图展现给用户。,Controller(控制器):该组件主要负责用户与软件之间的交互操作,控制模型状态变化的传播,以确保用户界面与模型状态的统一。Web应用中当用户请求到来时,控制器本身不输出任何东西也不做任何处理,它只是接收请求并决定调用哪个模型去处理该请求,然后确定使用哪个视图组件来显示模型处理返回的数据。,MVC与三层架构的异同点,它俩根本不是一个概念。 三层架构是一个分层式的软件体系架构设计,它可适用于任何一个项目。此处的MV
11、C是一种设计模式,它是根据项目的具体需求来决定是否适用于该项目. 那么架构跟设计模式有什么区别呢?从接手一个项目开始,首先,需要进行架构设计,一般采用的就是分层式的架构设计,即三层架构。然后,在确定了架构以后,再根据项目的具体需求去考虑是否需要应用一些设计模式,比如是否应用MVC模式,抽象工厂模式等等。(MVC与三层架构不是一个等级的,而与抽象工厂等同属于设计模式)最后,确定了模式以后,就是一些具体的实现了。,MVC与三层架构的异同点,三层架构将整个项目划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。 在三层架构中没有定义 Controler的概念。而MVC也没有把业务的逻
12、辑访问看成两个层,这是采用三层架构或MVC搭建程序最主要的区别。 在三层中也提到了Model,但是三层架构中Model的概念与MVC中Model的概念是不一样的,“三层”中典型的Model层是以实体类构成的,而MVC里,则是由业务逻辑与访问数据组成的。,MVC的基本构成,基于MVC模型的Web应用的基本工作流程如图所示:,整个工作流程可以分为4个步骤:,(1)用户通过视图(一般是JSP页面或HTML页面)发出请求。 (2)控制器接收请求后,调用相应的模型并改变其状态。 (3)当模型状态改变后,控制器选择对应的视图组件来反馈改变后的结果。 (4)视图根据改变后的模型,将正确的状态信息显示给用户。
13、,MVC组件类型的关系和功能,MVC的优点及缺点,1.MVC的优点体现在如下几个方面 :,有利于分工部署。使用MVC设计模式开发应用程序,不同职能的 人员分工非常明确。 降低耦合,提高可维护性。MVC设计模式将表现层与业务层有效 分离,降低了二者之间的耦合紧密程度。 提高应用程序的可重用性。对于同一个Web应用,客户可能会使用 多种方式进行访问。,2.MVC的缺点体现在如下几个方面:,MVC并不适合小型应用程序的开发设计。对于某些小型应用来说, 严格区分这3个部分会增加一些不必要的工作,影响开发效率。 基于MVC设计模式进行程序设计,要求开发人员在开始编程之前 必须精心设计程序结构;在设计过程
14、中,由于将一个完整的应用划 分为3个组件,相应增加了需要管理文件的数量。,传统web开发模式与MVC模式的比较,传统web开发模式基本上分为视图,业务逻辑2层,是水平方向的划分。 MVC模式是物理性的划分为3层,是垂直方向的划分。,MVC组件类型的关系和功能,MVC结构提供了一种按功能对各种对象进行分割的方法,其目的是为了将各对象间的耦合程度减至最小。MVC结构本来是为了将传统的输入(input)、处理(processing)、输出(output)任务运用到图形化用户交互模型中而设计的。但是,将这些概念运用于基于Web的企业级多层应用领域也是很适合的。 在MVC结构中,模型(Model)代表应
15、用程序的数据(data)和用于控制访问和修改这些数据的业务逻辑(business rule)。 当模型发生改变时,它会通知视图(View),并且为视图提供查询模型相关状态的能力。同时,它也为控制器(Controller)提供访问封装在模型内部的应用程序功能的能力。 一个视图(View)用来组织模型的内容。它从模型那里获得数据并指定这些数据如何表现。当模型变化时,视图负责维持数据表现的一致性。视图同时将用户请求告知控制器(Controller)。 控制器(Controller)定义了应用程序的行为;它负责对来自视图的用户请求进行解释,并把这些要求映射成相应的行为,这些行为由模型负责实现。在独立运
16、行的GUI客户端,用户请求可能是一些鼠标单击或是菜单选择操作。在一个Web应用程序中,它们的表现形式可能是一些来自客户端的GET或POST的HTTP请求。模型所实现的行为包括处理业务和修改模型的状态。根据用户要求和模型行为的结果,控制器选择一个视图作为对用户请求的应答。,jsp+servlet+javaBean实现MVC 流程,JSP作为视图,只用于显示 Servlet作为控制器,所有的请求,跳转都由servlet完成业务逻辑部分由javabean完成,jsp+servlet+javaBean实现MVC 技术点,视图上用javabean来传递数据在servlet中完成具体的业务逻辑。保存执行结
17、果,并把数据派发到视图。 request.setAttribute(“messages”,ret); Requestdispatcher rd=request.getRequestDispatcher(“index.jsp”); Requestdispatcher.forward(request,response);在jsp中通过request.getAttribute(“messages”)来接收这个数据,也可以通过标签(taglib)来接收这个数据,比如 ,概括一下,从程序上划分: 用于显示的页面是视图层,用于流程控制的是控制层,其余的都是模型层 各层功能:视图:1.显示格式化后的数据2.
18、向控制器发出请求控制器:1.响应视图的请求,调用相应的模型2. 根据用户请求和模型响应结果,选择合适的视图模型:提供纯数据,采用MVC结构开发的底线,所有的请求,流程控制都是由控制器完成视图部分不能有任何的业务逻辑,MVC设计模式的优势,首先,最重要的一点是多个视图能共享一个模型。由于模型返回的数据没有进行格式化,所以同样的构件能被不同界面使用,无论用户想要Flash界面或是 WAP 界面;用一个模型就能处理它们。由于已经将数据和业务逻辑从表示层分开,所以你可以最大化的重用你的代码。 因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变应用程序的数据层和业务逻辑。如果想把数据库从MyS
19、QL移植到Oracle,只需改变模型即可。一旦正确的实现了模型,视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互对立,改变其中一个不会影响其它两个,所以依据这种设计思想你能构造良好的松偶合的组件。 在MVC模式中,由于按层把系统分开,那么就能更好的实现开发中的分工。网页设计人员可以进行视图部分的开发,对业务熟悉的开发人员可开发业务模型,而其它开发人员可开发控制层。 同时,在项目维护中,因为结构清晰,非常利用维护工作。 MVC更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码。,MVC设计模式的缺点,MVC的缺点是由
20、于它没有明确的定义,所以完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。 你将不得不花费相当可观的时间去考虑如何将MVC运用到你的应用程序,同时由于模型和视图要严格的分离,这样也给调试应用程序到来了一定的困难。 增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。 视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。 视图对模型数据的低效
21、率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。,28,基于 MVC 体系结构的应用程序,MVC 体系结构遵循分层方式,用户使用该方式可将代码分别写入不同的类和方法中。以一个 简单论坛系统的部分功能为例,加以理解,.标题.,View-这个 JSP提供图形界面用于客户发新贴,基于 MVC 体系结构的应用程序,. public class newTopicServlet extends HttpServlet . public void doGet(HttpServletRequest request, HttpServ
22、letResponse response) throwsServletException, IOException .request.setCharacterEncoding(“GBK“);String title = request.getParameter(“title“);. DataBaseConn dbBean = DataBaseConn.newInstance();Connection con = dbBean.getConnDB();Statement stmt = con.createStatement(); . /* *把视图转发到viewForum.jsp */javax
23、.servlet.RequestDispatcher dis = request.getRequestDispatcher( “viewforum.jsp“);dis.forward(request, response); .,Controller-这个 Servlet转发视图,基于 MVC 体系结构的应用程序,.首页 )“上一页.,查看论坛的内容,并且进行分页显示,View-视图对象viewforum.jsp,基于 MVC 体系结构的应用程序,public class ForumServlet extends HttpServlet .PageBean page1=new PageBean(
24、);PageBean page2=page1.getResult(String)request.getParameter(“jumpPage“);/把PageBean保存到request对象中。request.setAttribute(“page2“,page2); . /* *把视图转发到view.jsp */javax.servlet.RequestDispatcher dis=request.getRequestDispatcher(“view.jsp“);dis.forward(request,response); .,Controller-控制器对象,32,基于 MVC 体系结构的应
25、用程序,.public int getMaxPage() return this.maxPage; public void setCurPage(int curPage) this.curPage = curPage; . while (rset.next() if (i (pageNum - 1) * pageBean.rowsPerPage - 1) Object obj = new Object3;obj0 = rset.getString(2); . public void setPageBean() throws Exception this.setMaxRowCount(this.
26、getAvailableCount(); /得到总行数if (this.maxRowCount % this.rowsPerPage = 0) /根据总行数计算总页数this.maxPage = this.maxRowCount / this.rowsPerPage;else this.maxPage = this.maxRowCount / this.rowsPerPage + 1; .,Model-PageBean,基于 MVC 体系结构的应用程序,. public class DataBaseConn Connection con = null;private static DataBa
27、seConn me = new DataBaseConn();public static DataBaseConn newInstance() return me;public Connection getConnDB() try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“).newInstance();con = DriverManager.getConnection(“jdbc:odbc:accp“, “, “); .public DataBaseConn() ,Model-DataBaseConn,11.3 Struts2框架的MVC实现机制
28、,11.3.1 Struts2框架的基本工作流程,11.3.2 Struts2 MVC的实现方式,11.3.3 Struts2 MVC的实际应用,Struts2框架是在Struts和WebWork基础上发展而来,它的核心架构就是基于MVC设计模式的。在实际Web应用开发过程中,Struts2框架主要用于解决表示层的相关问题。,Struts2框架的基本工作流程,Struts2框架作为一个表示层的框架,主要用于处理应用程序与客户端交互问题,基本工作流程如图所示,Struts2框架的基本工作流程,Struts2框架的基本工作流程可为5步:,(1)客户端向Struts2容器发出HttpServletR
29、equest类型的请求。 (2)FilterDispatcher接收该请求,并根据URL地址寻找并调用指定的Action类。 (3)Action类处理请求后,返回一个逻辑视图Result,该逻辑视图可映射至指定的物理视图(HTML页面或JSP页面或FreeMarker等其它视图技术)。 (4)根据Result信息在struts.xml配置文件中找到对应的物理视 图。 (5)将物理视图呈现给客户端。,Struts2框架的基本工作流程,在工作流程中,按照MVC各组件构成可将Struts2各部分划分如下,模型。Action类中封装了业务逻辑模型,在Struts2框架中Action是 作为模型存在的。
30、Action主要有两个作用:首先它可以调用相应 业务逻辑处理请求,其次它可以传递数据。视图。Struts2框架中视图有多种表现形式,除了HTML页面,JSP 页面这些常规表现形式以外,Struts2还支持FreeMarker,Tiles, SiteMesh等其它视图技术。控制器。FilterDispatcher是Struts2框架中的控制器组件,从根本上 来说FilterDispatcher是一个Servlet过滤器。客户端发送的 HttpServletRequest请求到来时,会首先经过FilterDispatcher的过滤, 由它来决定调用哪个模型(Action)来处理请求。,Struts
31、2 MVC的实际应用(1),本应用包含了前端控制器和页面控制器两种MVC实现模式。,(1)创建一个Web工程,并引入Struts2框架所需运行库文件,包括:commons-logging-1.0.4.jar,freemarker-2.3.8.jar,ognl-2.6.11.jar,struts2-core-2.0.11.jar,xwork-2.0.4.jar。,(2)在web.xml配置文件中添加Struts2控制器FilterDispatcher的相应配置,添加代码如下:,struts2org.apache.struts2.dispatcher.FilterDispatcherstruts2
32、/* ,Struts2 MVC的实际应用(2),(3)在工程的com包下创建模型类“FrontAction.java”,该类用于处理前端控制器模式下的请求,实现代码如下:,public class FrontAction private String username; /定义变量username,用于传递数值public String getUsername() return username;public void setUsername(String username) this.username = username;public String execute() /对页面传递的use
33、rname变量进行处理username = “你好“ + username + “!这是前端控制器模式!“;/ 返回一个字符串型的逻辑视图return “success“; ,Struts2 MVC的实际应用(3),(4)在工程的com包下创建模型类“PageAction.java”,该类用于处理页面控制器模式下的请求,实现代码如下:,public class PageAction private String msg; /定义变量msg,用于传递数值public String getMsg() return msg;public String execute() /对msg进行赋值msg =
34、 “这是页面控制器模式!“;/返回一个字符串型的逻辑视图return “success“; ,Struts2 MVC的实际应用(4),/front.jsp/page.jsp,(5)在工程src根目录下创建Struts2框架的核心配置文件“struts.xml”,该文件用于配置Action及Result相关信息。该文件包含的主要代码如下:,Struts2 MVC的实际应用(5),(6)修改WebRoot下“index.jsp”页面代码,提供一个文本输入框和一个提交按钮。实现代码如下:,上述代码将页面字符编码设置为“GBK”,并指定Struts2框架标签库的uri。通过标签创建一个表单,并使用标签
35、和标签分别创建一个文本输入框和提交按钮。在标签中指定“action”属性的值为“front”,当用户在该页面点击提交按钮时,将会向Struts2容器发出“front.action”的请求。,Struts2 MVC的实际应用(6),front.jsp页面将自动发出“page.action”请求 标签请求page.action,实现液面控制器模式 ,(7)在WebRoot下创建front.jsp页面,用于显示前端控制器模式下Action执行成功后的结果信息。该页面的主要实现代码如下:,(8)在WebRoot下创建page.jsp页面,用于显示液面控制器模式下Action执行成功后的结果信息。该页面
36、的主要实现代码如下:,Struts2 MVC的实际应用(7),发布运行该程序,进入index.jsp页面,如图所示,输入字符串“sunyang”,并点击确认按钮,11.4 Spring框架的MVC实现机制,11.4.1 Spring MVC的基本工作流程,11.4.2 Spring MVC的实际应用,Spring是Java企业级应用中经常被用到的一种框架技术,它以控制反转(IoC)和AOP为核心,统一管理各对象的配置、查找及应用,有效实现了业务逻辑与基础服务的分离。,IOC 控制反转,public class PersonServiceBean private PersonDao person
37、Dao = new PersonDaoBean();public void save(Person person)personDao.save(person); PersonDaoBean 是在应用内部创建及维护的。所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。,依赖注入(Dependency Injection),当我们把依赖对象交给外部容器负责创建,那么PersonServiceBean 类可以改成如下: public class PersonServiceBean private
38、PersonDao personDao ;/通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以使用setter方法进行注入。public PersonServiceBean(PersonDao personDao)this.personDao=personDao; public void save(Person person)personDao.save(person); 所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。,Spring MVC的基本工作流程(1),Spring MVC采用了松耦合以及可插拔式的组件结构,从根本上来说
39、,Spring MVC是基于Model2模式的,它的基本工作流程示意图如图所示。,Spring MVC的基本工作流程(2),Spring MVC的基本工作流程可为7步:,(1)客户端发出Http请求。 (2)Spring容器的DispatcherServlet接收请求,并根据请求寻找相应的控制器。 (3)DispatcherServlet找到具体的控制器以后,将客户端请求分派给该控制器,控制器调用业务层相关业务对象处理请求。 (4)控制器处理完毕后,将ModelAndView返回给DispatcherServlet,其中ModelAndView包含了逻辑视图名称以及物理视图所需要的数据信息。
40、(5)DispatcherServlet根据逻辑视图名称,寻找对应的物理视图。其中,ViewResolver负责建立逻辑视图与物理视图的映射关系。 (6)找到具体的物理视图以后,DispatcherServlet将其分派给View对象。 (7)View以Http响应形式将最终结果返回给客户端。,Spring MVC的实际应用(1),Spring MVC应用实例:,(1)创建一个Web工程,并引入Spring MVC所需的运行库文件spring-webmvc.jar。,(2)在web.xml文件中添加DispatcherServlet的配置信息,添加代码如下:,springMVCorg.spri
41、ngframework.web.servlet.DispatcherServletspringMVC*.html ,Spring MVC的实际应用(2),(3)在工程的com包下创建一个类“HelloController.java”,该类作为控制器,负责处理请求逻辑。实现代码如下:,public class HelloController implements Controller private String name;public String getName() return name;public void setName(String name) this.name = name;/
42、 实现Controller中的handleRequest方法public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception /三个参数分别为逻辑视图名称,传递数据的关键字,传递的值return new ModelAndView(“success“, “name“, name); ,Spring MVC的实际应用(3),(4)在工程WebRoot/WEB-INF下创建DispatcherServlet上下文配置文件“springMVC-servlet.xml”,并在该配置文件中添加控制器的配置信息。代码如下:,(5)在“springmvc-servlet.xml”中配置视图解析器,该解析器用于建立逻辑视图与物理视图的映射关系。添加代码如下:,Spring MVC的实际应用(4),(6)编写结果显示页面success.jsp,该页面主要用于显示name参数的值。添加代码如下:,你好,,发布运行程序,得到结果如图所示:,本案例的执行流程如图所示:,