假设Coffee Break的老板想在Web页上的applet中显示当前的咖啡价格。让applet直接从数据库提取价格,他就可以确信显示的是最新价格。
为此需要创建两个代码文件,一个保存applet代码,一个保存Html代码。applet代码包含一般程序都有的JDBC代码以及运行applet和显示数据库查询结果的附加代码。本例中applet代码保存在OutputApplet.Java文件中。为在HTML页中显示applet,文件OutputApplet.html会告诉浏览器要显示的内容及显示的位置。
本节其余部分讲述applet代码中的各种元素,它们在独立应用程序中是不会出现的。其中某些元素包括了Java程序设计语言的一些高级特性。这里给出了一些基本原理和基本解释,但对它们的完全解释超出了本教程范围。为完成该示例applet,只需把握一般的思想,因此不用担心没有完全了解。您可用该applet代码作模板,将查询替代为自己的即可。
编写applet代码
编写代码前,applet导入独立应用程序没有用到的一些类。applet导入了applet特有的两个类:Applet类(java.applet包的一部分)和Graphics类(java.awt包的一部分)。applet还导入了通用的java.util.Vector类以便访问类似于数组、大小可修改的容器。这些代码使用Vector对象保存查询结果以在后面显示。
所有的applet扩展了Applet类;换言之,它们是Applet的子类。因此每个appplet定义必须包含extends Applet字样,如下所示:
public class MyAppletName extends Applet {
. . .
}
在applet例子OutputApplet中,这行代码也包括implements Runnable字样,实际代码如下:
public class OutputApplet extends Applet implements Runnable {
. . .
}
Runnable是一个接口,它答应一次运行多个线程。线程是连续的控制流,程序可以是多线程的,换言之,很多线程并发地处理不同事情。OutputApplet类通过定义run方法——Runnable中的惟一方法来实现Runnable接口。本例中run方法包含有如下用途的JDBC代码:打开连接、执行查询及从结果集中检索结果。由于数据库连接可能较慢,有时需几秒钟,通常好的想法是构建一个applet以使用不同线程处理数据库工作。
与独立应用程序(需要一个main方法)类似,一个applet至少要实现一个init、start或paint方法。示例applet定义了一个start方法和一个paint方法。每次调用start时就会创建一个新线程(名为worker)以重估数据库查询。每次调用paint时要么显示查询结果,要么显示描述当前applet状态的字符串。
如前所述,OutputApplet中定义的run方法包含了JDBC代码。当线程worker调用start方法时就会自动调用run方法执行线程worker中的JDBC代码。run方法中的代码与其他示例代码中看到的带有3个异常的代码非常相似。首先它使用Vector类保存查询结果。第二它没有输出结果,而是把结果添加到Vector results中以在后面显示。第三它同样没有输出异常,而是记录错误消息以在后面显示。
applet使用各种方式描绘/显示内容。该applet是一个仅有文本的简单applet,使用drawString方法(Graphics类的一部分)显示文本。drawString方法带有3个参数:(1) 要显示的字符串;(2) x坐标——指出显示字符串的横向起点;(3) y坐标——指出显示字符串的纵向起点(这在文本下面)。
OutputApplet.java中的paint方法调用drawString方法在屏幕上实际显示内容。drawString主要显示Vector results中的数据(存储的查询结果)。当没有查询结果时,drawString将显示String message的当前内容。这个字符串将以“Initializing”开始。当调用start方法时,这个字符串设为“Connecting to database”;当碰到一个异常时,setError方法就将它设为错误消息。因此,假如数据库连接要开销一定时间,applet浏览者将会看到消息“Connecting to database”,这就是message那时的内容(当AWT要applet在屏幕上显示它的当前状态时,AWT就会调用paint方法)。
OutputApplet类中定义的最后两个方法setError和setResults是专用的,这表明它们只可让OutputApplet使用。这两个方法都调用了repaint方法以清除屏幕和调用paint。因此假如setResults调用repaint,将显示查询结果;假如setError调用repaint,将显示错误消息。
最后,OutputApplet中定义的所有方法(除run方法外)都是同步的(synchronized)。要害字synchronized表明当一个方法访问一个对象时,其他的同步方法将不可再访问那个对象。方法run没有声明为同步,因此applet仍可以在处理数据库连接时在屏幕上描绘自己。假如数据库访问方法是同步的,那么在执行期间会阻止重画applet,这就可能导致延迟,且不会显示任何相关的状态消息。
总之,好的编程习惯是在applet中做一些独立应用程序不需做的事情:
将JDBC代码放入独立的线程。
延迟期间在屏幕上显示状态消息(如在连接数据库时开销较长时间)。
在屏幕上显示错误消息,而不是将它们输出到System.out或System.err。
运行Applet
在运行示例applet前需要编译文件OutputApplet.java。编译创建了可在OutputApplet.html文件中引用的OutputApplet.class文件。
运行applet最轻易的方式是使用applet查看器(JDK的一部分)。只要使用下面各种平台下的指令就可以编译和运行OutputApplet.java:
UNIX
javac OutputApplet.java
appletviewer OutputApplet.html
Windows 95/NT
javac OutputApplet.java
appletviewer OutputApplet.html
在网上加载applet有着安全方面的限制。尽管这会显得麻烦,但对于网络安全是绝对必要的,安全是Java程序设计语言的一个主要优点。除非浏览器答应网络连接,否则applet只可对它的源主机进行网络连接。一台主机是否认为本地安装的applet是“信任的”,这取决于浏览器上设置的安全限制。applet通常不能读/写在执行它的主机上存放的文件,也不可加载库和定义本地方法。
通常applet可对它们的源主机进行网络连接,因此它们可在Intranet上很好地运行。
JDBC-ODBC Bridge驱动程序有点例外。它可以非常成功地用于Intranet访问,但它要求在每个客户端上安装ODBC、桥、桥本地库和JDBC。使用这种配置就可在Java程序和信任的applet中进行Intranet访问。由于桥要求非凡的客户端配置,所以在使用JDBC-ODBC Bridge驱动器的Internet上运行applet很不实际。这是JDBC-ODBC Bridge而不是JDBC的一个局限。假如使用纯Java JDBC驱动程序,不必做任何非凡配置就可在Internet上运行applet。