| 
 
|  |  
| JDK1.1的新功能--序列化接口(Serializableinterface),簡(jiǎn)化了對(duì)象持久化(Persistence)的實(shí)現(xiàn)。以下介紹如何通過(guò)SMTPE-mail將對(duì)象傳送給另一個(gè)用戶。 
 摘要:一些應(yīng)用程序需要以一種非實(shí)時(shí)的方式(例如旅行指南、錯(cuò)誤報(bào)告(bugreport)、 時(shí)間表(timesheet)等)和其余用戶共享對(duì)象。Java語(yǔ)言開發(fā)工具包(JDK)1.1版提供了一 個(gè)重要的功能:java.io.Serializable接口。該技術(shù)能讓你知道如何序列化一個(gè)對(duì)象,然 后用e-mail傳給其它用戶。
 
 對(duì)象持久化和用戶間對(duì)象共享是許多商業(yè)解決方案的基礎(chǔ)。例如,一個(gè)公司可以用從本公司網(wǎng)址啟動(dòng)的Applet來(lái)完成一個(gè)時(shí)間表的制作。同樣該公司也可以提供象具有開支報(bào)告、旅行指 南、錯(cuò)誤報(bào)告(bugreport)等功能的Applet。在這些情況下,從Applet的使用者獲得的數(shù)據(jù)需要和負(fù)責(zé)薪水、付款、旅行房間預(yù)訂的人們共享。執(zhí)行這些職能的人們可能分布在不同的 城市和國(guó)家,可能工作在不同的時(shí)區(qū),不能希望每個(gè)工作人員都能象貓頭鷹一樣在晚上工作以填寫這樣的表格。相同的信息也不應(yīng)該重新輸入。因此,能夠存儲(chǔ)并且把這些相關(guān)對(duì)象傳 送到商業(yè)應(yīng)用中是這些applet有別于其它applet的優(yōu)勢(shì)。
 
 目前已經(jīng)有許多方法能實(shí)現(xiàn)對(duì)象的持久化,例如使用對(duì)象數(shù)據(jù)庫(kù)和磁盤文件。同樣的也有許多辦法可以共享對(duì)象,例如將數(shù)據(jù)寫入一個(gè)套接字,或者實(shí)現(xiàn)一個(gè)符合CORBA,SOM的模 型。以上這幾種方案均有自己的優(yōu)點(diǎn),當(dāng)你設(shè)計(jì)你的商業(yè)解決方案時(shí),需要認(rèn)真地考慮這些方案。但是,還有一種開銷不大但可靠的方法,它使用Internet和Intranet用戶能夠獲取的 技術(shù)服務(wù)在世界范圍傳送對(duì)象的拷貝。它就是簡(jiǎn)單郵件傳輸協(xié)議,SMTP。
 
 用E-mail發(fā)送Java對(duì)象
 
 存儲(chǔ)和保存對(duì)象的一個(gè)簡(jiǎn)單方法是將對(duì)象序列化而后用E-mail將它發(fā)送給別的用戶。這種 方法有以下優(yōu)點(diǎn):
 
 發(fā)送的計(jì)算機(jī)或NC(網(wǎng)絡(luò)計(jì)算機(jī))無(wú)需硬盤空間
 
 使用現(xiàn)有的系統(tǒng)傳送、排隊(duì)、發(fā)送對(duì)象
 
 允許用戶使用最喜歡的郵件客戶程序來(lái)接受郵件
 
 提供簡(jiǎn)單的機(jī)制將同一對(duì)象的拷貝分發(fā)給許多人
 
 這種方法也有不足之處:
 
 郵件的傳送可能因?yàn)镋-mail主機(jī)的關(guān)機(jī)而被較長(zhǎng)時(shí)間地延遲。所有的主機(jī)都可能出現(xiàn)這 種情況,E-mail服務(wù)器的錯(cuò)誤恢復(fù)優(yōu)先級(jí)通常比數(shù)據(jù)庫(kù)服務(wù)器低。
 
 郵件的傳送不能得到保證--在你的E-mail服務(wù)器通知你郵件沒有發(fā)出時(shí),你不得不重新 發(fā)送郵件。
 
 E-mail服務(wù)器和POP客戶程序的功能不足以處理大量交易信息。
 這些不足和你使用的應(yīng)用程序有關(guān)。對(duì)于很多商業(yè)解決方案,這些不足并不重要。作為一個(gè)設(shè)計(jì)人員,你工作的一部分就是在全面考慮價(jià)格、性能和需求的情況下確定系統(tǒng)的最佳整體結(jié)構(gòu)。
 
 使用Java傳送對(duì)象的四個(gè)步驟:
 
 Applet必須依次以下面所列出的四個(gè)步驟傳送Java對(duì)象:
 
 序列化有關(guān)對(duì)象
 
 發(fā)送時(shí)選擇Base64編碼方式對(duì)序列化對(duì)象編碼(RFC1521)
 
 與一個(gè)SMTP服務(wù)器連接
 
 將該對(duì)象傳送到這個(gè)SMTP服務(wù)器
 
 下面將介紹如何用E-mail發(fā)送一個(gè)假設(shè)的"臭蟲"報(bào)告到公司的質(zhì)量保證部門。
 
 將對(duì)象序列化
 
 JDK1.1提供的一個(gè)奇妙的機(jī)制,java.io.Serializable接口,能夠序列化并且重建對(duì)象。 這個(gè)接口能使用存儲(chǔ)對(duì)象(writeObject())和恢復(fù)對(duì)象(readObject())方法函數(shù)。在很多 情況下,使用這個(gè)接口很方便,只需實(shí)現(xiàn)并且調(diào)用這兩個(gè)方法函數(shù)。
 
 以下的代碼定義了一個(gè)簡(jiǎn)單的BugReport對(duì)象,它實(shí)現(xiàn)了最簡(jiǎn)單的序列化接口。
 
 1 import java.Io.*;
 2 public class BugReport implements Serializable {
 3 private Float m_SoftwareVersion; // version number from Help.About, e.g. "1.0"
 4 private String m_ErrorDescription; // Description of error
 5 private int m_Severity; // 1=System unusable - 5=Minor Aesthetic defect
 
 6 public BugReport (Float SoftwareVersion, String ErrorDescription, int Severity) {
 7 m_SoftwareVersion = SoftwareVersion;
 8 m_ErrorDesctiption = ErrorDescription;
 9 m_Severity = Severity;
 10 }
 
 11 public BugReport () // for reconstituting serialized objects
 
 12 public void save (OutputStream os)
 13 throws IOException {
 14 try {
 15 ObjectOutputStream o = new ObjectOutputStream(os);
 16 o.writeObject(this);
 17 o.flush();
 18 }
 19 catch (IOException e) {throw e;}
 20 }
 
 21 public BugReport restore (InputStream is)
 22 throws IOException, ClassNotFoundException {
 23 BugReport RestoredBugReport = null;
 24 try {
 25 ObjectInputStream o = new ObjectInputStream(is);
 26 RestoredBugReport = (BugReport)o.readObject();
 27 }
 28 catch (IOException e) {throw e;}
 29 catch (ClassNotFoundException e) {throw e;}
 30 return RestoredBugReport;
 31 }
 32 }
 
 1使用import語(yǔ)句引入I/O包,包括序列化接口。
 
 2-5定義類中的成員變量,并指出該類實(shí)現(xiàn)了序列化接口。
 
 6-10提供一個(gè)簡(jiǎn)單的構(gòu)造函數(shù)
 
 11一個(gè)空的構(gòu)造函數(shù)。這個(gè)構(gòu)造函數(shù)在重建序列化對(duì)象時(shí)使用。見以下的例子。
 
 12-20定義一個(gè)方法函數(shù),它把對(duì)象寫入一個(gè)已經(jīng)打開了的ObjectOutputStream。這個(gè)方 法函數(shù)首先創(chuàng)建一個(gè)ObjectOutputStream對(duì)象,然后調(diào)用writeObject方法函數(shù),最后在 函數(shù)返回前顯式清空輸出緩沖區(qū)。
 
 21-30定義一個(gè)方法函數(shù),它從一個(gè)打開了的InputStream中讀入一個(gè)BugReport對(duì)象。注 意,如果輸入流中下一個(gè)對(duì)象和正在讀入對(duì)象的類型不一致時(shí),readObject()將會(huì)拋出一 個(gè)異常。
 
 使用BugReport對(duì)象相當(dāng)簡(jiǎn)單。譬如我們想要?jiǎng)?chuàng)建一個(gè)新的BugReport對(duì)象并且把它存入 一個(gè)文件,我們會(huì)用到以下代碼:
 
 1 import java.io.*;
 .
 .
 2 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2);
 3 FileOUtputStream os = new FileOutputStream("MyBug.test");
 4 bug.save(os);
 
 很簡(jiǎn)單,對(duì)嗎?當(dāng)然,一旦對(duì)象已經(jīng)被序列化,沒有人能阻止你繼續(xù)操縱對(duì)象的狀態(tài)。上一 個(gè)例子中包涵了一個(gè)在被寫入磁盤時(shí)已經(jīng)存在對(duì)象的拷貝。因此你必須要十分謹(jǐn)慎,以防 在對(duì)對(duì)象做出所有的修改之后沒有序列化對(duì)象,從而丟失了對(duì)象的狀態(tài)修改信息。
 
 以下是怎樣恢復(fù)一個(gè)對(duì)象的拷貝:
 
 1 import java.io.*
 .
 .
 2 FileInputStream fis = new FileInputStream("MyBug.test");
 3 BugReport bug = new BugReport().restore(fis);
 
 這更簡(jiǎn)單!是不是Java的功能越來(lái)越強(qiáng)大了?
 
 現(xiàn)在我們修改第二個(gè)例子的第3行,使對(duì)象被寫入一個(gè)字節(jié)數(shù)組而不是一個(gè)文件:
 
 1 import java.io.*
 .
 .
 2 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2);
 3 字 節(jié)ArrayOutputStream os = new 字 節(jié)ArrayOutputStream();
 4 bug.save(os);
 
 好了,我們已經(jīng)構(gòu)造了一個(gè)對(duì)象,并且學(xué)會(huì)把它序列化后放入一個(gè)字節(jié)OutputStream。然 后,我們將把這個(gè)字節(jié)OutputStream轉(zhuǎn)化為一個(gè)Base64編碼的字符串。
 
 
 .Base64編碼
 
 目前的Internet E-mail標(biāo)準(zhǔn)--簡(jiǎn)單郵件傳遞協(xié)議(SMTP)在RFC821中宣布。對(duì)于我們來(lái)說(shuō), RFC821對(duì)郵件的內(nèi)容規(guī)定了兩條重要但不難實(shí)現(xiàn)的限制。
 
 1.郵件的內(nèi)容必須全部為7-比特的美國(guó)ASCII碼。
 
 2.每一行的長(zhǎng)度不能超過(guò)1000的字符。
 
 因此為了通過(guò)SMTP用E-mail進(jìn)行傳送,內(nèi)存的序列化對(duì)象必須轉(zhuǎn)化為和以上相容的格式。
 
 RFC1521提供了一個(gè)可行的方案。它定義了郵件的內(nèi)容部分,使之能包涵多種形式的數(shù) 據(jù)。這種標(biāo)準(zhǔn)就是目前眾所周知的MIME。
 
 按照RFC1521編碼過(guò)程為:輸入是24個(gè)比特,輸出是4個(gè)字節(jié)。24個(gè)比特輸入組從左至右 由3個(gè)8比特的輸入組形成。這24個(gè)比特被看成4個(gè)連續(xù)的6比特組,而每個(gè)6比特輸入組被翻 譯為Base64碼表中的一個(gè)數(shù)字。
 
 這意味著如果我們有下面的3個(gè)字節(jié)的輸入--xC,xF3,xFF--它將會(huì)被轉(zhuǎn)化為如下 的Base64的編碼:x3,xF,xF,x3F。
 
 
 圖Base64編碼實(shí)例
 
 Base64編碼似乎有點(diǎn)神秘,但實(shí)現(xiàn)它的代碼卻非常簡(jiǎn)單,在下面的程序中我們可以看到 這一點(diǎn)。在這個(gè)例子中,我們創(chuàng)建了一個(gè)新類,Codecs?,F(xiàn)在,Codecs有兩個(gè)方法函數(shù):一 個(gè)用來(lái)對(duì)字符數(shù)組編碼,一個(gè)用來(lái)對(duì)String類編碼。對(duì)String類編碼的方法函數(shù)簡(jiǎn)單地調(diào) 用String類的getBytes()函數(shù),然后對(duì)返回的結(jié)果字符數(shù)組進(jìn)行編碼。我們將增加從Base6解 碼至原先格式的方法函數(shù)。
 
 1 public class Codecs {
 2 private Codecs() // do not instantiate this class
 
 3 public final static String base64Encode(String strInput) {
 4 if (strInput == null) return null;
 5 byte byteData[] = new byte[strInput.length()];
 6 strInput.getBytes(0, strInput.length(), byteData, 0);
 7 return new String(base64Encode(byteData), 0);
 8 }
 
 9 public final static byte[] base64Encode(byte[] byteData) {
 10 if (byteData == null) return null;
 11 int iSrcIdx; // index into source (byteData)
 12 int iDestIdx; // index into destination (byteDest)
 13 byte byteDest[] = new byte[((byteData.length+2)/3)*4];
 
 14 for (iSrcIdx=0, iDestIdx=0; iSrcIdx >> 2) & 077);
 16 byteDest[iDestIdx++] = (byte) ((byteData[iSrcIdx+1] >>> 4) & 017 |
 (byteData[iSrcIdx] << 4) & 077); 17 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx+2]>>> 6) & 003 |
 (byteData[iSrcIdx+1] << 2) & 077); 18 byteDest[iDestIdx++]="(byte)" (byteData[iSrcIdx+2] & 077); 19 } 20 if (iSrcIdx < byteData 26 else 27 byteDest[iDestIdx++]="(byte)" ((byteData[iSrcIdx] << 4) & 077); 28 } 29 for (iSrcIdx="0;" iSrcIdx < iDestIdx; iSrcIdx++) { 30 if (byteDest[iSrcIdx] < 26) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + "A"); 31 else if (byteDest[iSrcIdx] < 52) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + "a"-26); 32 else if (byteDest[iSrcIdx] < 62) byteDest[iSrcIdx]="(byte)(byteDest[iSrcIdx]" + "0"-52); 33 else if (byteDest[iSrcIdx] < 63) byteDest[iSrcIdx]="+" ; 34 else byteDest[iSrcIdx]="/" ; 35 } 36 for ( ; iSrcIdx < byteDest.length; iSrcIdx++) 37 byteDest[iSrcIdx]="=" ; 38 return byteDest; 39 } 40 }
 
 
 1-2定義public的Codecs類和一個(gè)不能被用戶調(diào)用的構(gòu)造函數(shù)。通常,這個(gè)類
 
 不應(yīng)被例示。
 
 3-8定義一個(gè)encodeBase64()方法函數(shù)。它的參數(shù)類型是String類型,返回Base64編碼的String。 它通過(guò)調(diào)用String。getBytes()并將結(jié)果數(shù)組傳送至encodeBase64(byte[])來(lái)完成函數(shù)的 功能。
 
 9-39定義一個(gè)encodeBase64()方法函數(shù)。參數(shù)為字符數(shù)組,返回Base64編碼的數(shù)組數(shù)組。
 
 10如果參數(shù)值為null,退出方法函數(shù)。
 
 11-13定義工作變量,其中字節(jié)Dest數(shù)組包含了返回調(diào)用者的編碼。注意,轉(zhuǎn)換后的數(shù)組 比輸入數(shù)組大約大三分之一。這是因?yàn)槊總€(gè)三字節(jié)s組被轉(zhuǎn)換成四個(gè)字節(jié)。
 
 14-19循環(huán)遍歷整個(gè)輸入數(shù)組,每次24比特,把這三個(gè)8比特組轉(zhuǎn)換成四個(gè)兩兩之間相距二 比特的6比特組。這段代碼比最初出現(xiàn)時(shí)簡(jiǎn)單。仔細(xì)學(xué)習(xí),看看和前面的例子有什么不同。
 
 20-28如果輸入數(shù)組的字節(jié)s數(shù)目不是3的倍數(shù),則轉(zhuǎn)換余下的1或2個(gè)字節(jié)。
 
 29-35把所得的編碼數(shù)據(jù)作為Base64碼表的下標(biāo)。(Base64碼表在RFC1521中說(shuō)明)
 
 36-37把目標(biāo)串中的沒有使用的字符置為"="。
 
 38返回給調(diào)用者基于Based64的編碼。
 我們已經(jīng)取得了很重要的進(jìn)展。到目前為止,我們已能序列化對(duì)象并將它放入內(nèi)存,把它 轉(zhuǎn)化為基于Base64編碼,目的是使用E-mail工具將它發(fā)給目標(biāo)用戶。作為我們目前進(jìn)展的 總結(jié),下面有一個(gè)代碼片斷,它生成一個(gè)BugReport對(duì)象實(shí)例,把它序列化并放入內(nèi)存,然后 轉(zhuǎn)化為Base64編碼。
 
 1 import java.io.*;
 2 import Codecs.base64Encode;
 :
 3 BugReport bug = new BugReport(1.0, "Crashes when spell checker invoked", 2);
 4 字 節(jié)ArrayOutputStream os = new 字 節(jié)ArrayOutputStream();
 5 bug.save(os);
 6 String strSerializedBug = os.toString();
 7 strSerializedBug = Codecs.base64Encode(strSerializedBug);
 
 
 .和SMTP服務(wù)器連接
 
 如果你想發(fā)一封郵件,必須通過(guò)以下五個(gè)步驟:
 
 1.為SMTP服務(wù)器申請(qǐng)一個(gè)域名
 
 2.建立一個(gè)TCP/IP的會(huì)話(session)
 
 3.在服務(wù)器上登錄
 
 4.填寫收信人的地址
 
 5.撰寫郵件的內(nèi)容
 
 下面分別就這些步驟進(jìn)行討論。
 
 為SMTP服務(wù)器申請(qǐng)一個(gè)域名
 
 正如你發(fā)送普通信件一樣,你首先得找一個(gè)郵局。對(duì)居民區(qū)和商業(yè)單位來(lái)說(shuō)這是一件非 常簡(jiǎn)單的事,因?yàn)猷]筒就在門口。Internet上的電子郵件也同樣簡(jiǎn)單。
 
 你或許已經(jīng)有一個(gè)Internet的電子郵件賬號(hào),如果這樣,你的郵件閱讀工具,可能是和WWW 瀏覽器捆綁在一起的軟件,或者是單獨(dú)的軟件如Eudora,要求你輸入一個(gè)有關(guān)SMTP服務(wù)器 的信息。它就是你所使用的DNS服務(wù)器的域名。這里有一些Internet服務(wù)提供商(ISP)供商的SMTP 服務(wù)器域名:
 
 你的Internet服務(wù)提供商將為它的SMTP服務(wù)器使用和上例相似的域名。
 
 ..與服務(wù)器建立一個(gè)TCP/IP會(huì)話
 
 一般SMTP服務(wù)器在25號(hào)端口(port25)監(jiān)聽連接請(qǐng)求。因此,和一個(gè)SMTP主機(jī)建立一個(gè)TCP/IP 連接就是建立一個(gè)和25號(hào)端口連接的套接字(socket)。下面這段Java程序試圖建立一個(gè)和 域名為"smtp.tjd.com"的主機(jī)的連接:
 
 1 import java.net.*;
 2 import java.io.*;
 3 :
 4 Socket socketSmtpServer = null;
 5 DataOutputStream dos = null;
 6 DataInputStream dis = null;
 
 7 try {
 8 socketSmtpServer = new Socket("smtp.tjd.com", 25);
 9 dos = new DataOutputStream(socketSmtpServer.getOutputStream());
 10 dis = new DataInputStream (socketSmtpServer.getInputStream());
 11 }
 12 catch (UnknownHostException e) {throw (e);}
 13 catch (IOException e) {throw (e);}
 
 
 這段代碼在建立TCP/IP連接的同時(shí)創(chuàng)建一個(gè)DataOutputStream對(duì)象和一個(gè)DataInputStream 對(duì)象,我們以后將會(huì)使用它們從SMTP服務(wù)器發(fā)送和接收數(shù)據(jù)。
 
 ..在服務(wù)器上登錄
 
 和在UNIX系統(tǒng)或者數(shù)據(jù)庫(kù)系統(tǒng)上登錄不同,你無(wú)須在一個(gè)SMTP服務(wù)器上真正地登錄,因?yàn)?這里沒有確認(rèn)/授權(quán)的過(guò)程,根本不需要真正登錄。你只是簡(jiǎn)單地讓服務(wù)器能識(shí)別你,這樣才 有資格成發(fā)送郵件。這一步其實(shí)不真正需要,但是不能忽略它。
 
 當(dāng)你第一次和服務(wù)器連接時(shí),服務(wù)器給你發(fā)送確認(rèn)它自己和它的SMTP版本號(hào)兩行數(shù)據(jù)。 我們不關(guān)心這些數(shù)據(jù),我們只是讀入它們并且將其忽略。在我們讀入這些數(shù)據(jù)后,服務(wù)器將 把我們推到"司機(jī)"的座位上然后等待和回答命令。下面是用Java語(yǔ)言實(shí)現(xiàn)的登 錄過(guò)程:
 
 1 String strBuf;
 2 String strMyName = "tomdaley";
 3 strBuf = dis.readLine();
 4 strBuf = dis.readLine();
 5 dos.writeBytes("HELO " + strMyName + "\n");
 6 strBuf = dis.readLine();
 7 dos.writeBytes("RSET\n");
 8 strBuf = dis.readLine();
 
 
 HELO命令讓服務(wù)器識(shí)別你的身份,RSET命令重置SMTP服務(wù)器的狀態(tài)。如果一切順利,RSET 命令不是必須的。但是因?yàn)槭虑椴⒎强偸沁M(jìn)行順利,而RSET是一個(gè)發(fā)送和執(zhí)行起來(lái)很" 便宜"的命令,因此首先執(zhí)行這條命令是一個(gè)很好的方法。
 
 注意在每條write字節(jié)s()語(yǔ)句后的readLine()語(yǔ)句,SMTP服務(wù)器為你發(fā)送的每條命令 返回一個(gè)狀態(tài)信息。狀態(tài)信息以一個(gè)3字節(jié)的數(shù)字開始,它被用來(lái)判斷命令執(zhí)行成功與否。 RFC821對(duì)此有詳盡的解釋。
 
 ..寫明收信人的地址
 
 下一步我們準(zhǔn)備填寫收信人的地址。和所有禮貌的信件相似,我們應(yīng)該提供給郵件傳送 代理和接收者地址同樣清楚的回信地址。下面Java的代碼實(shí)現(xiàn)了這個(gè)功能:
 
 1 dos.writeBytes("MAIL FROM:\n");
 2 dis.readLine();
 3 dos.writeBytes("RCPT TO:\n");
 4 dos.readLine();
 
 
 ..撰寫郵件的內(nèi)容
 
 現(xiàn)在我們準(zhǔn)備創(chuàng)建郵件最有趣的部分--數(shù)據(jù)區(qū)域。數(shù)據(jù)區(qū)域包括兩個(gè)子區(qū)域:
 
 1.郵件客戶程序閱讀的頭部信息
 
 2.MIME-編碼的正文和數(shù)據(jù)
 
 數(shù)據(jù)區(qū)域的頭部信息并不是必須的,但在你使用收信客戶程序看信時(shí),它能使你的郵件 看起來(lái)更美觀。頭部信息是郵件內(nèi)容的一個(gè)概括,它使郵件更容易管理。
 
 數(shù)據(jù)區(qū)域頭部信息和辦公室間的備忘錄的開頭相似,可以這樣發(fā)送:
 
 1 dos.writeBytes ("DATA\N");
 2 strBuf = dis.readLine();
 3 dos.writeBytes ("To: Tom Daley \n");
 4 dos.writeBytes ("From: Tom Daley \n");
 5 dos.writeBytes ("Subject: Bug Report\n");
 
 
 注意,我們?cè)诎l(fā)送"DATA"命令后讀入且只讀入一行。當(dāng)你發(fā)送"DATA" 命令的時(shí)候,服務(wù)器可能回送下面形式的消息作為應(yīng)答:"354Entermail,endwith "."onalinebyitself"。這意味著如果SMTP服務(wù)器沒有看到信件的 結(jié)尾,不會(huì)通過(guò)套接字發(fā)送任何數(shù)據(jù)。
 
 為了能傳送序列化編碼對(duì)象,我們把它封閉到郵件內(nèi)容的MIME部分。MIME部分最開始是 純文本,用MIME的語(yǔ)法來(lái)描述,就是"Content-Type:text/plain。"。在文本部 分我們將發(fā)送若干指令,用來(lái)指明一起發(fā)送的對(duì)象和關(guān)于它的簡(jiǎn)單說(shuō)明。下面的代碼實(shí)現(xiàn) 了這種功能:
 
 1 String strBoundary = "SimpleBoundary";
 2 String strInstructions = "Save the attached file and read it with BugNews.class.";
 2 dos.writeBytes("Mime-Version 1.0\n");
 3 dos.writeBytes("Content-Type: multipart/mixed; boundary=\"" + strBoundary + "\"\n");
 4 dos.writeBytes("--" + strBoundary + "\n");
 5 dos.writeBytes("Content-Type: text/plain; charset=\"us-ascii\"\n\n");
 6 dos.writeBytes(strInstructions + "\n");
 
 
 現(xiàn)在我們?cè)撟鲑M(fèi)了這么多的口舌一直想做的事情,將序列化的對(duì)象附在SMTP郵件內(nèi)容上。 請(qǐng)記住,郵件內(nèi)容每行不能超出1000個(gè)字節(jié)。對(duì)于有多個(gè)部分的MIME則有更多的限制,即每 行不能超出74個(gè)字節(jié)的二進(jìn)制編碼。這意味著我們必須聲明一個(gè)string對(duì)象,它包含序列 化的,基于BASE64編碼對(duì)象,然后我們以每次74個(gè)字節(jié)的方式將這個(gè)string對(duì)象寫入SMTP 套接字。
 
 1 dos.writeBytes("--" + strBoundary + "\n");
 2 dos.writeBytes("Content-Type: application/octet-stream; name=\"BugReport.bug\"\n");
 3 dos.writeBytes("Content-Transfer-Encoding: base64\n");
 4 dos.writeBytes("Content-Disposition: attachment; 2005101201304.htm=\"BugReport.bug\"\n");
 5 dos.writeBytes("Content-Description: Bug Report from a customer\n\n");
 
 6 int iLines = strObject.length() / 74;
 7 for (i = 0; i
 
 我們完成了!現(xiàn)在我們的錯(cuò)誤報(bào)告(bugreport)正延著全球SMTP郵件分發(fā)系統(tǒng)迂回前進(jìn),它將很快出現(xiàn)在一些人的辦公桌上。不過(guò)我敢打賭,他們收到錯(cuò)誤報(bào)告時(shí)的心情不會(huì)和你解決如何發(fā)送它時(shí)的心情一樣愉快 .
 |  |