本文是Monica Pawlan的"JDK 1.2 Roadmap: Putting It All Together"一文的展开,它讲述了一个使用SQL命令和JDBC API的快速原型项目背后的故事。这篇文章覆盖了数据库表的定义和Swing组件的使用,而且在整个过程中给出了详尽的代码和大量的屏幕抓图。
在"JDK 1.2 Roadmap: Putting It All Together"这篇文章里,我们认识了 "杜克的面包店"的拥有人和操作者Kate Cookie。Kate曾经请程序员Madhavi Rao来为"杜克的面包店"设计了软件架构。在完成这项工作后,Madhavi去参与一个网上零售商的大规模Java开发项目,因为Kate还需要一个原型系统,Madhavi就把这个工作推荐给了我。
经过与Kate的几次协商,她描述了她的经营情况和目标,我们决定采用这样一种方法:我先拼装出一个快速原型系统,这样她就可以开始使用这个程序,以后再根据她的需求进展提出一套更加具体的要求。
Kate说她最初想要关注的是在她生意兴隆的店铺里的一些特制产品。这些产品将通过特快专递的方式邮寄给客户。具体地说,她选择了全麦烤面包、小胡萝卜饼、奶奶面包和百吉饼。她想要这个程序能够让她输入客户的数据,而且当客户的数据输入以后,她要能够通过输入客户的电话号码再点一下Find按钮就列出这个客户的信息。她还告诉我说她正在使用一台装有Microsoft Access软件的Windows PC。我提醒她说,使用什么平台并没有太大关系,因为Java技术的继承性,而且由于使用JDBC API,我们将可以使用标准的SQL命令来处理数据。如果以后我们想要使用另外一个数据库产品来代替Micosoft Access的话,我们只需要对数据库设置语句做很小的一点改动就可以很容易实现。Kate听了我的话很兴奋,于是我就开始着手工作了。
定义数据库环境 第一步首先要定义数据库环境。我决定使用一个叫做BakeryBook的数据库里的两张表,这两张表分别是Addresses和Orders。这两张表逻辑上通过一个ID字段相链接,这个ID字段在Addresses表中是主键,而在Orders表里就是名为LinkAddrTbl的第二个字段。当生成订单的时候,来自Addresses表的ID字段就被包含到Orders表中,这样订单数据就可以与客户数据相联系了。这两张表在Microsoft Access面板里描述如下。
Addresses表的字段描述,其中ID是主键
这张表里面除了ID字段是自动编号的长整数外,其他所有字段都是文本型的。自动编号字段可以为每一个写入的记录自动生成一个唯一的数字。正因为这个原因,如果不再有其他方面考虑的话,主键使用自动编号字段是自然的选择。图中的小钥匙图标表示ID字段是这个Addresses表的主键。
当Kate在电话订购中输入客户的数据时,Addresses表将是她操作的对象,也将是她预期使用这个软件的主要途径。她计划通过晚上的货物空运来配送她的新鲜面包。这个原型软件使用一个电话号码作为搜索关键词来获得已经加入到数据库里的客户信息。一旦客户的名字、地址和其他信息显示到屏幕上,Kate将能够通过点击一个单选按钮来产生一个弹出窗口,存储一个订单,然后为四种产品中的每一种(如全麦烤面包或百吉饼)输入订单编号,这样就生成了一张订单。
Orders 表的字段描述如下:
订购信息被写入到这张Orders 表中,其中字段CustID是主键。LinkAddrTbl是一个长整数,用于指回到Addresses 表中的主记录。字段wheat、 cake、 naan和 bagel也是长整数,用来存储Addresses表里某个客户的订购信息。
JDBC-ODBC ODBC是Microsoft 定义的一个API。在Sun开发Java JDBC API之前,ODBC是应用最广泛的用于访问关系数据库的编程接口。但ODBC使用的是C语言接口,这就使其在安全性、实现、健壮性和可移值性方面都表现出很多缺点。由于广泛使用了指针,要想精确地把ODBC的基于C的API转换成Java API可能会很困难。但是ODBC可以在Java平台下使用,在JDBC API的帮助下,以JDBC-ODBC桥的形式就可以很好地实现这一点。
桥 JDBC API是使用SQL的首选接口。它非常易于使用,因为程序员不必担心内存管理或字节调整这样的问题。JDBC建立于ODBC基础之上,而不是从头开始的。JDBC-ODBC桥本身就是定义在 sun.jdbc.odbc.JdbcOdbcDriver中的一个JDBC驱动。这个桥定义了作为JDBC子协议的odbc。在将来,随着大量纯Java JDBC驱动程序的开发,将使得这种JDBC-ODBC桥接方式变得多余了,但是在本文中我们需要用它来连接Microsoft Access。
Microsoft 推出了超越ODBC的一些新API,例如OLE(Object Linking and Embedding)DB,ADO(Active X Data Objects)和RDS(Remote Data Service)。OLE DB和ADO也是面向对象的可以执行SQL命令的数据库接口。然而OLE DB 是一种为工具而不是为开发人员设计的低层接口。ADO要更新些,更类似JDBC API一些,但是它不是纯的Java。RDS提供了类似于JDBC API的RowSet工具的功能,但是RDS并不是用Java编程语言写的,而且不可移植。
两层模型和三层模型 在两层模型里,Java applet或应用程序将直接与数据源对话。这就要求有一个可以与数据源进行对话的JDBC驱动程序,比如Access数据库,。用户的SQL命令被送往数据库或其他数据源,然后这些语句的执行结果又被传回给用户。
数据源可以位于另一台计算机上,用户通过网络连接到上面。这就叫做客户机/服务器配置,其中用户的计算机为客户机,提供数据库的计算机为服务器。网络可以是 intranet,也可以是 Internet。
在三层模型中,命令先是被发送到服务的"中间层",然后由它将命令发送给数据源。数据库对 SQL 语句进行处理并将结果送回到中间层,中间层再将结果送回给用户。这种三层模型提供了对于各种更新的更大控制,而且它还简化了应用程序的部署。在许多情况下,这种三层模型还可以提供性能上的优势。然而对于我们"杜克的面包店",两层模型就可以工作得很好了。
在windows 98 下配置Micosoft Access
Kate Cookie正在使用一台运行Windows 98的机器,而这台机器上还安装了Micosoft Access。所以我们需要按照以下几步通过JDBC-ODBC桥来进行通信,并且连接到名为BakeryBook的数据库。
在Windows的控制面板里,双击ODBC数据源。就会出现下面的窗口。
"杜克的面包店"数据库名为BakeryBook.mdb。选择这个条目,然后点击"Add"按钮。这时将会出现另一个标题为"Create New Data Source"的窗口。选择"Microsoft Access Driver"条目,然后点击"Finish"按钮。
这时将会出现下面这样的窗口。"杜克的面包店"数据库的名字是BakeryBook。为了找到这个数据库所在的目录路径,点击"Select"按钮,它会让您查找一个目录。当输入了数据库的名字、路径和描述文字以后,点击"Advanced"按钮。
接下来就会出现下面这个窗口。
出于演示的目的,我们输入默认的登录名"anonymous",密码为"guest"。点击"ok"关闭这个对话框,并在剩下的所有ODBC窗口中点击"OK"按钮。这就结束了配置过程。
现在我们要准备开始看一些代码了!
代码预排 我使用JFC(Java Foundation Classes)开发了一个原型GUI。它们由以下几方面组成:Abstract Window Toolkit (AWT), Accessibility API, 2D API, 对拖放功能的增强支持, 和Swing组件。
Swing组件经常被认为是轻量级的组件。因为它们是完全用Java语言写的,所以总的来说,它们并不因为主平台强加于GUI的复杂性而显得笨重。 因为下面这两个原因,我们通常不需要重量级的组件。
不同平台上的同等组件不必以同样的方式来实现其功能。
每个组件的外观(look-and-feel)是与主机操作系统密切相关的。
下面回顾一下将Swing组件和老的AWT组件区别开来的一些重要特征。
Swing提供了大量的新组件,例如表、树、滑块、进度条、内建框架和文本组件。
Swing组件能够在它们上面放置工具条提示。工具条提示就是当鼠标移动到组件所在区域时所弹出来的说明性文字。工具条提示可以为我们提供关于该组件的一些额外信息。
键盘事件可以绑定到组件,并定义它们将如何对各种各样的键击做出响应。
还有一些用来呈现您自已的轻量级Swing组件的调试支持。
Swing的出现伴随着一种默认的叫做"Metal"的look-and-feel(L&Fs),它包含了现在主流L&Fs的一些最好的图形元素。Java编程语言使得它很容易实现一些其他的L&Fs,比如类似于Windows 或Motif外观,但是对于这个应用程序来说Metal将是最合适的。
下面的代码片段来自于叫做DukeBakery的主类。这里您可以看到基本GUI组件的创建过程。 public class DukeBakery extends JFrame {
private DataPanel screenvar;
private JTextArea msgout;
private Connection dbconn;
public DukeBakery() {
super( "DUKE'S BAKERY" );
// Set up GUI environment
Container p = getContentPane();
screenvar = new DataPanel();
msgout = new JTextArea( 8, 40 );
p.setLayout( new FlowLayout() );
p.add( new JScrollPane(
screenvar ) );
p.add( new JScrollPane(msgout) );
语句super( "DUKE'S BAKERY" );的执行调用了super类Jframe的构造函数,并将字符串"DUKE'S BAKERY"放置到窗口的标题栏上。然后我们就得到了一个容器对象p,它创建一个用来连接组件以供显示的内容窗格(content pane)。接下来一个DataPanel对象被实例化。这是我自已定义的一个类,我们将在下一节中详细分析它的代码。同时,一个有8字符行和40字符列的JtextArea被实例化。语句p.setLayout( new FlowL