﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-飘羽-文章分类-JAVA学习</title><link>http://www.cppblog.com/xmh79/category/947.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 18:41:37 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 18:41:37 GMT</pubDate><ttl>60</ttl><item><title>java下编写串口通讯程序</title><link>http://www.cppblog.com/xmh79/articles/4124.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Tue, 14 Mar 2006 02:45:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/4124.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/4124.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/4124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/4124.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/4124.html</trackback:ping><description><![CDATA[<DIV class=postTitle>1、下载java Communications api开发包。</DIV>
<DIV class=postText>
<P>2、将win32com.dll拷贝入C:\j2sdk1.4.2_04\bin </P>
<P>3、将comm.jar拷贝入C:\j2sdk1.4.2_04\jre\lib\ext </P>
<P>4、将javax.comm.properties拷贝入C:\j2sdk1.4.2_04\jre\lib </P>
<P>5、编译CommTest.java文件 </P>
<P>import java.io.*; </P>
<P>import java.util.*; </P>
<P>import javax.comm.*; </P>
<P>public class CommTest{ </P>
<P>public static void main(String[] args){</P>
<P>&nbsp;SerialPort serialPort=null; </P>
<P>DataOutputStream doutput=null; </P>
<P>InputStream inputStream; </P>
<P>CommPortIdentifier portId=null; </P>
<P>String messageString="hello \n"; </P>
<P>try{ </P>
<P>portId=CommPortIdentifier.getPortIdentifier("COM1");</P>
<P>&nbsp;}catch(NoSuchPortException ne) { </P>
<P>System.out.println("ne"); ne.printStackTrace(); </P>
<P>} </P>
<P>try{ </P>
<P>serialPort=(SerialPort) portId.open("TestComm", 5);</P>
<P>&nbsp;OutputStream output = serialPort.getOutputStream(); </P>
<P>doutput=new DataOutputStream(output); </P>
<P>inputStream = serialPort.getInputStream(); </P>
<P>}catch(PortInUseException ex) { </P>
<P>System.out.println("ex"); ex.printStackTrace(); </P>
<P>}catch(IOException ie) {</P>
<P>&nbsp;System.out.println("ie");</P>
<P>&nbsp;ie.printStackTrace();</P>
<P>&nbsp;//serialPort.close(); </P>
<P>} </P>
<P>try { </P>
<P>serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); </P>
<P>} catch (UnsupportedCommOperationException e) {} </P>
<P>} </P>
<P>try { </P>
<P>doutput.write(messageString.getBytes()); </P>
<P>} catch (IOException e) {}</P>
<P>&nbsp;} </P>
<P>6、串口打开后，用InputStream和DataOutputStream读写就可以了。</P>
<P>7、由于串口为共享资源，所以在设计程序时应采用单例模式。</P></DIV><img src ="http://www.cppblog.com/xmh79/aggbug/4124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-03-14 10:45 <a href="http://www.cppblog.com/xmh79/articles/4124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用Java实现串口全双工通讯</title><link>http://www.cppblog.com/xmh79/articles/4101.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Mon, 13 Mar 2006 10:07:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/4101.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/4101.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/4101.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/4101.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/4101.html</trackback:ping><description><![CDATA[一个嵌入式系统通常需要通过串口与其主控系统进行全双工通讯，譬如一个流水线控制系统需要不断的接受从主控系统发送来的查询和控制信息，并将执行结果或查询结果发送回主控系统。本文介绍了一个简单的通过串口实现全双工通讯的Java类库，该类库大大的简化了对串口进行操作的过程。<BR>本类库主要包括：SerialBean.java (与其他应用程序的接口), SerialBuffer.java(用来保存从串口所接收数据的缓冲区), ReadSerial.java (从串口读取数据的程序)。另外本类库还提供了一个例程SerialExample.java 作为示范。在下面的内容中将逐一对这几个部分进行详细介绍。<BR><BR>　<B>　1. SerialBean</B><BR><BR>　　SerialBean是本类库与其他应用程序的接口。该类库中定义了SerialBean的构造方法以及初始化串口，从串口读取数据，往串口写入数据以及关闭串口的函数。具体介绍如下：<BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD height=17>　　public SerialBean(int PortID)</TD></TR></TBODY></TABLE><BR>　　本函数构造一个指向特定串口的SerialBean，该串口由参数PortID所指定。PortID = 1 表示COM1，PortID = 2 表示COM2，由此类推。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public int Initialize()</TD></TR></TBODY></TABLE><BR>　　本函数初始化所指定的串口并返回初始化结果。如果初始化成功返回1，否则返回-1。初始化的结果是该串口被SerialBean独占性使用，其参数被设置为9600, N, 8, 1。如果串口被成功初始化，则打开一个进程读取从串口传入的数据并将其保存在缓冲区中。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public String ReadPort(int Length)</TD></TR></TBODY></TABLE><BR>　　本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public void WritePort(String Msg)</TD></TR></TBODY></TABLE><BR>　　本函数向串口发送一个字符串。参数Msg是需要发送的字符串。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public void ClosePort()</TD></TR></TBODY></TABLE><BR>　　本函数停止串口检测进程并关闭串口。<BR><BR>　　SerialBean的源代码如下：<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>package serial;<BR><BR>import java.io.*;<BR>import java.util.*;<BR>import javax.comm.*;<BR><BR>/**<BR>*<BR>* This bean provides some basic functions to implement full dulplex<BR>* information exchange through the srial port.<BR>*<BR>*/<BR><BR>public class SerialBean<BR>{<BR>　static String PortName;<BR>　CommPortIdentifier portId;<BR>　SerialPort serialPort;<BR>　static OutputStream out;<BR>　static InputStream in;<BR><BR>　SerialBuffer SB;<BR>　ReadSerial RT;<BR><BR>　/**<BR>　*<BR>　* Constructor<BR>　*<BR>　* @param PortID the ID of the serial to be used. 1 for COM1,<BR>　* 2 for COM2, etc.<BR>　*<BR>　*/<BR><BR>　public SerialBean(int PortID)<BR>　{<BR>　　PortName = "COM" + PortID;<BR>　}<BR><BR>　/**<BR>　*<BR>　* This function initialize the serial port for communication. It starts a<BR>　* thread which consistently monitors the serial port. Any signal captured<BR>　* from the serial port is stored into a buffer area.<BR>　*<BR>　*/<BR><BR>　public int Initialize()<BR>　{<BR><BR>　　int InitSuccess = 1;<BR>　　int InitFail = -1;<BR><BR>　　try<BR>　　{<BR><BR>　　　portId = CommPortIdentifier.getPortIdentifier(PortName);<BR><BR>　　　try<BR>　　　{<BR>　　　　serialPort = (SerialPort)<BR>　　　　portId.open("Serial_Communication", 2000);<BR>　　　} catch (PortInUseException e)<BR>　　　{<BR>　　　　return InitFail;<BR>　　　}<BR><BR>　　　//Use InputStream in to read from the serial port, and OutputStream<BR>　　　//out to write to the serial port.<BR><BR>　　try<BR>　　{<BR>　　　in = serialPort.getInputStream();<BR>　　　out = serialPort.getOutputStream();<BR>　　} catch (IOException e)<BR>　　{<BR>　　　return InitFail;<BR>　　}<BR><BR>　//Initialize the communication parameters to 9600, 8, 1, none.<BR><BR>　　try<BR>　　{<BR>　　　serialPort.setSerialPortParams(9600,<BR>　　　SerialPort.DATABITS_8,<BR>　　　SerialPort.STOPBITS_1,<BR>　　　SerialPort.PARITY_NONE);<BR>　　} catch (UnsupportedCommOperationException e)<BR>　　{<BR>　　　return InitFail;<BR>　　}<BR>　} catch (NoSuchPortException e)<BR>　{<BR>　　return InitFail;<BR>　}<BR><BR>　// when successfully open the serial port, create a new serial buffer,<BR>　// then create a thread that consistently accepts incoming signals from<BR>　// the serial port. Incoming signals are stored in the serial buffer.<BR><BR>　SB = new SerialBuffer();<BR>　RT = new ReadSerial(SB, in);<BR>　RT.start();<BR><BR>　// return success information<BR>　<BR>　return InitSuccess;<BR>　}<BR><BR>　/**<BR>　*<BR>　* This function returns a string with a certain length from the incoming<BR>　* messages.<BR>　*<BR>　* @param Length The length of the string to be returned.<BR>　*<BR>　*/<BR><BR>　public String ReadPort(int Length)<BR>　{<BR>　　String Msg;<BR>　　Msg = SB.GetMsg(Length);<BR>　　return Msg;<BR>　}<BR><BR>　/**<BR>　*<BR>　* This function sends a message through the serial port.<BR>　*<BR>　* @param Msg The string to be sent.<BR>　*<BR>　*/<BR><BR>　public void WritePort(String Msg)<BR>　{<BR>　　int c;<BR>　　try<BR>　　{<BR>　　　for (int i = 0; i &lt; Msg.length(); i++)<BR>　　　　out.write(Msg.charAt(i));<BR>　　} catch (IOException e) {}<BR>　}<BR><BR>　/**<BR>　*<BR>　* This function closes the serial port in use.<BR>　*<BR>　*/<BR><BR>　public void ClosePort()<BR>　{<BR>　　RT.stop();<BR>　　serialPort.close();<BR>　}<BR>}<BR></TD></TR></TBODY></TABLE><STRONG>2. SerialBuffer<BR><BR></STRONG>　　SerialBuffer是本类库中所定义的串口缓冲区，它定义了往该缓冲区中写入数据和从该缓冲区中读取数据所需要的函数。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public synchronized String GetMsg(int Length)</TD></TR></TBODY></TABLE><BR>　　本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public synchronized void PutChar(int c)</TD></TR></TBODY></TABLE><BR>　　本函数望串口缓冲区中写入一个字符，参数c 是需要写入的字符。<BR><BR>　　在往缓冲区写入数据或者是从缓冲区读取数据的时候，必须保证数据的同步，因此GetMsg和PutChar函数均被声明为synchronized并在具体实现中采措施实现的数据的同步。<BR><BR>　　SerialBuffer的源代码如下：<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>package serial;<BR><BR>/**<BR>*<BR>* This class implements the buffer area to store incoming data from the serial<BR>* port.<BR>*<BR>*/<BR><BR>public class SerialBuffer<BR>{<BR>　private String Content = "";<BR>　private String CurrentMsg, TempContent;<BR>　private boolean available = false;<BR>　private int LengthNeeded = 1;<BR><BR>　/**<BR>　*<BR>　* This function returns a string with a certain length from the incoming<BR>　* messages.<BR>　*<BR>　* @param Length The length of the string to be returned.<BR>　*<BR>　*/<BR><BR>public synchronized String GetMsg(int Length)<BR>{<BR>　LengthNeeded = Length;<BR>　notifyAll();<BR><BR>　if (LengthNeeded &gt; Content.length())<BR>　{<BR>　　available = false;<BR>　　while (available == false)<BR>　　{<BR>　　　try<BR>　　　{<BR>　　　　wait();<BR>　　　} catch (InterruptedException e) { }<BR>　　}<BR>　}<BR><BR>　CurrentMsg = Content.substring(0, LengthNeeded);<BR>　TempContent = Content.substring(LengthNeeded);<BR>　Content = TempContent;<BR>　LengthNeeded = 1;<BR>　notifyAll();<BR>　return CurrentMsg;<BR>}<BR><BR>/**<BR>*<BR>* This function stores a character captured from the serial port to the<BR>* buffer area.<BR>*<BR>* @param t The char value of the character to be stored.<BR>*<BR>*/<BR><BR>public synchronized void PutChar(int c)<BR>{<BR>　Character d = new Character((char) c);<BR>　Content = Content.concat(d.toString());<BR>　if (LengthNeeded &lt; Content.length())<BR>　{<BR>　　available = true;<BR>　}<BR>　notifyAll();<BR>}<BR>}<BR></TD></TR></TBODY></TABLE><BR>　<B>　3. ReadSerial</B><BR><BR>　　ReadSerial是一个进程，它不断的从指定的串口读取数据并将其存放到缓冲区中。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public ReadSerial(SerialBuffer SB, InputStream Port)</TD></TR></TBODY></TABLE><BR>　　本函数构造一个ReadSerial进程，参数SB指定存放传入数据的缓冲区，参数Port指定从串口所接收的数据流。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>　　public void run()</TD></TR></TBODY></TABLE><BR>　　ReadSerial进程的主函数，它不断的从指定的串口读取数据并将其存放到缓冲区中。<BR><BR>　　ReadSerial的源代码如下：<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>package serial;<BR><BR>import java.io.*;<BR><BR>/**<BR>*<BR>* This class reads message from the specific serial port and save<BR>* the message to the serial buffer.<BR>*<BR>*/<BR><BR>public class ReadSerial extends Thread<BR>{<BR>　private SerialBuffer ComBuffer;<BR>　private InputStream ComPort;<BR><BR>/**<BR>*<BR>* Constructor<BR>*<BR>* @param SB The buffer to save the incoming messages.<BR>* @param Port The InputStream from the specific serial port.<BR>*<BR>*/<BR><BR>public ReadSerial(SerialBuffer SB, InputStream Port)<BR>{<BR>　ComBuffer = SB;<BR>　ComPort = Port;<BR>}<BR><BR>public void run()<BR>{<BR>　int c;<BR>　try<BR>　{<BR>　　while (true)<BR>　　{<BR>　　　c = ComPort.read();<BR>　　　ComBuffer.PutChar(c);<BR>　　}<BR>　} catch (IOException e) {}<BR>}<BR>}</TD></TR></TBODY></TABLE><BR>　　<B>4. SerialExample</B><BR><BR>　　SerialExample是本类库所提供的一个例程。它所实现的功能是打开串口COM1，对其进行初始化，从串口读取信息对其进行处理后将处理结果发送到串口。<BR><BR>
<TABLE cellPadding=0 width="100%" bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>import serial.*;<BR>import java.io.*;<BR><BR>/**<BR>*<BR>* This is an example of how to use the SerialBean. It opens COM1 and reads<BR>* six messages with different length form the serial port.<BR>*<BR>*/<BR><BR>class SerialExample<BR>{<BR>　public static void main(String[] args)<BR>　{<BR>　　//TO DO: Add your JAVA codes here<BR><BR>　　SerialBean SB = new SerialBean(1);<BR>　　String Msg;<BR>　<BR>　　SB.Initialize();<BR>　　for (int i = 5; i &lt;= 10; i++)<BR>　　{<BR>　　　Msg = SB.ReadPort(i);<BR>　　　SB.WritePort("Reply: " + Msg);<BR>　　}<BR>　　SB.ClosePort();<BR>　}<BR>}<BR></TD></TR></TBODY></TABLE><BR>　　<B>5. 编译与调试</B><BR><BR>　　本类库中使用了Java Communication API (javax.comm)。这是一个Java扩展类库，并不包括在标准的Java SDK当中。如果你尚未安装这个扩展类库的话，你应该从Sun公司的Java站点下载这个类库并将其安装在你的系统上。在所下载的包里面包括一个安装说明，如果你没有正确安装这个类库及其运行环境的话，运行这个程序的时候你会找不到串口。<BR><BR>　　正确安装Java Communication API并将上述程序编译通过以后，你可以按如下方法测试这个程序。如果你只有一台机器，你可以利用一条RS-232电缆将COM1和COM2连接起来，在COM1上运行SerialExample，在COM2上运行Windows提供的超级终端程序。如果你有两台机器的话，你可以利用一条RS-232电缆将两台机器的COM1(或者是COM2)连接起来，在一端运行例程，另外一端运行Windows提供的超级终端程序。如果有必要的<BR>话，可以对SerialExample中所声明的串口进行相应改动。<BR><BR>　　本程序在Windows 2000 + Java SDK 1.3环境下编译通过并成功运行。<img src ="http://www.cppblog.com/xmh79/aggbug/4101.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-03-13 18:07 <a href="http://www.cppblog.com/xmh79/articles/4101.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实战体会Java多线程编程的精要 </title><link>http://www.cppblog.com/xmh79/articles/4090.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Mon, 13 Mar 2006 07:40:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/4090.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/4090.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/4090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/4090.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/4090.html</trackback:ping><description><![CDATA[<SPAN class=myp111><FONT id=zoom>在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多，这是因为 Java 编程语言提供了语言级的支持。本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观。读完本文以后，用户应该能够编写简单的多线程程序。 
<P><B><FONT color=#330099>为什么会排队等待？</FONT></B><BR><BR>下面的这个简单的 Java 程序完成四项不相关的任务。这样的程序有单个控制线程，控制在这四个任务之间线性地移动。此外，因为所需的资源 — 打印机、磁盘、数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间，所以每项任务都包含明显的等待时间。因此，程序在访问数据库之前必须等待打印机完成打印文件的任务，等等。如果您正在等待程序的完成，则这是对计算资源和您的时间的一种拙劣使用。改进此程序的一种方法是使它成为多线程的。</P><A id=code name=code></A>
<P><I>四项不相关的任务</I></P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>class myclass {
static public void main(String args[]) {
    print_a_file();
    manipulate_another_file();
    access_database();
    draw_picture_on_screen();
    }
}
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>在本例中，每项任务在开始之前必须等待前一项任务完成，即使所涉及的任务毫不相关也是这样。但是，在现实生活中，我们经常使用多线程模型。我们在处理某些任务的同时也可以让孩子、配偶和父母完成别的任务。例如，我在写信的同时可能打发我的儿子去邮局买邮票。用软件术语来说，这称为多个控制（或执行）线程。</P>
<P>可以用两种不同的方法来获得多个控制线程：</P>
<UL>
<LI><I>多个进程</I><BR>在大多数操作系统中都可以创建多个进程。当一个程序启动时，它可以为即将开始的每项任务创建一个进程，并允许它们同时运行。当一个程序因等待网络访问或用户输入而被阻塞时，另一个程序还可以运行，这样就增加了资源利用率。但是，按照这种方式创建每个进程要付出一定的代价：设置一个进程要占用相当一部分处理器时间和内存资源。而且，大多数操作系统不允许进程访问其他进程的内存空间。因此，进程间的通信很不方便，并且也不会将它自己提供给容易的编程模型。 
<LI><I>线程</I><BR>线程也称为轻型进程 (LWP)。因为线程只能在单个进程的作用域内活动，所以创建线程比创建进程要廉价得多。这样，因为线程允许协作和数据交换，并且在计算资源方面非常廉价，所以线程比进程更可取。线程需要操作系统的支持，因此不是所有的机器都提供线程。Java 编程语言，作为相当新的一种语言，已将线程支持与语言本身合为一体，这样就对线程提供了强健的支持。</LI></UL></FONT></SPAN><BR><BR><SPAN class=myp111><FONT id=zoom><B><FONT color=#330099>使用 Java 编程语言实现线程</FONT></B><BR><BR>Java编程语言使多线程如此简单有效，以致于某些程序员说它实际上是自然的。尽管在 Java 中使用线程比在其他语言中要容易得多，仍然有一些概念需要掌握。要记住的一件重要的事情是 <TT>main()</TT> 函数也是一个线程，并可用来做有用的工作。程序员只有在需要多个线程时才需要创建新的线程。 
<P><B>Thread 类</B><BR>Thread 类是一个具体的类，即不是抽象类，该类封装了线程的行为。要创建一个线程，程序员必须创建一个从 Thread 类导出的新类。程序员必须覆盖 Thread 的 <TT>run()</TT> 函数来完成有用的工作。用户并不直接调用此函数；而是必须调用 Thread 的 <TT>start()</TT> 函数，该函数再调用 <TT>run()</TT>。下面的代码说明了它的用法：</P>
<P><I>创建两个新线程</I></P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>import java.util.*;

class TimePrinter extends Thread {
    int pauseTime;
    String name;
    public TimePrinter(int x, String n) {
        pauseTime = x;
        name = n;
    }

    public void run() {
        while(true) {
            try {
                System.out.println(name + ":" + new
                    Date(System.currentTimeMillis()));
                Thread.sleep(pauseTime);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
    }

    static public void main(String args[]) {
        TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
        tp1.start();
        TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
        tp2.start();

    }
}
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>在本例中，我们可以看到一个简单的程序，它按两个不同的时间间隔（1 秒和 3 秒）在屏幕上显示当前时间。这是通过创建两个新线程来完成的，包括 <TT>main()</TT> 共三个线程。但是，因为有时要作为线程运行的类可能已经是某个类层次的一部分，所以就不能再按这种机制创建线程。虽然在同一个类中可以实现任意数量的接口，但 Java 编程语言只允许一个类有一个父类。同时，某些程序员避免从 Thread 类导出，因为它强加了类层次。对于这种情况，就要 <I>runnable 接口</I>。</P>
<P><B>Runnable 接口</B><BR>此接口只有一个函数，<TT>run()</TT>，此函数必须由实现了此接口的类实现。但是，就运行这个类而论，其语义与前一个示例稍有不同。我们可以用 runnable 接口改写前一个示例。（不同的部分用黑体表示。） <!--  and show the differences in red. --></P>
<P><I>创建两个新线程而不强加类层次</I></P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>import java.util.*;

class TimePrinter <B>implements Runnable</B> {
    int pauseTime;
    String name;
    public TimePrinter(int x, String n) {
        pauseTime = x;
        name = n;
    }

    public void run() {
        while(true) {
            try {
                System.out.println(name + ":" + new
                    Date(System.currentTimeMillis()));
                Thread.sleep(pauseTime);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
    }

    static public void main(String args[]) {
        <B>Thread t1 = new Thread</B>(new TimePrinter(1000, "Fast Guy"));
        t1.start();
        <B>Thread t2 = new Thread</B>(new TimePrinter(3000, "Slow Guy"));
        t2.start();

    }
}
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>请注意，当使用 runnable 接口时，您不能直接创建所需类的对象并运行它；必须从 Thread 类的一个实例内部运行它。许多程序员更喜欢 runnable 接口，因为从 Thread 类继承会强加类层次。</P>
<P><B>synchronized 关键字</B><BR>到目前为止，我们看到的示例都只是以非常简单的方式来利用线程。只有最小的数据流，而且不会出现两个线程访问同一个对象的情况。但是，在大多数有用的程序中，线程之间通常有信息流。试考虑一个金融应用程序，它有一个 Account 对象，如下例中所示：</P>
<P><I>一个银行中的多项活动</I></P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>public class Account {
    String holderName;
    float amount;
    public Account(String name, float amt) {
        holderName = name;
        amount = amt;
    }

    public void deposit(float amt) {
        amount += amt;
    }

    public void withdraw(float amt) {
        amount -= amt;
    }

    public float checkBalance() {
        return amount;
    }
}
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>在此代码样例中潜伏着一个错误。如果此类用于单线程应用程序，不会有任何问题。但是，在多线程应用程序的情况中，不同的线程就有可能同时访问同一个 Account 对象，比如说一个联合帐户的所有者在不同的 ATM 上同时进行访问。在这种情况下，存入和支出就可能以这样的方式发生：一个事务被另一个事务覆盖。这种情况将是灾难性的。但是，Java 编程语言提供了一种简单的机制来防止发生这种覆盖。每个对象在运行时都有一个关联的锁。这个锁可通过为方法添加关键字 <TT>synchronized</TT> 来获得。这样，修订过的 Account 对象（如下所示）将不会遭受像数据损坏这样的错误：</P>
<P><I>对一个银行中的多项活动进行同步处理</I></P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>public class Account {
    String holderName;
    float amount;
    public Account(String name, float amt) {
        holderName = name;
        amount = amt;
    }

    public <B>synchronized</B> void deposit(float amt) {
        amount += amt;
    }

    public <B>synchronized</B> void withdraw(float amt) {
        amount -= amt;
    }

    public float checkBalance() {
        return amount;
    }
}</PRE></TD></TR></TBODY></TABLE><BR>
<P><TT>deposit()</TT> 和 <TT>withdraw()</TT> 函数都需要这个锁来进行操作，所以当一个函数运行时，另一个函数就被阻塞。请注意，<TT> checkBalance()</TT> 未作更改，它严格是一个读函数。因为 <TT>checkBalance()</TT> 未作同步处理，所以任何其他方法都不会阻塞它，它也不会阻塞任何其他方法，不管那些方法是否进行了同步处理。<BR><BR><BR><SPAN class=myp111><FONT id=zoom><B><FONT color=#330099>Java 编程语言中的高级多线程支持</FONT></B><BR><BR></P>
<P><B>线程组</B><BR>线程是被个别创建的，但可以将它们归类到<I>线程组</I>中，以便于调试和监视。只能在创建线程的同时将它与一个线程组相关联。在使用大量线程的程序中，使用线程组组织线程可能很有帮助。可以将它们看作是计算机上的目录和文件结构。</P>
<P><B>线程间发信</B><BR>当线程在继续执行前需要等待一个条件时，仅有 <TT>synchronized</TT> 关键字是不够的。虽然 <TT>synchronized</TT> 关键字阻止并发更新一个对象，但它没有实现<I>线程间发信</I>。Object 类为此提供了三个函数：<TT>wait()</TT>、<TT>notify()</TT> 和 <TT>notifyAll()</TT>。以全球气候预测程序为例。这些程序通过将地球分为许多单元，在每个循环中，每个单元的计算都是隔离进行的，直到这些值趋于稳定，然后相邻单元之间就会交换一些数据。所以，从本质上讲，在每个循环中各个线程都必须等待所有线程完成各自的任务以后才能进入下一个循环。这个模型称为<I> 屏蔽同步</I>，下例说明了这个模型：</P>
<P><I>屏蔽同步</I></P>
<P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>public class BSync {
    int totalThreads;
    int currentThreads;

    public BSync(int x) {
        totalThreads = x;
        currentThreads = 0;
    }

    public synchronized void waitForAll() {
        currentThreads++;
        if(currentThreads &lt; totalThreads) {
            try {
                wait();
            } catch (Exception e) {}
        }
        else {
            currentThreads = 0;
            notifyAll();
        }
    }
}
</PRE></TD></TR></TBODY></TABLE><BR><BR></P>
<P>当对一个线程调用 <TT>wait()</TT> 时，该线程就被有效阻塞，只到另一个线程对同一个对象调用 <TT>notify()</TT> 或 <TT>notifyAll()</TT> 为止。因此，在前一个示例中，不同的线程在完成它们的工作以后将调用 <TT>waitForAll()</TT> 函数，最后一个线程将触发 <TT>notifyAll()</TT> 函数，该函数将释放所有的线程。第三个函数 <TT>notify()</TT> 只通知一个正在等待的线程，当对每次只能由一个线程使用的资源进行访问限制时，这个函数很有用。但是，不可能预知哪个线程会获得这个通知，因为这取决于 Java 虚拟机 (JVM) 调度算法。</P>
<P><B>将 CPU 让给另一个线程</B><BR>当线程放弃某个稀有的资源（如数据库连接或网络端口）时，它可能调用 <TT>yield()</TT> 函数临时降低自己的优先级，以便某个其他线程能够运行。</P>
<P><B>守护线程</B><BR>有两类线程：用户线程和守护线程。<I>用户线程</I>是那些完成有用工作的线程。<I> 守护线程</I>是那些仅提供辅助功能的线程。Thread 类提供了 <TT>setDaemon()</TT> 函数。Java 程序将运行到所有用户线程终止，然后它将破坏所有的守护线程。在 Java 虚拟机 (JVM) 中，即使在 main 结束以后，如果另一个用户线程仍在运行，则程序仍然可以继续运行。<BR><BR><SPAN class=myp111><FONT id=zoom><B><FONT color=#330099>避免不提倡使用的方法</FONT></B><BR><BR>不提倡使用的方法是为支持向后兼容性而保留的那些方法，它们在以后的版本中可能出现，也可能不出现。Java 多线程支持在版本 1.1 和版本 1.2 中做了重大修订，<TT>stop()</TT>、<TT>suspend()</TT> 和 <TT>resume()</TT> 函数已不提倡使用。这些函数在 JVM 中可能引入微妙的错误。虽然函数名可能听起来很诱人，但请抵制诱惑不要使用它们。<!-- The Java gurus suggest that a thread should be allowed to return from <tt>run()</tt> function gracefully instead of using the <tt>stop()</tt> function, which is akin to jumping from a speeding train. --> </P>
<P><B><FONT color=#330099>调试线程化的程序</FONT></B><BR><BR>在线程化的程序中，可能发生的某些常见而讨厌的情况是死锁、活锁、内存损坏和资源耗尽。</P>
<P><B>死锁</B><BR>死锁可能是多线程程序最常见的问题。当一个线程需要一个资源而另一个线程持有该资源的锁时，就会发生死锁。这种情况通常很难检测。但是，解决方案却相当好：在所有的线程中按相同的次序获取所有资源锁。例如，如果有四个资源 —A、B、C 和 D — 并且一个线程可能要获取四个资源中任何一个资源的锁，则请确保在获取对 B 的锁之前首先获取对 A 的锁，依此类推。如果“线程 1”希望获取对 B 和 C 的锁，而“线程 2”获取了 A、C 和 D 的锁，则这一技术可能导致阻塞，但它永远不会在这四个锁上造成死锁。</P>
<P><B>活锁</B><BR>当一个线程忙于接受新任务以致它永远没有机会完成任何任务时，就会发生活锁。这个线程最终将超出缓冲区并导致程序崩溃。试想一个秘书需要录入一封信，但她一直在忙于接电话，所以这封信永远不会被录入。</P>
<P><B>内存损坏</B><BR>如果明智地使用 <TT>synchronized</TT> 关键字，则完全可以避免内存错误这种气死人的问题。</P>
<P><B>资源耗尽</B><BR>某些系统资源是有限的，如文件描述符。多线程程序可能耗尽资源，因为每个线程都可能希望有一个这样的资源。如果线程数相当大，或者某个资源的侯选线程数远远超过了可用的资源数，则最好使用<I> 资源池</I>。一个最好的示例是数据库连接池。只要线程需要使用一个数据库连接，它就从池中取出一个，使用以后再将它返回池中。资源池也称为<I> 资源库</I>。</P>
<P><B><FONT color=#330099>调试大量的线程</FONT></B><BR><BR>有时一个程序因为有大量的线程在运行而极难调试。在这种情况下，下面的这个类可能会派上用场： </P>
<P></P>
<P>
<TABLE class=code-sample cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD><PRE>public class Probe extends Thread {
    public Probe() {}
    public void run() {

        while(true) {
            Thread[] x = new Thread[100];
            Thread.enumerate(x);

            for(int i=0; i&lt;100; i++) {
            Thread t = x[i];
            if(t == null)
                break;
            else
                System.out.println(t.getName() + "\t" + t.getPriority()
                + "\t" + t.isAlive() + "\t" + t.isDaemon());
            }
        }
    }
}
</PRE></TD></TR></TBODY></TABLE></FONT></SPAN></P></FONT></SPAN></FONT></SPAN><STRONG><FONT color=#330099>限制线程优先级和调度<BR><BR></FONT></STRONG>Java 线程模型涉及可以动态更改的线程优先级。本质上，线程的优先级是从 1 到 10 之间的一个数字，数字越大表明任务越紧急。JVM 标准首先调用优先级较高的线程，然后才调用优先级较低的线程。但是，该标准对具有相同优先级的线程的处理是随机的。如何处理这些线程取决于基层的操作系统策略。在某些情况下，优先级相同的线程分时运行；在另一些情况下，线程将一直运行到结束。请记住，Java 支持 10 个优先级，基层操作系统支持的优先级可能要少得多，这样会造成一些混乱。因此，只能将优先级作为一种很粗略的工具使用。最后的控制可以通过明智地使用 <TT>yield()</TT> 函数来完成。通常情况下，请不要依靠线程优先级来控制线程的状态。</CCID_NOBR> 
<P></P><B><FONT color=#330099>小结</FONT></B><BR><BR>本文说明了在 Java 程序中如何使用线程。像是否<I>应该</I>使用线程这样的更重要的问题在很大程序上取决于手头的应用程序。决定是否在应用程序中使用多线程的一种方法是，估计可以并行运行的代码量。并记住以下几点： 
<P></P>
<UL>
<LI>使用多线程不会增加 CPU 的能力。但是如果使用 JVM 的本地线程实现，则不同的线程可以在不同的处理器上同时运行（在多 CPU 的机器中），从而使多 CPU 机器得到充分利用。 
<LI>如果应用程序是计算密集型的，并受 CPU 功能的制约，则只有多 CPU 机器能够从更多的线程中受益。 
<LI>当应用程序必须等待缓慢的资源（如网络连接或数据库连接）时，或者当应用程序是非交互式的时，多线程通常是有利的。</LI></UL>
<P>基于 Internet 的软件有必要是多线程的；否则，用户将感觉应用程序反映迟钝。例如，当开发要支持大量客户机的服务器时，多线程可以使编程较为容易。在这种情况下，每个线程可以为不同的客户或客户组服务，从而缩短了响应时间。</P>
<P>某些程序员可能在 C 和其他语言中使用过线程，在那些语言中对线程没有语言支持。这些程序员可能通常都被搞得对线程失去了信心。</P><A id=resources name=resources></A>
<P><STRONG class=subhead>参考资料</STRONG></P>
<UL>
<LI>请阅读 Scott Oaks 和 Henry Wong 所著的</LI></UL><img src ="http://www.cppblog.com/xmh79/aggbug/4090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-03-13 15:40 <a href="http://www.cppblog.com/xmh79/articles/4090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>j2ee的13种核心技术</title><link>http://www.cppblog.com/xmh79/articles/3375.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Tue, 21 Feb 2006 07:07:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/3375.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/3375.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/3375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/3375.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/3375.html</trackback:ping><description><![CDATA[<P>英文原版：<A href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1201-weblogic_p.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1201-weblogic_p.html</A></P>
<P>　　内容简介</P>
<P>　　STEVEN GOULD在文中介绍了JAVA2平台企业版（J2EE）的13种核心技术：JDBC, JNDI, EJBS, RMI, JSP, JAVA SERVLETS, XML, JMS, JAVA IDL, JTS, JTA, JAVAMAIL 和 JAF。为了联系实际，GOULD基于WEBLOGIC应用服务器—来自BEA SYSTEMS公司的一种广为应用的产品—环境来介绍J2EE的这些技术。</P>
<P>　　JAVA最初是在浏览器和客户端机器中粉墨登场的。当时，很多人质疑它是否适合做服务器端的开发。现在，随着对JAVA2平台企业版（J2EE）第三方支持的增多，JAVA被广泛接纳为开发企业级服务器端解决方案的首选平台之一。</P>
<P>　　J2EE平台由一整套服务（SERVICES）、应用程序接口（APIS）和协议构成，它对开发基于WEB的多层应用提供了功能支持。</P>
<P>　　在本文中我将解释支撑J2EE的13种核心技术：JDBC, JNDI, EJBS, RMI, JSP, JAVA SERVLETS, XML, JMS, JAVA IDL, JTS, JTA, JAVAMAIL 和 JAF，同时还将描述在何时、何处需要使用这些技术。当然，我还要介绍这些不同的技术之间是如何交互的。</P>
<P>　　此外，为了让您更好地感受J2EE的真实应用，我将在WEBLOGIC应用服务器—来自BEA SYSTEMS公司的一种广为应用的产品—环境下来介绍这些技术。不论对于WEBLOGIC应用服务器和J2EE的新手，还是那些想了解J2EE能带来什么好处的项目管理者和系统分析员，相信本文一定很有参考价值。</P>
<P>　　宏观印象: 分布式结构和J2EE</P>
<P>　　过去，二层化应用 -- 通常被称为CLIENT/SERVER应用 -- 是大家谈论的最多的。图1刻画了典型的二层化结构。在很多情况下，服务器提供的唯一服务就是数据库服务。在这种解决方案中，客户端程序负责数据访问、实现业务逻辑、用合适的样式显示结果、弹出预设的用户界面、接受用户输入等。CLIENT/SERVER结构通常在第一次部署的时候比较容易，但难于升级或改进，而且经常基于某种专有的协议—通常是某种数据库协议。它使得重用业务逻辑和界面逻辑非常困难。更重要的是，在WEB时代，二层化应用通常不能体现出很好的伸缩性，因而很难适应INTERNET的要求。</P>
<P align=center></P>
<P>　　图1. 二层化应用结构</P>
<P>　　SUN设计J2EE的部分起因就是想解决二层化结构的缺陷。于是，J2EE定义了一套标准来简化N层企业级应用的开发。它定义了一套标准化的组件，并为这些组件提供了完整的服务。J2EE还自动为应用程序处理了很多实现细节，如安全、多线程等。</P>
<P>　　用J2EE开发N层应用包括将二层化结构中的不同层面切分成许多层。一个N层化应用A能够为以下的每种服务提供一个分开的层： </P>
<P>　　显示：在一个典型的WEB应用中，客户端机器上运行的浏览器负责实现用户界面。 </P>
<P>　　动态生成显示: 尽管浏览器可以完成某些动态内容显示，但为了兼容不同的浏览器，这些动态生成工作应该放在WEB服务器端进行，使用JSP、SERVLETS，或者XML（可扩展标记语言）和（可扩展样式表语言）。 </P>
<P>　　业务逻辑：业务逻辑适合用SESSION EJBS（后面将介绍）来实现。 </P>
<P>　　数据访问：数据访问适合用ENTITY EJBS（后面将介绍）和JDBC来实现。 </P>
<P>　　后台系统集成: 同后台系统的集成可能需要用到许多不同的技术，至于何种最佳需要根据后台系统的特征而定。 </P>
<P>　　您可能开始诧异：为什么有这么多的层？事实上，多层方式可以使企业级应用具有很强的伸缩性，它允许每层专注于特定的角色。例如，让WEB服务器负责提供页面，应用服务器处理应用逻辑，而数据库服务器提供数据库服务。</P>
<P>　　由于J2EE建立在JAVA2平台标准版（J2SE）的基础上，所以具备了J2SE的所有优点和功能。包括“编写一次，到处可用”的可移植性、通过JDBC访问数据库、同原有企业资源进行交互的CORBA技术，以及一个经过验证的安全模型。在这些基础上，J2EE又增加了对EJB（企业级JAVA组件）、JAVA SERVLETS、JAVA服务器页面（JSPS）和XML技术的支持。</P>
<P>　　分布式结构与WEBLOGIC应用服务器</P>
<P>　　J2EE提供了一个框架--一套标准API--用于开发分布式结构的应用，这个框架的实际实现留给了第三方厂商。部分厂商只是专注于整个J2EE架构中的的特定组件，例如APACHE的TOMCAT提供了对JSP和SERVLETS的支持，BEA系统公司则通过其WEBLOGIC应用服务器产品为整个J2EE规范提供了一个较为完整的实现。</P>
<P>　　WEBLOGIC服务器已使建立和部署伸缩性较好的分布式应用的过程大为简化。WEBLOGIC和J2EE代你处理了大量常规的编程任务，包括提供事务服务、安全领域、可靠的消息、名字和目录服务、数据库访问和连接池、线程池、负载平衡和容错处理等。</P>
<P>　　通过以一种标准、易用的方式提供这些公共服务，象WEBLOGIC服务器这样的产品造就了具有更好伸缩性和可维护性的应用系统，使其为大量的用户提供了增长的可用性。</P>
<P>　　J2EE技术</P>
<P>　　在接下来的部分里，我们将描述构成J2EE的各种技术，并且了解WEBLOGIC服务器是如何在一个分布式应用中对它们进行支持的。最常用的J2EE技术应该是JDBC、JNDI、EJB、JSP和SERVLETS，对这些我们将作更仔细的考察。</P>
<P>　　图2表示了在一个分布式应用中，J2EE技术的各个方面通常在何处发挥作用。</P>
<P align=center></P>
<P>　　图2. 一个N层应用结构的例子 </P>
<P>　　JAVA DATABASE CONNECTIVITY (JDBC)</P>
<P>　　JDBC API以一种统一的方式来对各种各样的数据库进行存取。和ODBC一样，JDBC为开发人员隐藏了不同数据库的不同特性。另外，由于JDBC建立在JAVA的基础上,因此还提供了数据库存取的平台独立性。</P>
<P>　　JDBC定义了4种不同的驱动程序，现分述如下：</P>
<P>　　类型 1: JDBC-ODBC BRIDGE</P>
<P>　　在JDBC出现的初期，JDBC-ODBC桥显然是非常有实用意义的，通过JDBC-ODBC桥，开发人员可以使用JDBC来存取ODBC数据源。不足的是，他需要在客户端安装ODBC驱动程序，换句话说，必须安装MICROSOFT WINDOWS的某个版本。使用这一类型你需要牺牲JDBC的平台独立性。另外，ODBC驱动程序还需要具有客户端的控制权限。</P>
<P>　　类型 2: JDBC-NATIVE DRIVER BRIDGE</P>
<P>　　JDBC本地驱动程序桥提供了一种JDBC接口，它建立在本地数据库驱动程序的顶层，而不需要使用ODBC。 JDBC驱动程序将对数据库的API从标准的JDBC调用转换为本地调用。使用此类型需要牺牲JDBC的平台独立性，还要求在客户端安装一些本地代码。</P>
<P>　　类型 3: JDBC-NETWORK BRIDGE</P>
<P>　　JDBC网络桥驱动程序不再需要客户端数据库驱动程序。它使用网络上的中间服务器来存取数据库。这种应用使得以下技术的实现有了可能，这些技术包括负载均衡、连接缓冲池和数据缓存等。由于第3种类型往往只需要相对更少的下载时间，具有平台独立性，而且不需要在客户端安装并取得控制权，所以很适合于INTERNET上的应用。</P>
<P>　　类型 4: PURE JAVA DRIVER</P>
<P>　　第4种类型通过使用一个纯JAVA数据库驱动程序来执行数据库的直接访问。此类型实际上在客户端实现了2层结构。要在N-层结构中应用，一个更好的做法是编写一个EJB，让它包含存取代码并提供一个对客户端具有数据库独立性的服务。</P>
<P>　　WEBLOGIC服务器为一些通常的数据库提供了JDBC驱动程序，包括ORACLE, SYBASE, MICROSOFT SQL SERVER以及INFORMIX。它也带有一种JDBC驱动程序用于CLOUDSCAPE，这是一种纯JAVA的DBMS，WEBLOGIC服务器中带有该数据库的评估版本。</P>
<P>　　以下让我们看一个实例。</P>
<P>　　JDBC实例</P>
<P>　　在这个例子中我们假定你已经在CLOUDSCAPE中建立了一个PHONEBOOK数据库，并且包含一个表，名为 CONTACT_TABLE ，它带有2个字段：NAME 和 PHONE。 开始的时候先装载CLOUDSCAPE JDBC DRIVER，并请求 DRIVER MANAGER得到一个对PHONEBOOK CLOUDSCAPE数据库的连接。通过这一连接，我们可以构造一个 STATEMENT 对象并用它来执行一个简单的SQL查询。最后，用循环来遍历结果集的所有数据，并用标准输出将NAME和PHONE字段的内容进行输出。</P>
<P>IMPORT JAVA.SQL.*;</P>
<P>PUBLIC CLASS JDBCEXAMPLE<BR>{<BR>PUBLIC STATIC VOID MAIN( STRING ARGS[] )<BR>{<BR>TRY<BR>{<BR>CLASS.FORNAME("COM.CLOUDSCAPE.CORE.JDBCDRIVER");<BR>CONNECTION CONN = DRIVERMANAGER.GETCONNECTION("JDBC:CLOUDSCAPE:PHONEBOOK");<BR>STATEMENT STMT = CONN.CREATESTATEMENT();<BR>STRING SQL = "SELECT NAME, PHONE FROM CONTACT_TABLE ORDER BY NAME";<BR>RESULTSET RESULTSET = STMT.EXECUTEQUERY( SQL );</P>
<P>STRING NAME;<BR>STRING PHONE;<BR>WHILE ( RESULTSET.NEXT() )<BR>{<BR>NAME = RESULTSET.GETSTRING(1).TRIM();<BR>PHONE = RESULTSET.GETSTRING(2).TRIM();<BR>SYSTEM.OUT.PRINTLN( NAME + ", " + PHONE );<BR>}<BR>}<BR>CATCH ( EXCEPTION E )<BR>{<BR>// HANDLE EXCEPTION HERE<BR>E.PRINTSTACKTRACE();<BR>}<BR>}<BR>}</P>
<P><BR>　　OK。接着我们来看一看JDBC是如何在企业应用中的进行使用。</P>
<P>　　JDBC在企业级应用中的应用</P>
<P>　　以上实例其实是很基本的，可能有些微不足道。它假定了一个2层结构。在一个多层的企业级应用中，更大的可能是在客户端和一个EJB进行通信，该EJB将建立数据库连接。为了实现和改进可伸缩性和系统性能， WEBLOGIC服务器提供了对连接缓冲池CONNECTION POOL的支持。</P>
<P>　　CONNECTION POOL减少了建立和释放数据库连接的消耗。在系统启动以后即可建立这样的缓冲池，此后如故再有对数据库的请求，WEBLOGIC服务器可以很简单地从缓冲池中取出数据。数据缓冲池可以在WEBLOGIC服务器的 WEBLOGIC.PROPERTIES 文件中进行定义。(可参考 WEBLOGIC.PROPERTIES 文件中的例子，WEBLOGIC服务器的文档中还有更详细的参考信息)</P>
<P>　　在企业级应用的另一个常见的数据库特性是事务处理。事务是一组申明STATEMENT，它们必须做为同一个STATEMENT来处理以保证数据完整性。缺省情况下JDBC使用 AUTO-COMMIT 事务模式。这可以通过使用CONNECTION类的 SETAUTOCOMMIT() 方法来实现。</P>
<P>　　现在我们已经对JDBC有了一些认识，下面该转向JNDI了。</P>
<P>　　JAVA NAMING AND DIRECTORY INTERFACE (JNDI)</P>
<P>　　JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源如DNS和LDAP，本地文件系统，后者在应用服务器中的对象。</P>
<P>　　在JNDI中，在目录结构中的每一个结点称为CONTEXT。每一个JNDI名字都是相对于CONTEXT的。这里没有绝对名字的概念存在。对一个应用来说，它可以通过使用 INITIALCONTEXT 类来得到其第一个CONTEXT:</P>
<P>　　CONTEXT CTX = NEW INITIALCONTEXT();</P>
<P>　　应用可以通过这个初始化的CONTEXT经有这个目录树来定位它所需要的资源或对象。例如，假设你在WEBLOGIC服务器中展开了一个EJB并将HOME接口绑定到名字 MYAPP.MYEJB ，那么该EJB的某个客户在取得一个初始化CONTEXT以后，可以通过以下语句定位HOME接口：</P>
<P>　　MYEJBHOME HOME = CTX.LOOKUP( "MYAPP.MYEJB" );</P>
<P>　　在这个例子中，一旦你有了对被请求对象的参考，EJB的HOME接口就可以在它上面调用方法。我们将在下面的"ENTERPRISE JAVA BEANS"章节中做更多的介绍。</P>
<P>　　以上关于JNDI的讨论只是冰山之一角而已。如果要更进一步地在CONTEXT中查找对象，JNDI也提供了一些方法来进行以下操作：　</P>
<P>　　将一个对象插入或绑定到CONTEXT。这在你展开一个EJB的时候是很有效的。</P>
<P>　　从CONTEXT中移去对象。</P>
<P>　　列出CONTEXT中的所有对象。</P>
<P>　　创建或删除子一级的CONTEXT。</P>
<P>　　接下来，我们要开始关注EJB了。</P>
<P>　　ENTERPRISE JAVA BEANS (EJB)</P>
<P>　　J2EE技术之所以赢得某体广泛重视的原因之一就是EJB。它们提供了一个框架来开发和实施分布式商务逻辑，由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。EJB规范定义了EJB组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务，例如目录服务、事务管理、安全性、资源缓冲池以及容错性。</P>
<P>　　EJB规范定义了3中基本的BEAN类型:</P>
<P>　　STATELESS SESSION BEANS: 提供某种单一的服务，不维持任何状态，在服务器故障发生时无法继续存在，生命期相对较短。例如，一个STATELESS SESSION BEAN可能被用于执行温度转换计算。 </P>
<P>　　STATEFUL SESSION BEAN: T提供了与客户端的会话交互，可以存储状态从而代表一个客户。典型例子是购物车。STATEFUL SESSION BEAN在服务器故障时无法继续生存，生命气相对较短。每一个实例只用于一个单个的线程。 </P>
<P>　　ENTITY BEANS: 提供了一致性数据的表示-- 通常存放在数据库中 -- 在服务器故障发生后能继续存在。多用户情况下可以使用EJB来表示相同的数据。ENTITY EJB的一个典型例子是客户的帐号信息。 </P>
<P>　　尽管有以上的区别，所有的EJB还是有许多的共同之处。它们都处理HOME INTERFACE。它定义了一个客户端是如何创建与消亡EJB的。可以在BEAN中对定义了客户端方法的远程接口进行调用；BEAN类则执行了主要的商务逻辑。</P>
<P>　　描述EJB的开发已经超出了本文的范围。但是，如果一个EJB已经被开发了或者从第三方进行了购买，它就必须在应用服务器中进行发布。WEBLOGIC SERVER 5.1带有一个EJB DEPLOYER TOOL来协助处理EJB的发布。当你使用EJB DEPLOYER TOOL的时候，你要定义客户端所用的JNDI名字来定位EJB。DEPLOYER TOOL将生成WRAPPER类来处理和容器的通信以及在一个JAR文件中把被请求的JAVA类绑定在一起。</P>
<P>　　一旦EJB被发布，客户端就可以使用它的JNDI名字来定位EJB。首先，它必须得到一个到HOME接口的REFERENCE。然后，客户端可以使用该接口，调用一个 CREATE() 方法来得到服务器上运行的某个BEAN实例的句柄；最后，客户端可以使用该句柄在BEAN中调用方法。</P>
<P>　　了解 EJB后，让我们再来看JSP。</P>
<P>　　JAVASERVER PAGES (JSPS)</P>
<P>　　我们中间可能已经有许多人已经熟悉MICROSOFT的ACTIVE SERVER PAGES (ASP)技术了。JSP和ASP相对应的，但更具有平台对立性。他们被设计用以帮助WEB内容开发人员创建动态网页，并且只需要相对较少的代码。 即使WEB设计师不懂得如何编程也可以使用JSP，因为JSP应用是很方便的。 JSP页面由HTML代码和嵌入其中的JAVA代码所组成。服务器在页面被客户端所请求以后对这些JAVA代码进行处理，然后将生成的HTML页面返回给客户端的浏览器。</P>
<P>　　下面我们来看一个JSP的简单实例。它只显示了服务器的当前日期和时间。虽然，对语法的具体解释已经超出了本文的范围，但我们还是可以很直观地看到，JAVA代码被放在&lt;%和%&gt;的中间，而JAVA的表达式则放在&lt;%=和%&gt;之间。</P>
<P>&lt;html&gt;<BR>&lt;head&gt;<BR>&lt;title&gt;Sample JSP Page&lt;/title&gt;<BR>&lt;/head&gt;<BR>&lt;body&gt;<BR>&lt;h1&gt;Date JSP sample&lt;/h1&gt;<BR><BR>&lt;h2&gt;<BR>&lt;% response.setHeader("Refresh", 5); %&gt;<BR>The current date is &lt;%= new Date()&nbsp;&nbsp;%&gt;.<BR>&lt;/h2&gt;<BR><BR>&lt;/body&gt;<BR>&lt;/html&gt; 
<P>　　您可能有时候听说过JHTML。这是JSP以前的一种较老的标准。WEBLOGIC服务器既可支持JSP，又可支持JHTML。请注意，在缺省状况下，JSP在WEBLOGIC服务器中并没有处于有效状态。要使之有效，你可以编辑WEBLOGIC.PROPERTIES文件。如果WEB服务器还没有处于有效状态，则要先使之有效。SERVLET的情况和JSP是一样的。</P>
<P>　　下面是: JAVA SERVLETS</P>
<P>　　JAVA SERVLETS</P>
<P>　　SERVLET提供的功能大多与JSP类似，不过实现的方式不同。JSP通常是大多数HTML代码中嵌入少量的JAVA代码，而SERVLETS全部由JAVA写成并且生成HTML。</P>
<P>　　SERVLET是一种小型的JAVA程序，它扩展了WEB服务器的功能。作为一种服务器端的应用，当被请求时开始执行，这和CGI PERL脚本很相似。SERVLETS和CGI脚本的一个很大的区别是：每一个CGI在开始的时候都要求开始一个新的进程 -- 而SERVLETS是在SERVLET引擎中以分离的线程来运行的。因此SERVLETS在可伸缩性上提供了很好的改进。</P>
<P>　　在开发SERVLETS的时候，您常常需要扩展JAVAX.SERVLET.HTTP.HTTPSERVLET 类，并且OVERRIDE一些它的方法，其中包括：</P>
<P>　　SERVICE(): 作为DISPATCHER来实现命令-定义方法 </P>
<P>　　DOGET(): 处理客户端的HTTP GET请求。 </P>
<P>　　DOPOST(): 进行HTTP POST操作 </P>
<P>　　其它的方法还包括处理不同类型的HTTP请求 -- 可以参考HTTPSERVLET API文档。</P>
<P>　　以上描述的是标准J2EE SERVLET API的各种方法。WEBLOGIC服务器提供了一个该API完整的实现途径。一旦你开发了一个SERVLET，你就可以在WEBLOGIC.PROPERTIES 中加以注册并由此可以在WEBLOGIC服务器中对它进行配置。</P>
<P>　　通过JAVA SERVLETS,我们已经到达了J2EE主要技术的末尾了。但J2EE所提供的并不止于这些。下面的段落中我们将简要地看一下现存的一些技术，包括RMI, JAVA IDL和CORBA, JTA, 以及XML，等等。</P>
<P>　　REMOTE METHOD INVOCATION (RMI)</P>
<P>　　正如其名字所表示的那样，RMI协议是在远程对象上调用一些方法。它使用了连续序列方式在客户端和服务器端传递数据。RMI是一种被EJB使用的更下层的协议。</P>
<P>　　JAVA IDL/CORBA</P>
<P>　　在JAVA IDL的支持下，开发人员可以将JAVA和CORBA集成在一起。 他们可以创建JAVA对象并使之可在CORBA ORB中展开, 或者他们还可以创建JAVA类并作为和其它ORB一起展开的CORBA对象的客户。后一种方法提供了另外一种途径，通过它JAVA可以被用于将你的新的应用和LEGACY系统相集成。</P>
<P>　　JAVA TRANSACTION ARCHITECTURE (JTA)/JAVA TRANSACTION SERVICE (JTS)</P>
<P>　　JTA定义了一种标准的API，应用系统由此可以存取各种事务监控。</P>
<P>　　JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。该事务管理器是在高层支持JAVA TRANSACTION API (JTA)规范，并且在较底层实现OMG OTS SPECIFICATION的JAVA映像。JTS事务管理器为应用服务器、资源管理器、独立的应用以及通信资源管理器提供了事务服务。</P>
<P>　　JAVAMAIL AND JAVABEANS ACTIVATION FRAMEWORK</P>
<P>　　JAVAMAIL是用于存取邮件服务器的API，它提供了一套邮件服务器的抽象类。不仅支持SMTP服务器，也支持IMAP服务器。</P>
<P>　　JAVAMAIL利用JAVABEANS ACTIVATION FRAMEWORK (JAF)来处理MIME-编码的邮件附件。MIME的字节流可以被转换成JAVA对象，或者转换自JAVA对象。由此大多数应用都可以不需要直接使用JAF。</P>
<P>　　JAVA MESSAGING SERVICE (JMS)</P>
<P>　　JMS是用于和面向消息的中间件相互通信的应用程序接口(API)。它既支持点对点的域，有支持发布/订阅(PUBLISH/SUBSCRIBE)类型的域，并且提供对下列类型的支持：经认可的消息传递,事务型消息的传递，一致性消息和具有持久性的订阅者支持。JMS还提供了另一种方式来对您的应用与LEGACY BACKEND系统相集成。</P>
<P>　　EXTENSIBLE MARKUP LANGUAGE (XML)</P>
<P>　　XML是一种可以用来定义其它标记语言的语言。它被用来在不同的商务过程中共享数据。XML的发展和JAVA是相互独立的，但是，它和JAVA具有的相同目标正是平台独立性。通过将JAVA和XML的组合，您可以得到一个完美的具有平台独立性的解决方案。目前正有许多不同的公司在为JAVA和XML的组合而努力。如果要了解更多的这方面的信息，可以访问SUN的JAVA-XML页面，或者IBM DEVELOPERWORKS的XML ZONE。</P>
<P>　　总结</P>
<P>　　在本文中，我们介绍了建立在J2EE上的分布式应用结构，并且描述了WEBLOGIC服务器对J2EE的各种支持。 然而，我们所揭示的仅仅是冰山之一角而已，要以一篇数千字的文章来展示J2EE潜在的对您的企业级应用的影响可是很不公平的。</P>
<P>　　我们已经关注了在您开始用J2EE进行工作时最有可能遇到的各类技术：JDBC, JNDI, EJB, JSP和SERVLET。我们也为您提供了一些尚未常见的J2EE技术的背景知识。不管您是一名开发人员，商务应用分析师，或者项目经理，都应该对J2EE和WEBLOGIC服务器所能提供给我们，给我们的企业以及我们的企业级应用所带来的意义有一个更好的认识。</P><img src ="http://www.cppblog.com/xmh79/aggbug/3375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-02-21 15:07 <a href="http://www.cppblog.com/xmh79/articles/3375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是J2EE？</title><link>http://www.cppblog.com/xmh79/articles/3374.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Tue, 21 Feb 2006 06:49:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/3374.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/3374.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/3374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/3374.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/3374.html</trackback:ping><description><![CDATA[<P><STRONG>一、准备篇 <BR>1&nbsp;什么是J2EE？它和普通的Java有什么不同？ <BR></STRONG>答：J2EE全称为Java2&nbsp;Platform,&nbsp;Enterprise&nbsp;Edition。 <BR>“J2EE平台本质上是一个分布式的服务器应用程序设计环境——一个Java环境，它提供了： <BR>·宿主应用的一个运行基础框架环境。 <BR>·一套用来创建应用的Java扩展API。”（引自《J2EE服务器端高级编程》）&nbsp; <BR><STRONG>2&nbsp;J2EE好学吗？</STRONG> <BR>答：J2EE是很多技术的集合体，并且还在成长中。 <BR>你会遇到很多专有名词：比如(X)HTML，Servlet/JSP，JDBC，JMS，JNDI，EJB，XML，Web&nbsp;Service……。 <BR>尤其是XML和Web&nbsp;Service正在快速成长。幸运的是，你不需要等到学会所有技术后再开始编程。 <BR>大体上J2EE可以分成3个主要应用：Servlet/JSP，EJB，XML/Web&nbsp;Service&nbsp;和一些支撑技术例如JDBC和JNDI。 <BR>你可以一个一个的学。&nbsp; <BR><STRONG>3&nbsp;J2EE有什么用？</STRONG> <BR>答：用来建设大型的分布式企业级应用程序。或者用更时髦的名词说就是“电子商务”应用程序。 <BR>这些企业可能大到拥有中心数据库服务器，Web服务器集群和遍布全国的办公终端，也可能小到只不过想做一个网站。&nbsp; <BR><STRONG>4&nbsp;学J2EE有前途吗？</STRONG> <BR>答：在这一市场目前只有一种技术可以和J2EE竞争，那就是Microsoft的.NET。 <BR>相对来说.NET要“新”一些而J2EE要“老”一些。 <BR>但是.NET只能用于Windows平台（Microsoft声称要开发C#在Linux上的虚拟机但是尚未兑现该诺言）， <BR>考虑到Linux的发展势头，你可以相信.NET不会一统天下。&nbsp; <BR><STRONG>5&nbsp;据说J2EE的性能不如.NET好，是真的吗？ <BR></STRONG>答：在Sun公司提供的样例程序Pet&nbsp;Store上，Microsoft声称不如相同的.NET程序好。 <BR>而Sun公司反驳说这一程序不能真正体现J2EE的性能，并且指责Microsoft在数据库上做了优化。 <BR>作者没有学习过.NET因而不能妄下断言。 <BR>无论如何，大型分布式程序中的性能瓶颈通常首先来自于错误的设计。&nbsp; <BR><STRONG>6&nbsp;听你说了这么多，我想学着玩玩。</STRONG> <BR>答：除非你想靠它当饭吃或者作为技术储备，否则请不要浪费你的时间。 <BR>Flash要好玩得多。计算机游戏就更加好玩了。&nbsp; <BR><STRONG>7&nbsp;学习J2EE该怎么开始？</STRONG> <BR>答：首先，下载一个J2EE服务器。其次，去java.sun.com下载J2EE的API。第三，找一本好的参考书。最后，找一个顺手的IDE。 <BR>J2EE服务器。你可以用Sun的J2EE&nbsp;SDK（免费），或者Weblogic（性能最好，但是太大，而且作者不推荐盗版行为），或者JBoss（免费，就是文档太少），或者JRun（开发版免费，作者用这个）。参考书作者感觉Wrox的《J2EE服务器端高级编程》不错，但是太老（作者手头的是2001年中文版）。你还需要去下载一些最新的技术资料（当然肯定是英文的）。 <BR>IDE如果你的机器配置够好（内存至少512M以上，256M或以下请勿考虑），可以用IBM的WSAD，不然就继续用Eclipse或者其他。 <BR>你也可以经常去水木清华的Java版逛逛，但是在发贴前先看看精华区里有没有你要的答案。&nbsp; <BR><STRONG>8&nbsp;我下了一个J2EE服务器但是不会配置。</STRONG> <BR>答：请认真阅读随机指导文档，不同的服务器的配置都不一样，作者爱莫能助。&nbsp; <BR><STRONG>9&nbsp;我发现你没有提到Tomcat。</STRONG> <BR>答：Tomcat只是一个Web服务器，更准确地说主要只是一个Web&nbsp;Container。 <BR>如果你想要学习EJB的话，Tomcat无法满足你的需要。&nbsp; <BR><STRONG>二、&nbsp;Servlet/JSP篇&nbsp; <BR>10&nbsp;什么是Servlet？ <BR></STRONG>答：一个Servlet是一个Java类。它处理Http(s)请求并作出响应，包括返回一个HTML页面或转交给其他URL处理。 <BR>Servlet必须运行在一个Web&nbsp;Container例如Tomcat中。 <BR>Servlet必须是javax.servlet.http.HttpServlet的子类， <BR>你可以继承doGet()或者doPost()方法，两者分别对应于Http(s)中的Get请求和Post请求。&nbsp; <BR><STRONG>11&nbsp;我怎么获得Http请求里的参数？ <BR></STRONG>答：HttpRequest的getParameter()方法。例如：String&nbsp;paramValue&nbsp;=&nbsp;request.getParameter("paramName");&nbsp; <BR><STRONG>12&nbsp;我怎么返回结果？ <BR></STRONG>答：你可以利用相关API打开一个输出流，并向流中直接写入一个HTML页面。 <BR>但是作者完全不赞成这样做。一方面这样做会很罗嗦。 <BR>另一方面从Model-View-Controller模式（在《J2EE核心模式》中被归为Front&nbsp;Controller模式）的观点来看， <BR>你应当提供一些HTML或者JSP作为视图（view），而Servlet则根据请求参数决定转到哪一个视图。 <BR>你可以利用response.sendRedirect(...)方法或request.getDispatcher(...).forward()方法来实现。&nbsp; <BR><STRONG>13&nbsp;sendRedirect()和forward()有什么不同？ <BR></STRONG>答：sendRedirect()是向浏览器发送一个redirect通知，浏览器重定向到新的URL。 <BR>而forward是在服务器端直接转到新的URL，对于浏览器是透明的。 <BR>前者浏览器的地址栏显示的是新的URL，后者浏览器的地址栏显示的是Servlet的URL。 <BR>因而当目标URL会自动刷新时，两者会造成一些差别。&nbsp; <BR><STRONG>14&nbsp;我写了一个Servlet程序，怎么运行它？ <BR></STRONG>答：开发J2EE程序有一个部署（deploy）的概念，实际上是开发——部署——运行的三部曲。 <BR>大多数服务器支持Hot&nbsp;deploy。你只需要在相应的Application目录（具体路径依赖于服务器）下面 <BR>建立一个符合WAR或EAR格式（参见16，17）的目录，启动服务器，就可以通过浏览器访问了。 <BR>特别的，你的Servlet的class文件应当放在/WEB-INF/classes目录中。 <BR>注意J2EE&nbsp;SDK不支持Hot&nbsp;deploy，你需要通过它的deploy&nbsp;tool来部署。 <BR>Tomcat只支持WAR格式。&nbsp; <BR><STRONG>15&nbsp;EAR和WAR有什么不同？</STRONG> <BR>答：EAR是一个完整的J2EE应用程序，包括Web部分和EJB部分。 <BR>WAR只是其中的Web部分。&nbsp; <BR><STRONG>16&nbsp;EAR格式是怎样的？ <BR></STRONG>答：一个EAR可以包含任意多个WAR或EJB&nbsp;JAR，并且包含一个META-INF的目录。 <BR>在/META-INF中包含了一个application.xml，其中描述了这个EAR包含哪些模块，以及安全性配置。 <BR>细节请看参考书。&nbsp; <BR><STRONG>17&nbsp;WAR格式是怎样的？</STRONG> <BR>答：一个WAR包含一个WEB-INF的目录，这个目录下包含classes目录，lib目录和web.xml。 <BR>/WEB-INF/classes存放按package组织的class文件，/WEB-INF/lib目录存放jar文件， <BR>web.xml描述了很多东西，请读参考书。&nbsp; <BR><STRONG>18&nbsp;我的普通HTML文件应当放在哪里？</STRONG> <BR>答：放在除了/WEB-INF以外的其他地方。&nbsp; <BR><STRONG>19&nbsp;我访问不到servlet，甚至连HTML文件都访问不到！</STRONG> <BR>答：第一你没启动服务器。第二你敲错了端口。第三你没有正确配置context-path。 <BR>第四你的服务器不支持auto&nbsp;reload或者你关闭了这一选项，你得重启服务器。 <BR>第五确认你没有把HTML放在/WEB-INF目录下，那是访问不到的。&nbsp; <BR><STRONG>20&nbsp;我能访问HTML但是访问不到servlet。</STRONG> <BR>答：请检查你的web.xml文件。确保你正确定义了&lt;servlet&gt;和&lt;servlet-mapping&gt;元素。 <BR>前者标识了一个servlet，后者将一个相对于context-path的URL映射到一个servlet。 <BR>在Tomcat中你可以通过/context-path/servlet/package/servletname的形式访问servlet， <BR>但是这只是Tomcat的便捷访问方式，并不是正式规范。 <BR>细节请看参考书。&nbsp; <BR><STRONG>21&nbsp;什么是JSP？它和Servlet有什么区别？ <BR></STRONG>答：你可以将JSP当做一个可扩充的HTML来对待。 <BR>虽然在本质上JSP文件会被服务器自动翻译为相应的Servlet来执行。 <BR>可以说Servlet是面向Java程序员而JSP是面向HTML程序员的，除此之外两者功能完全等价。&nbsp; <BR><STRONG>22&nbsp;我的JSP显示的汉字是乱码。</STRONG> <BR>答：在你的JSP开头加上一行&nbsp;&lt;%@&nbsp;page&nbsp;contentType="text/html;&nbsp;charset=gb2312"%&gt; <BR>如果你已经声明了page我想你知道该怎么修改。 <BR><STRONG>23&nbsp;JSP文件存放在哪里？</STRONG> <BR>答：除了/WEB-INF下的任何地方。&nbsp; <BR><STRONG>24&nbsp;在JSP里面怎么引用Java&nbsp;Bean。</STRONG> <BR>答：首先，确认你要引用的类在/WEB-INF/classes下或在/WEB-INF/lib的某个jar内。 <BR>其次，在JSP里加一行&nbsp;&lt;jsp:useBean&nbsp;id="..."&nbsp;scope="..."&nbsp;class="..."/&gt; <BR>具体解释请看参考书。&nbsp; <BR><STRONG>25&nbsp;我想在servlet间传递数据。</STRONG> <BR>答：利用session。在Servlet/JSP中，你可以在4个地方保存数据。 <BR>1)&nbsp;page，本页面。 <BR>2)&nbsp;session，用来存放客户相关的信息，比如购物车，对应接口为javax.servlet.http.HttpSession。 <BR>session机制实际上是cookie和URL&nbsp;Rewrite的抽象，服务器会自动使用cookie或URL&nbsp;Rewrite来实现。 <BR>3)&nbsp;request，可以在forward()时传递信息，对应接口为javax.servlet.http.HttpRequest。 <BR>4)&nbsp;application，或称context，存放全局信息，对应接口为javax.servlet.ServletContext。&nbsp; <BR><STRONG>26&nbsp;怎么调用cookie？</STRONG> <BR>答：作者建议使用session，你总是会遇到某些禁用cookie的用户。这时session会自动使用URL重写来实现。&nbsp; <BR><STRONG>27&nbsp;怎么在JSP里面实现文件下载？ <BR></STRONG>答：实际上这是一个HTML的问题。答案是一个超链接&lt;a&gt;。&nbsp; <BR><STRONG>28&nbsp;怎么实现文件上传？</STRONG> <BR>答：客户端是HTML问题，在form中设置method为post，enctype为multi-part/form-data，加一个&lt;input&nbsp;type="file"&gt;。 <BR>而在接收的servlet中只是一个I/O问题。&nbsp; <BR><STRONG>29&nbsp;我想让页面自动刷新，比如聊天室。</STRONG> <BR>答：这是一个HTML问题，在&lt;head&gt;部分中加一条&lt;meta&nbsp;http-equiv="refresh"&nbsp;content="5"&nbsp;url="..."&gt;。 <BR>这是所谓的Clinet-push，客户端刷新技术。&nbsp; <BR><STRONG>30&nbsp;我想让用户登录以后才能访问页面。</STRONG> <BR>答：使用声明式安全措施。 <BR>你只需要在web.xml中定义安全角色（Role），并定义受保护的URL集合只能由特定Role访问。 <BR>大多数服务器支持基于数据库的用户映射，你只要在相应数据库中建立两张表并配置服务器就可以了。 <BR>注意J2EE&nbsp;SDK不支持基于数据库的用户映射。 <BR>细节请看参考书和服务器文档。&nbsp; <BR><STRONG>31&nbsp;我想要能注册用户。</STRONG> <BR>答：参看30。在接受注册请求的Servlet中执行写入数据库操作即可。&nbsp; <BR><STRONG>32&nbsp;怎么在JSP中访问数据库？</STRONG> <BR>答：标准做法是使用DAO模式，定义一个Java&nbsp;bean来访问数据库并在JSP中使用。 <BR>然而，当你的数据库模式很简单时，你可以使用JSTL中的&lt;sql:query&gt;标签来快速访问。&nbsp; <BR><STRONG>33&nbsp;什么是JSTL？</STRONG> <BR>答：JSTL是Jsp&nbsp;Standard&nbsp;Tag&nbsp;Library的缩写。这是一组通用标签并将成为JSP&nbsp;2.0的一部分。 <BR>其中包含赋值&lt;c:set&gt;，分支&lt;c:if&gt;，循环&lt;c:forEach&gt;，查询数据库&lt;sql:query&gt;，更新数据库&lt;sql:update&gt; <BR>等。目前你需要像添加自定义标签库一样来添加JSTL，但是可以预计JSP&nbsp;2.0会将JSTL作为组成部分。 <BR>标签库可以在http://jakarta.apache.org下载。注意JSTL需要在支持JSP1.2或更高版本的容器下运行。</P><img src ="http://www.cppblog.com/xmh79/aggbug/3374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-02-21 14:49 <a href="http://www.cppblog.com/xmh79/articles/3374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java串行端口通讯技术慨论</title><link>http://www.cppblog.com/xmh79/articles/3363.html</link><dc:creator>飘羽</dc:creator><author>飘羽</author><pubDate>Tue, 21 Feb 2006 02:14:00 GMT</pubDate><guid>http://www.cppblog.com/xmh79/articles/3363.html</guid><wfw:comment>http://www.cppblog.com/xmh79/comments/3363.html</wfw:comment><comments>http://www.cppblog.com/xmh79/articles/3363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmh79/comments/commentRss/3363.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmh79/services/trackbacks/3363.html</trackback:ping><description><![CDATA[<P><FONT face=Tahoma>了解串行通讯<BR><BR>　　串行通讯协议有很多种，像RS232，RS485，RS422，甚至现今流行的USB等都是串行通讯协议。而串行通讯技术的应用无处不在。可能大家见的最多就是电脑的串口与Modem的通讯。记得在PC机刚开始在中国流行起来时（大约是在90年代前五年），那时甚至有人用一条串行线进行两台电脑之间的数据共享。除了这些，手机，PDA，USB鼠标、键盘等等都是以串行通讯的方式与电脑连接。而笔者工作性质的关系，所接触到的就更多了，像多串口卡，各种种类的具有串口通讯接口的检测与测量仪器，串口通讯的网络设备等。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然串行通讯有很多种，但笔者所知的在整个电子通讯产品方面，以RS232的通讯方式最为多见。虽然</FONT><A class=bluekey href="http://www.yesky.com/key/919/165919.html" target=_blank><FONT face=Tahoma>USB接口</FONT></A><FONT face=Tahoma>的电子产品也是层出不穷，但了解一下Java在串行通讯方面的技术还有有必要的，说不定有哪位读者还想用此技术写一个PDA与电脑之间数据共享的程序呢。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文主要以RS232为主来讲解Java的串行通讯技术。<BR>RS232通讯基础<BR><BR>　　RS-232-C(又称 EIA RS-232-C，以下简称RS232)是在1970年由美国电子</FONT><A class=bluekey href="http://www.yesky.com/key/4036/164036.html" target=_blank><FONT face=Tahoma>工业</FONT></A><FONT face=Tahoma>协会（EIA）联合贝尔系统、调制解调器厂家及</FONT><A class=bluekey href="http://www.yesky.com/key/2669/172669.html" target=_blank><FONT face=Tahoma>计算</FONT></A><FONT face=Tahoma>机终端生产厂家共同制定的用于串行通讯的标准。RS232是一个全双工的通讯协议，它可以同时进行数据接收和发送的工作。RS232的端口通常有两种：9针(DB9)和25针(DB25)。<BR><BR>　　DB9和DB25的常用针脚定义<BR><BR></FONT></P>
<P align=center><FONT face=Tahoma><IMG onerror="this.src='http://www.yesky.com/image20010518/129786.gif';" hspace=3 src="http://www.yesky.com/image20010518/129786.gif" align=center vspace=1 border=1></FONT></P>
<P><BR><BR><FONT face=Tahoma>　　常见的边线方式<BR><BR>　　常见的通讯方式是三线式，这种方式是将两个RS232设备的发送端(TXD)和接收端(RXD)及接地端(GND)互相连接，也是许多读者所知道的连接方式：<BR><BR></FONT></P>
<P align=center><FONT face=Tahoma><IMG onerror="this.src='http://www.yesky.com/image20010518/129787.gif';" hspace=3 src="http://www.yesky.com/image20010518/129787.gif" align=center vspace=1 border=1></FONT></P>
<P><BR><BR><FONT face=Tahoma>　　这种方式分别将两端的RS232接口的2--3,3---2,5(7)---5(7)针脚连接起来。其中2是数据接收线(RXD)，3是数据发送线(TXD)，5(7)是接地(RND)。如果有一台式PC，和一部NoteBook电脑，就可以用这种方式连线了。用三线式可以将大多数的RS232设备连接起来。但如果你认死了2--3,3--2,5(7)--5(7)对接这个理，会发现在连某些RS232设备时并不奏效。这是因为有些设备在</FONT><A class=bluekey href="http://www.yesky.com/key/1524/171524.html" target=_blank><FONT face=Tahoma>电路</FONT></A><FONT face=Tahoma>内部已将2和3线调换过来了，你只要2,3,5(7)针一一对应就行了。<BR><BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffcc99>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>　　小技巧：如何辨别TXD和RXD端口？<BR><BR>　　搞电子的人手边应该常备一个电表，用来测测电压，电阻什么的会很有用。你只要分别测一下RS232端口的2--5或3--5针脚之间的电压，通常TXD针脚与GND之间会有3~15V左右的负电压，表示它是TXD针脚。 </FONT></P></TD></TR></TBODY></TABLE></P>
<P><BR>
<SCRIPT>zmbbs=1;</SCRIPT>
<FONT face=Tahoma>安装Java Communications API <BR><BR>　　Sun的J2SE中并没有直接提供以上提到的任何一种串行通讯协议的开发包，而是以独立的jar包形式发布在java.sun.com网站上(从这里下载)----即comm.jar，称之为Javatm Communications API，它是J2SE的标准扩展。comm.jar并不是最近才有，早在1998年时，sun就已经发布了这个开发包。comm.jar分别提供了对常用的RS232串行端口和IEEE1284并行端口通讯的支持。目前sun发布的comm.jar只有Windows和Solaris平台两个版本，如果你需要Linux平台下的，可以在http://www.geeksville.com/~kevinh/linuxcomm.html找到。<BR><BR>　　在使用comm.jar之前，必须知道如何安装它。这也是困扰许多初学java RS232通讯者的一个难题。如果我们电脑上安装了JDK, 它将同时为我们安装一份JRE(Java Runtime Entironment)，通常我们运行程序时都是以JRE来运行的。所以以下的安装适用于JRE。如果你是用JDK来运行程序的，请将相应的&lt;JRE_HOME&gt;改成&lt;JDK_HOME&gt;。<BR><BR>　　下载了comm.jar开发包后，与之一起的还有两个重要的文件，win32com.dll和javax.comm.properties。 comm.jar提供了通讯用的java API，而win32com.dll提供了供comm.jar调用的本地驱动接口。而javax.comm.properties是这个驱动的类配置文件。首先将comm.jar复制到&lt;JRE_HOME&gt;\lib\ext目录。再将win21com.dll复制到你的RS232应用程序运行的目录，即user.dir。然后将javax.comm.properties复制到&lt;JRE_HOME&gt;\lib目录。<BR><BR>　　通讯前的准备<BR><BR>　　如果你手头上没有现成的提供了标准RS232串口的设备，你可以将自己的电脑模拟成两台不同的串口设备。通常电脑主机后面的面板提供了两个9针的串口，请将这两个串口的2,3,5脚按前面介绍的方法连接。电子市场都有现成的连接头卖，请不要买那种封装的严严实实的接头，而要买用螺丝封装可以拆开的连接头，这样可以方便自己根据需要连接各个针脚。<BR><BR>　　Comm API基础<BR><BR>　　我无意于在此详细描述Comm API每个类和接口的用法，但我会介绍Comm API的类结构和几个重要的API用法。<BR><BR>　　所有的comm API位于javax.comm包下面。从Comm API的javadoc来看，它介绍给我们的只有区区以下13个类或接口：<BR><BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>javax.comm.CommDriver <BR>javax.comm.CommPort <BR>javax.comm.ParallelPort <BR>javax.comm.SerialPort <BR>javax.comm.CommPortIdentifier <BR>javax.comm.CommPortOwnershipListener<BR>javax.comm.ParallelPortEvent <BR>javax.comm.SerialPortEvent <BR>javax.comm.ParallelPortEventListener (extends java.util.EventListener) <BR>javax.comm.SerialPortEventListener (extends java.util.EventListener) <BR>javax.comm.NoSuchPortException <BR>javax.comm.PortInUseException <BR>javax.comm.UnsupportedCommOperationException </FONT></P></TD></TR></TBODY></TABLE></P>
<P><FONT face=Tahoma>下面讲解一下几个主要类或接口。<BR><BR>　　1.枚举出系统所有的RS232端口<BR><BR>　　在开始使用RS232端口通讯之前，我们想知道系统有哪些端口是可用的，以下代码列出系统中所有可用的RS232端口:<BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>Enumeration en = CommPortIdentifier.getPortIdentifiers();<BR>CommPortIdentifier portId;<BR>while (en.hasMoreElements()) <BR>{<BR>portId = (CommPortIdentifier) en.nextElement();<BR>/*如果端口类型是串口，则打印出其端口信息*/<BR>if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) <BR>{<BR>System.out.println(portId.getName());<BR>}<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<P><BR><FONT face=Tahoma>　　在我的电脑上以上程序输出以下结果：<BR><BR>　　COM1<BR>　　COM2<BR><BR>　　CommPortIdentifier类的getPortIdentifiers方法可以找到系统所有的串口，每个串口对应一个CommPortIdentifier类的实例。<BR><BR>　　2.打开端口<BR><BR>　　如果你使用端口，必须先打开它。<BR><BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>try{<BR>CommPort serialPort = portId.open("My App", 60);<BR>/* 从端口中读取数据*/<BR>InputStream input = serialPort.getInputStream();<BR>input.read(...); <BR>/* 往端口中写数据*/<BR>OutputStream output = serialPort.getOutputStream();<BR>output.write(...)<BR>...<BR>}catch(PortInUseException ex)<BR>{ ... }</FONT></P></TD></TR></TBODY></TABLE></P>
<P><BR><FONT face=Tahoma>　　通过CommPortIdentifier的open方法可以返回一个CommPort对象。open方法有两个参数，第一个是String，通常设置为你的应用程序的名字。第二个参数是时间，即开启端口超时的毫秒数。当端口被另外的应用程序占用时，将抛出PortInUseException异常。<BR><BR>　　在这里CommPortIdentifier类和CommPort类有什么区别呢？其实它们两者是一一对应的关系。CommPortIdentifier主要负责端口的初始化和开启，以及管理它们的占有权。而CommPort则是跟实际的输入和输出功能有关的。通过CommPort的getInputStream()可以取得端口的输入流，它是java.io.InputStream接口的一个实例。我们可以用标准的InputStream的操作接口来读取流中的数据，就像通过FileInputSteam读取文件的内容一样。相应的，CommPort的getOutputStream可以获得端口的输出流，这样就可以往串口输出数据了。<BR><BR>　　3. 关闭端口<BR><BR>　　使用完的端口，必须记得将其关闭，这样可以让其它的程序有机会使用它，不然其它程序使用该端口时可能会抛出端口正在使用中的错误。很奇怪的是，CommPortIdentifier类只提供了开启端口的方法，而要关闭端口，则要调用CommPort类的close()方法。<BR><BR>通讯方式<BR><BR>　　CommPort的输入流的读取方式与文件的输入流有些不一样，那就是你可能永远不知这个InputStream何时结束，除非对方的OutputStream向你发送了一个特定数据表示发送结束，你收到这个特定字符后，再行关闭你的InputStream。而comm.jar提供了两种灵活的方式让你读取数据。<BR>1. 轮询方式(Polling)<BR><BR>　　举个例子，你同GF相约一起出门去看电影，但你的GF好打扮，这一打扮可能就是半小时甚至一小时以上。这时你就耐不住了，每两分钟就催问一次“好了没？”，如此这样，直到你的GF说OK了才算完。这个就叫轮询(Polling)。<BR><BR>　　在程序中，轮询通常设计成一个封闭的循环，当满足某个条件时即结束循环。刚才那个例子中，你的GF说“OK了！”，这个就是结束你轮询的条件。在单线程的程序中，当循环一直执行某项任务而又无法预知它何时结束时，此时你的程序看起来可能就像死机一样。在VB程序中，这个问题可以用在循环结构中插入一个doEvent语句来解决。而Java中，最好的方式是使用线程，就像以下代码片断一样。<BR><BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>public TestPort extend Thread<BR>{<BR>...<BR>InputStream input = serialPort.getInputStream();<BR>StringBuffer buf = new StringBuffer();<BR>boolean stopped = false;<BR>...<BR>public void run()<BR>{<BR>try {<BR>while( !stopped )<BR>int ch = input.read();<BR>if ( ch=='q' || ch=='Q' )<BR>{<BR>/* 结束读取，关闭端口...*/<BR>stopped = true;<BR>...<BR>}<BR>else<BR>{<BR>buf.append((char)ch);<BR>...<BR>}<BR>}catch (InterruptedException e) { }<BR>}<BR><BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<P><BR><FONT face=Tahoma>　　2. 监听方式(listening)<BR><BR>　　Comm API支持标准的Java Bean型的事件模型。也就是说，你可以使用类似AddXXXListener这样的方法为一个串口注册自己的监听器，以监听方式进行数据读取。 <BR><BR>　　如要对端口监听，你必须先取得CommPortIdentifier类的一个实例，<BR>CommPort serialPort = portId.open("My App", 60); <BR><BR>　　从而取得SerialPort，再调用它的addEventListener方法为它添加监听器，<BR>serialPort.addEventListener(new MyPortListener()); <BR><BR>　　SerialPort的监听器必须继承于SerialPortEventListener接口。当有任何SerialPort的事件发生时，将自动调用监听器中的serialEvent方法。Serial Event有以下几种类型： <BR><BR>　　BI - 通讯中断.<BR>　　CD - 载波检测.<BR>　　CTS - 清除发送.<BR>　　DATA_AVAILABLE - 有数据到达.<BR>　　DSR - 数据设备准备好.<BR>　　FE - 帧错误.<BR>　　OE - 溢位错误.<BR>　　OUTPUT_BUFFER_EMPTY - 输出缓冲区已清空.<BR>　　PE - 奇偶校验错.<BR>　　RI - 　振铃指示.<BR>　<BR>　　下面是一个监听器的示例：<BR><BR></FONT></P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>
<P><FONT face=Tahoma>public void MyPortListener implements SerialPortEventListener<BR>{ <BR>　public void serialEvent(SerialPortEvent evt)<BR>　{<BR>　　switch (evt.getEventType())<BR>　　{<BR>　　　case SerialPortEvent.CTS :<BR>　　　　System.out.println("CTS event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.CD :<BR>　　　　System.out.println("CD event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.BI :<BR>　　　　System.out.println("BI event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.DSR :<BR>　　　　System.out.println("DSR event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.FE :<BR>　　　　System.out.println("FE event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.OE :<BR>　　　　System.out.println("OE event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.PE :<BR>　　　　System.out.println("PE event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.RI :<BR>　　　　System.out.println("RI event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.OUTPUT_BUFFER_EMPTY :<BR>　　　　System.out.println("OUTPUT_BUFFER_EMPTY event occured.");<BR>　　　　break;<BR>　　　case SerialPortEvent.DATA_AVAILABLE :<BR>　　　　System.out.println("DATA_AVAILABLE event occured.");<BR>　　　　int ch;<BR>　　　　StringBuffer buf = new StringBuffer();<BR>　　　　InputStream input = serialPort.getInputStream<BR>　　　　try {　<BR>　　　　　while ( (ch=input.read()) &gt; 0) {<BR>　　　　　　buf.append((char)ch); <BR>　　　　　}<BR>　　　　　System.out.print(buf);<BR>　　　　} catch (IOException e) {}<BR>　　　　break;　<BR>　　　}<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<P><BR><FONT face=Tahoma>　　这个监听器只是简单打印每个发生的事件名称。而对于大多数应用程序来说，通常关心是DATA_AVAILABLE事件，当数据从外部设备传送到端口上来时将触发此事件。此时就可以使用前面提到过的方法，serialPort.getInputStream()来从InputStream中读取数据了。<BR></FONT></P><img src ="http://www.cppblog.com/xmh79/aggbug/3363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmh79/" target="_blank">飘羽</a> 2006-02-21 10:14 <a href="http://www.cppblog.com/xmh79/articles/3363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>