|
大多数企业应用都涉及从数据存储中访问数据、根据用户的请求修改或过滤数据、并最终把数据显示给用户。通常,访问、修改、格式化显示信息的代码都集中在一个单独的组件中(例如,一个Java servlet)。但随着应用变得日益复杂,维护这些无差别的代码将会变得十分困难。Model-View-Controller (MVC)Java 设计模式通过把应用功能分为三种角色解决了这个问题。
· Model 代表业务数据,以及与访问和修改这些数据相关的规则(表格、视图、数据库用户、等等)。
· View 代表用户界面(Web 页面、 WAP 界面、SOAP 、等等)
· Controller 负责接收用户的输入,将输入翻译成数据请求,然后为用户选择适当的数据视图
这种设计模式是页面流技术的基础。在一个页面流中,客户端浏览器通过HTTP get 或 post向页面流发出信息请求。然后,页面流(扮演controller的角色)处理用户的请求,向数据库、遗留系统、等等(model)发出一个数据请求。返回的数据在发送给适当的JSP 页面用于显示之前(View),可能会被提前处理一下。下图展现了这个过程。
本文将会介绍一个具体的例子,说明如何使用WebLogic Workshop 8.1中的页面流技术从数据库中获取一个数据库表的内容,然后显示给用户。本文假定您已经正确建立了一个数据连接,并对Java 、 JSP 、TSQL 比较熟悉。本文将会用到位于samples/workshop 域中的cgDataSource。
首先,在WebLogic Workshop 中创建一个名为“DataTutorial”的空应用。请确保这个新应用被设置成使用“samples/workshop”域,方法是右键单击该应用,选择“Properties”,然后单击“WebLogic Server”部分。server home directory 应该指向“<install location>weblogic81bsamplesworkshop”。现在,选择“Tools/WebLogic Server/Start Server”,启动服务器。
在新应用中,右键单击“DataTutorial”文件夹,然后创建一个名为“ItemsTable”的Web项目。右键单击新创建的 ItemsTable 项目文件夹,选择“New/Choose File Type...”,然后选择“Business Logic”组中的“Database Control”,这将会打开数据库控件向导。我们将把新的数据库控件命名为“DataModel”,并使用cgDataSource。如果在Data Source 下拉列表中没有发现cgDataSource ,请检查服务器是否已经正确启动,以及使用的是否为samples/workshop 域。单击next,选择“Don't create methods”,然后单击“Create”。通常,最好让向导来创建数据库表的访问方法。不过这里为了演示其中的原理,我们将会手工创建。
双击datamodel 文件夹中的新DataModel.jcx 文件,然后选择“Source View”。其中有几个地方需要处理。首先,把“data-source-jndi-name”从“DATA_SOURCE_JNDI”改为“cgDataSource”。然后,删除向导自动添加的schema,在本教程中我们不会用到它。DataModel 控件的代码现在应该如下所示:
|
package datamodel;
import java.sql.SQLException;
import javax.sql.RowSet;
import weblogic.jws.control.DatabaseControl;
import weblogic.jws.control.DatabaseFilter;
/**
*:connection data-source-jndi-name="cgDataSource"
*/
public interface DataModel extends DatabaseControl
{
}
|
|
很快我们将会添加一个方法来获取“Cajun” schema 中 “Items”表的所有行。不过首先需要创建一个“Item”对象来简化对返回数据的访问。请右键单击“datamodel”文件夹,然后选择“New/Java Class”。把这个类命名为“Item”。Items 表中的每一行都包含项目编号、项目名称、剩余数量、和价格信息。我们将会为Item类添加公共成员,用于存放这些信息。对于一个真正的 Java类,您通常想要添加获取、设置、和构造方法来处理变量的设置和检索,但本文的重点不是Java 类的创建,所以我们只是快速而简单地定义这个类。请不要忘记实现“java.io.Serializable”接口,这样才能把这个类传递到request 流中。完成后的Item.java 文件应该如下所示:
|
package datamodel;
public class Item implements java.io.Serializable
{
public Integer ItemNumber;
public String ItemName;
public Integer QuantityAvailable;
public Double Price;
}
|
|
现在我们将在数据库控件中构建一个方法,该方法使用新创建的Item类从Items表中获取所用数据行。在DataModel.jcx 中,进入Design View,右键单击控件,添加一个名为“getItems”的新方法。右键单击这个新方法,然后选择“Edit SQL”,这就是我们应该输入获取数据的SQL查询的地方。把以下代码输入到 SQL 框中,用于从Cajun schema 的Items 表中获取所有列:
|
SELECT ITEMNUMBER, ITEMNAME, QUANTITYAVAILABLE, PRICE FROM CAJUN.ITEMS
|
|
以上语句将会返回表中全部的项目,所以我们应该把返回类型设为一个项目数组(使用我们创建的Item类)。在Java 框中添加如下代码:
|
public Item[] getItems()
|
|
现在,如果进入 Source View,DataModel 控件的代码应该如下所示:
|
package datamodel;
import java.sql.SQLException;
import javax.sql.RowSet;
import weblogic.jws.control.DatabaseControl;
import weblogic.jws.control.DatabaseFilter;
/**
*:connection data-source-jndi-name="cgDataSource"
*/
public interface DataModel extends DatabaseControl
{
/**
* :sql statement="SELECT ITEMNUMBER, ITEMNAME, QUANTITYAVAILABLE, PRICE
FROM CAJUN.ITEMS"
*/
public Item[] getItems();
}
|
|
现在,可以在页面流中使用这个控件了。在ItemsTable 项目中,您将会看到三个文件:index.jsp 、error.jsp、和Controller.jpf。其中controller 文件是Model-View-Controller 设计模式的 controller 部分,而.JSP 文件是view 部分。
双击Controller.jpf ,确保位于“Flow View”。然后拖动DataModel.jsx 到页面流中,这样您就获得了一个可以在页面流中访问的控件实例。您的页面视图应该如下所示:
上图表明进入页面流的新用户将会首先执行“begin”方法(我们将在这里从数据库中获取数据)。我们将会把从数据库控件获得的数据放到request 流中,这样index.jsp 页面才能访问它们。请注意Data Palette中的dataModel 成员,这意味着页面流中的所有事件都可以访问我们的DataModel数据库控件。在后台,WebLogic 会创建并部署一个 Java servlet ,用于控制页面流上的动作,我们只需关注.jpf 文件中的基本代码即可。
现在,切换到 source view。因为我们将会用到Item 类,所以需要在导入部分添加一个引用,如下:
|
import datamodel.Item;
|
|
至此,从数据库中获取项目列表的准备已经完成。为了达到这个目的,我们将会添加以下代码,在begin() 方法中访问dataModel的getItems()方法。对数据库控件的调用将被括入一个try/catch 区中,这样就可以捕获所有错误并将其发送给服务器窗口。
|
protected Forward begin()
{
try
{
Item[] Items = dataModel.getItems();
getRequest().setAttribute( "items", Items );
}
catch( Throwable ex )
{
ex.printStackTrace();
}
return new Forward("index");
}
|
|
我们刚刚调用了数据库控件的getItems() 方法,并把返回值放入一个Item 数组中。现在,为了可以在.jsp 页面中访问这个数组,我们将使用setAttribute 方法将其放入 HTTP Request 流中。如果愿意的话,我们也可以直接在页面流中访问dataModel 变量,但MVC设计模式的思想是使用controller (页面流)来控制数据访问、处理错误、等等;而view (JSP 页面)只关心数据的显示。完整的Controller.jpf 应该如下所示:
|
import com.bea.wlw.netui.pageflow.PageFlowController;
import com.bea.wlw.netui.pageflow.Forward;
import datamodel.Item;
/**
* This is the default controller for a blank web application.
*/
public class Controller extends PageFlowController
{
/**
* :control
*/
private datamodel.DataModel dataModel;
/**
* :action
* :forward name="index" path="index.jsp"
*/
protected Forward begin()
{
try
{
Item[] Items = dataModel.getItems();
getRequest().setAttribute( "items", Items );
}
catch( Throwable ex )
{
ex.printStackTrace();
}
return new Forward("index");
}
}
|
|
我们已经从数据库中获取了数据并将其放入request 流中。现在,需要把item 列表显示到JSP 页面中。请双击index.jsp, 进入Source View。同样,因为我们需要在这个JSP 中使用Item 类,所以需要引用它。请像下面这样,在页面的顶部添加导入语句:
|
<% import="datamodel.Item"%>
|
|
把<title> 该成“Items Table”并添加代码,使index.jsp 如下所示:
|
<!--Generated by Weblogic Workshop-->
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
<%@ taglib uri="netui-tags-html.tld" prefix="netui"%>
<%@ taglib uri="netui-tags-template.tld" prefix="netui-template"%>
<% import="datamodel.Item"%>
<html>
<head>
<title>Items Table</title>
</head>
<body>
Here is our Items Table:<p>
<table border=1>
<tr><td>Item Number</td><td>Item Name</td><td>Quantity
Available</td><td>Price</td></tr>
<% // Get the Items from the request stream
Item oItem[] = (Item[]) request.getAttribute("items");
// Loop through the items
for (int f=0 ; f < oItem.length ; f++)
{
out.println("<tr><td>" + oItem[f].ItemNumber +
"</td><td>" + oItem[f].ItemName +
"</td><td>" + oItem[f].QuantityAvailable +
"</td><td>quot; + oItem[f].Price +
"</td></tr>");
}
%>
</table>
</body>
</html>
|
|
现在来研究一下这些代码。首先,使用下面这行代码从 request 流中获取Item 数组:
|
Item oItem[] = (Item[]) request.getAttribute("items");
|
|
然后遍历所有项目:
|
for (int f=0 ; f < oItem.length ; f++)
|
|
对于每一个项目,我们都会打印项目编号、项目名称、剩余数量、和价格到输出流中的表格单元。
|
out.println("<tr><td>" + oItem[f].ItemNumber + "</td><td>" + oItem[f].ItemName +
"</td><td>" + oItem[f].QuantityAvailable + "</td><td>quot; + oItem[f].Price +
"</td></tr>");
|
|
因为使用Item 对象来存放来自Items 表的各个列,所以我们可以方便地访问对象的成员。
现在到了最激动人心的时刻:请在菜单栏中选择 Debug/Start。所有用到的servlet、bean、文件等将被第一次构建并部署到服务器,这将会导致计算机忙碌一段时间。之后,以下信息将会出现在 Workshop 测试浏览器中:
如果没有获得以上信息,而是获得一个错误页面,请在begin 方法的第一行代码处设置一个断点,然后重新运行。逐步调试代码,您应该可以发现错误发生的地方。
注意,这个应用的URL 是Controller.jpf、而不是index.jsp。我曾经提到过,controller实际上是一个Java servlet,当需要呈现显示时,它会调用JSP文件,但核心的“controller”功能位于JPF中。我们的数据访问功能被封装在数据库控件中,从某种意义上讲,位于数据库本身之上。
尽管只是一个简单的例子,但您应该可以了解到在Web 页面中访问数据并按照用户的需要格式化数据是多么简单。我们把应用的功能分成三个独立的角色:数据库控件是我们的“model”——控制对数据库的访问并处理来自数据库的数据。在本文的例子中,controller 被命名为Controller.jpf——即页面流本身。这一部分负责处理来自用户的请求(即本例中来自主页的请求)、向Model请求数据、然后把数据显示给用户。打个比方,如果用户使用移动电话请求数据, 那么我们的controller 文件将会方便地定向到另外一个针对移动电话的 view。 我们的数据库控件可以被其他页面流或Web 服务重用。重用是MVC 设计模式的另外一个优点。如果有任何问题、bug、或意见,请访问dev2dev,网址http://dev2dev.bea.com 或中文dev2dev技术站点 http://dev2dev.bea.com.cn。
|