程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2ME >> 在J2ME平台上構建你的郵件程序

在J2ME平台上構建你的郵件程序

編輯:J2ME
在J2ME平台上構建你的郵件程序
Jacky Pan



Table of Contents
1. 教程的介紹和程序的安裝

2. 程序的結構

3. 界面的設計

4. 賬戶的管理

5. MIDlet和Servlet的網絡連接

6. Servlet和JavaMail

7. 簡單的XML

8. 小結




1.教程的介紹和程序的安裝



本教程講述了如何在J2ME平台上編寫一個簡單的郵件應用程序,包括界面的設計,郵件的發送/接受,郵件賬戶的創建/修改/刪除,後台Servlet的編寫。



為了運行本教程所帶的演示程序,您需要安裝下列軟件:

1. WTK2.0 (Java.sun.com)

2. Apache Tomcat (www.apache.org)



安裝和運行示例程序的步驟:

1. 從http://groups.yahoo.com/group/OriTec/files/下載MicroMail Beta.zip(包括了源代碼和二進制文件)

2. 解壓MicroMail Beta.zip至$TMP

3. 在$WTK/aPPS下建一新目錄MicroMail

4. 拷貝$TMP/src/clIEnt/* 至 $WTK/aPPS/MicroMail/src/

5. 拷貝$/TMP/bin/server/mail.war至$TOMCAT/webaPPS/

6. 運行Tomcat

7. 運行WTK2.0, “Open Project” 並選中MicroMail


8. 設置URL為MailAgent的地址http://server/mail/MailAgent


2. 程序的結構

采用ClIEnt-Web Server-Mail Server三層架構,如圖1。

MIDlet

(Cell Phone)

Servlet

(Web Server)

Mail Server











My Application


Figure 1



Cell Phone將請求(接受/發送郵件)傳給Web Server,Web Server將這些http請求轉換成對POP3或 SMTP Server的請求。POP3/SMTP Server執行相應的請求,並將相應通過Web Server返回給Cell Phone.



客戶端(PDA/手機)為J2ME平台上的程序。MIDP2提供了一些基本網絡連接的API。利用這些API可以使得J2ME程序可以向遠端發出Http請求,並接受響應,傳遞數據流。



MailAgent 為Servlet,用來接收來自客戶端的請求,並調用Java Mail API,將這些請求轉變成對遠端Mail Server 的請求,同時將Mail Server的響應傳給客戶端。



那麼為什麼要采用這樣的架構了?這是因為MIDP2.0只支持HTTP協議, 而不支持POP3 和 SMTP等其它應用層協議,而J2EE提供了完整的Java Mail的API,所以考慮通過一個Servlet將Http請求轉換成POP3或SMTP請求。另一個原因是,很多運營商可能只提供有限的網絡訪問的能力,而通過一個agent則提供了程序部署的靈活性。



下面簡單介紹一下源碼的結構,在客戶端,ui包中的類定義程序的用戶界面,utility包中的類定義了數據庫的操作,網絡的連接,XML的解析等,mail包中的類定義了郵件賬戶,郵件的頭。

ui package:

AccountForm.Java

AccountsList.Java

Confirm.Java

ConfirmListener.Java

MailMIDlet.Java

MessageList.Java

ProgressForm.Java

SendMessage.Java

WriteContent.Java



utility package:

DBOperator.Java

HeadParser.Java

NetAdapter.Java

Networker.Java

ParserListener.Java



mail package:

MailAccount.Java

MessageHead.Java



服務器端只有一個文件MailAgent.Java,包含了一個servlet,用來做midlet和郵件服務器的橋梁。






3. 界面的設計

MIDP2.0提供了大量的API供開發者創建和控制用戶界面。在包Javax.microedition.lcdui中提供了List, Form, TextBox, Alert等Screen組件,在Form中可以包含一系列Item,如ChoiceGroup, TextFIEld, StringItem等。包中還提供了Command組件,以及相應的Listener。



源文件ui/MailMIDlet.Java定義了程序的入口以及MicroMail的主頁面。如圖2主頁面是一個List,顯示了幾個功能模塊,包括添加賬戶,修改/刪除賬戶,接受郵件,發送郵件。


Figure 2

public MailMIDlet()

{

display = Display.getDisplay(this);

/* 創建List */

mainList = new List("MicroMail0.1", Choice.IMPLICIT);

/* 創建兩個控制按鈕OK和Exit */

cmOK = new Command("OK", Command.OK, 1);

cmExit = new Command("Exit", Command.EXIT, 1);

/* 向mainlist中添加內容 */

mainList.append("Add Account", null);

mainList.append("Edit Account", null);

mainList.append("Receive Message", null);

mainList.append("Send Message", null);

/* 為mainlist添加Command */

mainList.addCommand(cmOK);

mainList.addCommand(cmExit);

/* MailMIDlet實現了CommandListener接口,可以作為監聽器 */

mainList.setCommandListener(this);



……

}



通過AccountForm(源文件ui/AccountForm.Java),用戶可以添加和修改郵件賬戶,如圖3。



Figure 3a Figure 3b



AccountForm包含了6個TextFIEld,分別顯示郵件賬戶的6個屬性。account為賬戶名,也是賬戶的唯一標識,不可重名。address為郵件的地址,如[email protected]。 user, passWord是在郵件服務商注冊的用戶名和密碼。pop3, smtp是pop3服務器和smtp服務器的名字或地址。

private void setContent(MailAccount Macc)

{

account = new TextField("Account: ", "", 20, TextFIEld.ANY);

address = new TextField("Address; ", "", 40, TextFIEld.EMAILADDR);

user = new TextField("User Name: ", "", 20, TextFIEld.ANY);

password = new TextField("Password: ", "", 20, TextFIEld.PASSWord);

pop3 = new TextField("POP3 Server: ", "", 20, TextFIEld.ANY);

smtp = new TextField("SMTP Server: ", "", 20, TextFIEld.ANY);



if (Macc != null)

{

account.setString(Macc.accountName);

address.setString(Macc.address);

user.setString(Macc.username);

password.setString(Macc.passWord);

pop3.setString(Macc.POP3Server);

smtp.setString(Macc.SMTPServer);

}



append(account);

append(address);

append(user);

append(passWord);

append(pop3);

append(smtp);



}

其它頁面與AccountForm類似,在此不再贅述,請大家參照源代碼和MIDP API的文檔。




4. 賬戶的管理

郵件賬戶的創建,修改,刪除都涉及到對數據記錄的存取。MIDP提供了一種叫做記錄管理系統(Record Management System)的機制來存儲和訪問數據。



Javax.microedition.rms.RecordStore提供了一些API來操作這個系統。靜態方法openRecordStore用來打開或創建一個RecordStore對象。方法addRecord, getRecord, deleteRecord, setRecord分別用來添加,訪問,刪除或修改RecordStore對象中的記錄。



utility/DBOperator.Java中封裝了這些方法,從而實現添加,修改,刪除郵件賬戶的操作。以添加帳戶為例,下面的addRecord方法用來向RecordStore中添加一個記錄,同時把這個記錄所表示的郵件賬戶加到一個accounts中,accounts是一個Vecotr,用來存儲系統中當前的賬戶。參數str包含了賬戶的所有信息,如賬戶名,地址,用戶名,密碼,pop3,smtp等,它們之間用空格隔開。



public void addRecord(String str)

{

int id;

byte[] rec = str.getBytes();

String record = str;



try

{

/* 向RecordStore中添加記錄 */

id = rs.addRecord(rec, 0 , rec.length);



/* 同時把帳戶添加到accounts向量中 */

MailAccount mailacc = MailAccount.createMailAccountFromString(id, str);

accounts.addElement(mailacc);

}

catch(RecordStoreException rse)

{

rse.printStackTrace();

}



}




5. MIDlet和Servlet的網絡連接

MIDP的網絡API在包Javax.microedition.io中定義,其中HttpConnection提供了對HTTP協議的支持。



在文件utility/Networker.Java中通過調用這些網絡API實現了接收當前信箱中郵件列表setMessageList,接受某一郵件的內容receiveMessage,發送郵件sendMessage等功能。以sendMessage為例。



public void sendMessage(final String url, final String formData)//send a message

{

/* 創建新的進程 */

Thread t = new Thread()

{

public void run()

{

HttpConnection http = null;



byte[] data = formData.getBytes();

try

{

/* 打開並返回一個HTTP連接 */

http = (HttpConnection) Connector.open(url);

......

/* 設置HTTP請求頭 */

http.setRequestMethod(HttpConnection.POST);

http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

http.setRequestProperty("User-Agent",

"Profile/MIDP-1.0 Configuration/CLDC-1.0");

http.setRequestProperty("Content-Language", "en-US");

http.setRequestProperty("Accept", "application/octet-stream");

http.setRequestProperty("Connection", "close"); // optional

http.setRequestProperty("Content-Length", Integer.toString(data.length));

......

/* 打開輸出流 */

OutputStream os = http.openOutputStream();

/* 寫郵件數據 */

os.write(data);

/* 關閉輸出流 */

os.close();



}

catch (IOException ioe)

{

......

}

finally

{

try

{

/* 關閉連接 */

if (http != null) http.close();

}

catch (IOException ignored) {}

}

}

};

/* 啟動進程 */

t.start();



}



MIDlet通過HTTP連接向Servelet發出接受或發送郵件的請求,Servlet根據不同的請求向郵件服務器發出相應的請求,並將返回結果傳給MIDlet。




6. Servlet和JavaMail

J2EE中提供了對郵件相關協議的支持,包javax.mail和包javax.mail.internet 中定義了JavaMail API。下面是MailAgent.Java中Servlet處理接受郵件列表請求的代碼片斷。

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException

{

PrintWriter out = response.getWriter();



String typeStr = request.getParameter("type");

int type = Integer.parseInt(typeStr);



String pop3Server;

String username;

String passWord;



PropertIEs props;

String provider;



switch (type)

{

case RECEIVE_LIST:

/* 提取參數pop3服務器,用戶名,密碼 */

pop3Server = request.getParameter(paramPOP3);

username = request.getParameter(paramName);

passWord = request.getParameter(paramPass);



if (pop3Server == null || username == null || passWord == null)

{

out.print(STATUS_BAD);//XML?

return;

}



props = new PropertIEs();

provider = "pop3";

try

{

/* 以指定的用戶名和密碼連接pop3服務器 */

Session session = Session.getDefaultInstance(props, null);

Store store = session.getStore(provider);

store.connect(pop3Server, username, passWord);

/* 得到INBOX收件箱 */

Folder inbox = store.getFolder("INBOX");



if (inbox == null)

{

out.print(STATUS_BAD);//XML?

return;

}

/* 打開收件箱 */

inbox.open(Folder.READ_ONLY);

/* 得到收件箱中的郵件列表,並寫到 XML中 */

writeXML(inbox.getMessages(), out);



inbox.close(false);

store.close();

}

catch(Exception e)

{

out.println(e.getMessage());

e.printStackTrace();

}



out.close();



break;



case RECEIVE_MESSAGE:

......

break;



case SEND_MESSAGE:

......

break;

}



}

J2EE程序的編譯和部署請大家參照相關的書籍或文檔。http://www.tusc.com.au/tutorial/Html/ 的<<Tutorial for building J2EE Applications using JBOSS and ECLIPSE>>是一篇不錯的文檔。




7. 簡單的XML

在MIDlet接受郵件時,首先向Servlet請求傳送郵箱中當前郵件的列表。列表中包括了郵件的頭部信息,包括發送者的地址,郵件的主題,發送的時間等,如圖4。


Figure 4

在郵件主題中可能包括任何字符,所以沒有辦法用某一特殊字符分隔這些信息,而XML正好適合傳輸這種具有特定格式的信息。在Servlet端,把有用的郵件頭部信息作為XML的元素寫到輸出流中。

private void writeXML(Message[] messages, PrintWriter out)

{

out.println("<?XML version=\"1.0\"?>");

out.println("<mail>");



if (messages == null)

{

out.println("<error>No Mail</error>");

}



try

{

int j = 0;

for (int i = messages.length -1; i >= 0; i--)

{

out.println("<message>");

/* 寫郵件頭 */

out.println("<from><![CDATA[" + InternetAddress.toString(messages[i].getFrom()) + "]]></from>");

out.println("<subject><![CDATA[" + messages[i].getSubject() + "]]></subject>");

out.println("<date>" + messages[i].getSentDate().toLocaleString() + "</date>");

out.println("<index>" + i + "</index>");

out.println("</message>");



j++;

if (j > 9)

{

/* 一次只看10個郵件 */

break;

}

}

}

catch(MessagingException me)

{

out.println("<error>" + me.toString() + "</error>");

}



out.println("</mail>");

}



在MIDlet端再解析這個XML,在J2ME平台上有許多免費的XML Parser,kxml就是其中的一個。可以從 http://kxml.enhydra.org/ 下載kXML 1.21的源代碼,jar文件以及API文檔。



下面是utility/HeadParser.Java中處理XML的代碼片斷

public void parse(InputStream in) throws IOException

{

Reader reader = new InputStreamReader(in);

XmlParser parser = new XMLParser(reader);

ParseEvent pe = null;



parser.skip();

/* 讀一個名字為mail的event */

parser.read(XML.START_TAG, null, "mail");



boolean trucking = true;

boolean first = true;



while (trucking)

{

/* 讀取下一個event */

pe = parser.read();



if (pe.getType() == XML.START_TAG)

{

/* 得到event的名字 */

String name = pe.getName();



if (name.equals("message"))

{

String from = null;

String subject = null;

String date = null;

int index = -1;



while ((pe.getType() != XML.END_TAG) ||

(pe.getName().equals(name) == false))

{

pe = parser.read();

if (pe.getType() == XML.START_TAG &&

pe.getName().equals("subject"))

{

pe = parser.read();

/* 得到event的內容 */

subject = pe.getText();

}

else if (pe.getType() == XML.START_TAG &&

pe.getName().equals("from"))

{

pe = parser.read();

from = pe.getText();

}

else if (pe.getType() == XML.START_TAG &&

pe.getName().equals("date"))

{

pe = parser.read();

date = pe.getText();

}

else if (pe.getType() == XML.START_TAG &&

pe.getName().equals("index"))

{

pe = parser.read();

index = Integer.parseInt(pe.getText());

}



}



/* 把郵件頭交給監聽器處理 */

headListener.itemParsed(from, subject, date, index);

}

else //Non Message block

{

while ((pe.getType() != XML.END_TAG) ||

(pe.getName().equals(name) == false))

pe = parser.read();

}

}

if (pe.getType() == XML.END_TAG &&

pe.getName().equals("mail"))

{

trucking = false;

}



}



具體的API的用法請大家參照kxml的文檔。JSR172 (J2ME Web Services Specification)提出了在J2ME平台上處理XML的規范,有興趣的朋友可以到jcp的網站 (http://www.jcp.org) 上看看,但目前可能還沒有廠商或組織的實現。




8. 小結

本文介紹了J2ME平台上郵件程序的編寫,涉及的知識點有:

1. J2ME的UI

2. Record Store

3. J2ME的網絡連接 / J2ME 和J2EE之間數據的傳遞

4. Parsing XML in J2ME

5. 簡單的Servlet

6. Java Mail APIs





參考資料有:

1. MIDP2.0 Spec, http://www.jcp.org

2. <<Core J2ME>>, http://www.coreJ2ME.com/

3. <<J2ME in Nutshell>>, http://www.oreilly.com

4. Tutorial for building J2EE Applications using JBOSS and ECLIPSE, http://www.tusc.com.au/tutorial/Html/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved