Velocity空间

快速构建JAVA应用
随笔 - 11, 文章 - 15, 评论 - 5, 引用 - 0
数据加载中……

CHAPTER 2 MVC 基本原理

 

如果你已经充分了解Internet,你或许会像我一样,准备开始传统的软件开发。在此之前,我们最好先学一下方法学,以便为今后的开发节约更多的时间。

不同的开发人员(比如页面设计者和代码开发者)完成不同的开发任务,尽量避免交叉,这样做可以起到事半功倍的效果。

在这一节,我们将公正的深入讨论一下混杂式编程,同时介绍MVC方法学,并介绍MVC是如何解决混杂式编程问题的。

混合呈现和逻辑

在此,我们创建了一个嵌入数据库调用脚本的WEB页面,并对它进行分析。

<%@ page language='java' import='java.sql.*' %>

<HTML>

<HEAD>

<TITLE>Test</TITLE>

</HEAD>

<%

ResultSet rs;

try {

Class.forName("com.mysql.jdbc.Driver");

connection = DriverManager.getConnection(

"jdbc:mysql://localhost/products");

statement = connection.createStatement();

%>

<BODY>

<%

if (request.getParameter("submit") = "submit") {

rs = statement.executeQuery("SELECT username, password,

city, state FROM product where username = " +

request.getParameter("username"));

if (rs.next()) {

%>

<form action="test.jsp" method="post">

<input type="text" name="username"

value="<%= rs.getString("username") %>">

<input type="text" name="password"

value="<%= rs.getString("password") %>">

<input type="text" name="city"

value="<%= rs.getString("city") %>">

<input type="text" name="state"

value="<%= rs.getString("state") %>">

<input type="submit" name="submit" value="Update">

</form>

<% } else { %>

No Information

<% }

}

%>

else if (request.getParameter("submit") = "update") {

statement.executeUpdate("UPDATE product set password= '"

+ request.getParameter("password") + "'" +

", city = '" + request.getParameter("city") + "'" +

", state = '" + request.getParameter("state") + "'" +

"where username = '" +

request.getParameter("username"));

}

} catch(ClassNotFoundException e) {

out.println("Driver Error");

} catch(SQLException e) {

out.println("SQLException: " + e.getMessage());

}

%>

<form action="test.jsp" method="post">

<input type="text" name="username">

<input type="text" name="password">

<input type="text" name="city">

<input type="text" name="state">

<input type="submit" name="submit" value="Submit">

</form>

</BODY>

</HTML>

Listing 2.1 A mixed presentation logic page.

以上代码是JSP页面的一个混合VIEW呈现和逻辑很好的例子,让我们来考虑以下几个在使用这个页面时必须面对的问题。

作为一个开发者,假设公司让你去创建一个简单的HTML窗体,以接收或显示用户名细节情况。这个需求的改变将导致你需要从复杂的页面代码中分离出商业逻辑逻辑,并在适应的位置增加新逻辑。

当然,并非所有的页面都这么简单,有些时候,需要在页面中增加一些图片时。对代码开发者来说,由于他对界面设计不太了解,最终结果将导致页面非常难看;对页面设计者来说,由于他不了解JAVA代码,最终可能出现程序不能运行的结果。

最后的结果就页面将难以维护和继续。

我希望这个故事对你来讲最好不要成为现实,但现实的情况恬恬如此。

Smalltalk-80 MVC三合一架构

Smalltalk-80被大量使用的时候,一种用于分离显示和逻辑的方法就显得非常重要了。进行分离后,前台只负责显示任务,后台负责数据获取和格式化处理,各司其职。下图为Smalltalk-80 MVC三合一架构。


Figure 2.1
The Smalltalk-80 MVC triad.

In Figure 2.1,我们发现它有三个主要组件:model viewcontroller。下面将对这三者和它们之间的关系进行解释。

Model

MVC的模型部分通常由以下两部分组成:

类或者别的数据结构,用于呈现系统或应用程序状态

动作/方法,用于改变系统状态

在很多情况下,模型用于呈现数据库里的数据。如果你在JAVA中使用MVC,则模型将被创建为JavaBeans,用于访问或加载系统数据。

使用模型的最核心想法是为了从用户呈现页面中完全分离数据。意思是模型与所有的输入和输入无关。可以从VIEW和控制器中访问模型。控制器从用户窗体接收输入信息,当信息需要进行加工时,控制器与模型进行交互,以得到适当的数据。

为了显示模型的信息,VIEW组件在模型里注册自己。当信息发生改变时,模型通知所有注册了的VIEW,告诉他们信息已经改变,可以获取新的信息并呈现给用户。模型不限于一个VIEW,它可以允许多个VIEW进行注册,并向他们告知系统目前的状态。


Figure 2.2
Model inputs and outputs.

正如你在Figure 2.2里看到的一样,模型主要连接到数据源(可以是数据库、固定格式的文件或一些扩展接口)。模型负责维护数据的真实性和可用性和完整性。其他输入包括VIEW组件更新注册和数据更新通知。

 

View

在我们讨论模型的时候已经接触到了VIEWVIEW组件是一个可视化组件,它用于向用户显示由模型建立的数据。在多数情况下,VIEW被设计成几种格式:比如字符、简单列表或一个组合风格。

当用户需要使用模型中的信息时,应用将生成一个新的用于某种特定格式显示数据的VIEW组件,VIEW将在模型里自动注册,以便于在数据或状态发生改变时,模型好通知该生成的VIEW组件。VIEW是如何获取数据的呢?其实,他可以通过调用模型中的特定方法,或接受串行化数据对象。VIEW也可以从控制器中获取数据(下一节,我们将讨论这个问题)。

Controller

控制器组件负责处理所有在应用和用户之间的交互。所有从键盘、鼠标和其他扩展接口的输入都将被发送到控制器组件。使用预先定义的逻辑,控制器确定数据是否需要在模型里更新或是否需要创建一个新的VIEW组件。

正如你所了解的一样,一些商业逻辑都包含在控制器和模型里,在VIEW组件里不包含商业逻辑。

MVC架构

MVC架构在Gang的四本书里都有涉及(Design Patterns: Elements of Reusable Object-Oriented Software)。在高级语言里建立MVC观念需要做很多工作,比如:JAVA包括两个有个的接口,java.util.Observable java.util.Observer,用于监测和通知状态改变。在剩余章节里,我们主要关注MVCWEB开发中相关的内容。

Sun模式1 2

之前,我们讨论了Smalltalk-80MVC定义,在WEB开发的开初,用于快速开发的新技术不断产生。JSP,一个类似的技术,允许WEB页面从静态内容向动态内容转变。把JSP用于MVC的模式1时,很不幸,除非你非常小心,一个动态WEB页面看起来像Listing 2.1一样,并且有太多的VIEW和控制器代码混杂在里面。

随着servlet的发展,开发者可以把控制器代码建立在动态页面里,并在里面放置自己的组件。这时,SUN提出了模式2,因为在MVC架构里有2个组件被使用。但许多可能需要考虑,其中之一就是模式2MVC之间如果联系,许多典型的原因就是WEB应用无法利用Observer(监测)模式。

MVC扩展到WEB应用

WEB站点利用HTTP协议进行数据传递。当用户访问WEB站点时,单击按钮或链接将向WEB服务器发送一个GET POST HTTP协议请求。然后,WEB服务器处理这个请求并返回HTML页面给用户。如Figure 2.3所示


Figure 2.3
Web page processing.

正如Figure 2.3显示的一样,整个处理过程是线性的,所有信息被转换附加到请求上。事实上,在Figure 2.3显示的处理中,WEB页面直接访问数据,从VIEW到数据层之间没有任何中介处理层,这将导致许多问题,这不是一个好的处理办法。解决方法是,在处理层加入适当的层,把它们进行分离。如Figure 2.4所示的三层结构。


Figure 2.4
Three-tier Web page processing.

Figure 2.4里,我们尝试把MVC架构带入WEB开发中,以分离不同层之间的功能。

MVC实践

在学习了以上知识的基础上,让我们看一下如何把Listing 2.1中的代码转换为MVC方式,让WEB设计者和WEB开发者的工作更容易。首先,我们需要创建一个包含所有显示信息的VIEW。如Listing 2.2所示:

<HTML>

<HEAD>

<TITLE>Test</TITLE>

</HEAD>

<BODY>

<form action="ControllerServlet.jsp" method="post">

<input type="text" name="username"

value="$$username">

<input type="text" name="password"

value="$$password">

<input type="text" name="city"

value="$$city">

<input type="text" name="state"

value="$$state">

$if ($$first) {

<input type="submit" name="submit" value="Submit">

$else

<input type="submit" name="submit" value="Update">

</form>

</BODY>

</HTML>

Listing 2.2 Example view code.

正如你在Listing 2.2里看到的一样,我们仍旧需要WEB设计者拥有一些通过控制器操作MODEL模型里数据的能力。根据个人经验,在VIEW层使用Loop和条件将减轻WEB应用开发相当多的工作。这些代码不能被用户直接访问,在显示给用户之前, WEB服务器将把它当作模板进行处理。

处理来自VIEW的请求,需要创建一个servletJAVA),详见Listing 2.3

public class ControllerServet extends HttpServlet {

private AccountLocalHome home = null;

public void init() throws ServletException {

try {

Context cmp = (Context) new

InitialContext().lookup("java:comp/env/cmp");

home = (AccountLocalHome) cmp.lookup("AccountBean");

} catch (NamingException e) {

e.printStackTrace();

}

}

public void doGet(HttpServletRequest req, HttpServletResponse res)

throws IOException, ServletException {

if (home == null) {

out.println("home is null");

} else {

AccountLocal account = home.create();

ServletContext app = getServletContext();

app.setAttribute("username", account.username);

app.setAttribute("passowrd", account.password);

app.setAttribute("city", account.city);

app.setAttribute("state", account.state);

RequestDispatcher disp;

disp = app.getRequestDispatcher("/ViewAccount.tmp");

disp.forward(request, response);

}

}

}

public void doPost(HttpServletRequest req, HttpServletResponse res)

throws IOException, ServletException {

doGet(req, res);

}

}

Listing 2.3 Example servlet code.

这个Servlet可以使用EJBs作为MODEL模型组件访问数据。在很多情况下,控制器Servlet将为特定的商业功能处理其他Servlet或对象。我们的Servlet将获得一个Account对象和对象与当前WEB应用的上下文之间的联系。这个处理将把存储在上下文中的数据传送到模板代码中(Listing 2.2)。

本章小节和下章介绍

在这一章里,我们探索了一MVC架构(一个用于分离系统组件和商业逻辑的方法)。最突出的问题是在VIEW组件里应该使用什么语言。我们的解决方案是使用Velocity——一个为WEB设计者特制的用于处理信息显示的语言。在下一章里,我们将介绍Velocity,分析其结构,并且用示例说明如何把Velocity集成到MVC架构里。

※※译者注:MVC是一种方法学,而不是一种特定的语言框架※※

posted on 2008-10-11 22:51 KINGWEE 阅读(559) 评论(0)  编辑  收藏 所属分类: Velocity


只有注册用户登录后才能发表评论。


网站导航: