在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为邮件的地址,如bill@ms.com。 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/

时间: 2024-10-02 01:05:17

在J2ME平台上构建你的邮件程序的相关文章

在windows平台上构建自己的PHP实现方法(仅适用于php5.2)

本篇文章是对在windows平台上构建自己的PHP实现方法进行了详细的分析介绍,需要的朋友可以参考下(仅适用于php5.2)   构建步骤1, 安装vs2008 2, 安装windows sdk 6.1 3, 下载php 5.2源码,可以从此处获取Releases (先不要解压) 4, 下载bindlib_w32.zip,点击下载bindlib_w32.zip5, 下载win32build.zip,点击下载win32build.zip6, 下载libxml2,iconv,zlib等库 http:

【Spark Summit EU 2016】使用Mobius在.NET平台上构建你的下一个Spark应用

本讲义出自Kaarthik Sivashanmugam在Spark Summit EU上的演讲,主要介绍了微软公司的用于在.NET平台上构建Spark应用的C#的API--Mobius. 在演讲中,Kaarthik Sivashanmugam分享了Mobius开发动机,对于相关语言的支持情况以及Mobius与Spark的关系,以及如何部署和运行Mobius应用等相关内容.

如何在AWS云平台上构建千万级用户应用

如何在AWS云平台上构建千万级用户应用 方国伟 首席云技术顾问 --弹性的确是云计算的一个重要特性 --AWS云平台也供Auto Scaling功能来帮助用户实现弹性伸缩 --应用服务的弹性伸缩需要良好的设计 如何在AWS云平台上构建千万级用户应用

解决在J2ME平台上的手机游戏移植的问题

手机游戏移植主要的工作是把原来的一款别的型号手机上的游戏.经过修改能在当前型号的手机上运行和使用的过程.所以可以把这个工作细分为几方面的事情: 1.处理屏幕尺寸 这也是最重要的一点.不同型号的手机.屏幕大小不同.分辨率不同.所以要保证每款游戏放在每种型号的手机上都能达到同样的运行效果.那的确是件困难的事情.所以移植的时候就尽量找差距较小的机型做移植.程序中需要注意的就是双缓冲的尺寸.和画面内容的位置.当然最愿意看到的就是能有个全局变量来控制整个游戏场景. 2.修改按键值 这是另一个重要的方面.确

在windows平台上构建自己的PHP实现方法(仅适用于php5.2)_php技巧

构建步骤1, 安装vs20082, 安装windows sdk 6.13, 下载php 5.2源码,可以从此处获取Releases (先不要解压)4, 下载bindlib_w32.zip,点击下载bindlib_w32.zip5, 下载win32build.zip,点击下载win32build.zip6, 下载libxml2,iconv,zlib等库 http://www.zlatkovic.com/pub/libxml/7, 创建C:\php5.2-mybuild (也可以改成你想要的目录,比

从Linux和UNIX平台上的预封装应用程序访问Optim归档数据

通过 Optim http://www.aliyun.com/zixun/aggregation/13722.html">Open Data Manager,Optim 可使用开放标准(比如 ODBC.JDBC 或 XML)提供对归档数据的持续访问.了解 Linux®/UNIX® 环境中访问 Optim 归档数据可用方法之间的区别,以及如何在 Linux 环境中配置 ODBC 来使用报告工具(比如 IBM Cognos®)访问 Optim 归档数据. Optim Open Data Man

在Google App Engine Java版上构建电子书分享网站

简介:"云计算"是目前热门的技术方向,本文从 Google 的云计算平台 App Engine 入手,简单介 绍了 Google 面向 Java 开发人员的云计算平台.从一个实际的电子书分享应用构建出发,讲述了如何在 Google App Engine 平台上构建这个应用程序. "云计算"基本概念的介绍 根据维基百科上的定义,云计算是一种动态易扩展,而且通常是通过互联网提供的虚拟化的资源计算 方式,用户不需要了解云内部的细节,也不必具有云内部的专业知识,或者直接控制

怎样在移动平台上美化邮件

问题描述 怎样在移动平台上美化邮件 有什么好的办法,在不通过html的方式的情况下,又能使得自己的邮件美观的方法? 解决方案 可以使用选用第三方邮件发送平台,比如国外的有sendgrid.mailgun,国内的有sendcloud,可以统一编辑,使用方便

Freeline - Android平台上的秒级编译方案

Freeline 技术揭秘 Freeline是什么? Freeline是蚂蚁金服旗下一站式理财平台蚂蚁聚宝团队15年10月在Android平台上的量身定做的一个基于动态替换的编译方案,5月阿里集团内部开源,稳定性方面:完善的基线对齐,进程级别异常隔离机制.性能方面:内部采用了类似Facebook的开源工具buck的多工程多任务并发思想:端口扫描,代码扫描,并发编译,并发dx,并发merge dex等策略,在多核机器上有明显加速效果,另外在class及dex,resources层面作了相应缓存策略