基于JAVA的邮件客户端的设计和实现
Posted dejyyhg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于JAVA的邮件客户端的设计和实现相关的知识,希望对你有一定的参考价值。
获取项目源文件,技术交流与指导联系Q:1225467431
摘 要
Java是Sun Microsystem公司推出的新一代面向对象和面向网络的程序设计语言,特别适合于Internet/Intranet上的应用软件开发,因此也把Java语言称为新一代网络程序设计语言。Java语言将面向对象、多线程、安全和网络等特征集于一身,为软件开发人员提供了很好的程序设计环境,当今企业级计算和应用中相当成熟和稳定的平台,在这个领域中不可否认地占据着领导地位。JBuilder是Borland公司推出的Java可视化集成开发工具,是目前最优秀的Java集成开发工具之一。利用JBuilder可以很方便的进行Web、数据库、XML、JavaBean以及EJB的开发。
本设计采用基于Java的技术开发了一个邮件客户端应用程序,采用JBuilder作为开发工具,完成的功能主要包括:主界面的设计、邮件的接收和发送功能,并制作了安装程序。主界面中实现了包括收件箱、发件箱、草稿箱、垃圾箱以及邮件阅读的功能。
本设计主要采用Java中的Javamail组件来实现邮件的接收与发送功能,JavaMail API是读取、撰写、发送电子信息的可选包,可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)。
本设计在介绍Java、JavaMail以及JBuilder的相关技术的基础上,介绍了邮件客户端系统的需求分析、概要设计以及详细设计的全过程,系统阐述了各阶段的设计流程和成果,调试了整个程序并展示了运行效果图。最后,对本设计的成果和不足进行了总结。
关键词:Java;Javamail;JBuilder;邮件客户端
Abstract
Java is the new generation programming language facing to object and network that produced by Sun Microsystem company,especially be fit for internet applications development on Internet/Intranet,so called Java as the new generation network programming language.Java contains so much characters to one,such as face to object,multithreading,and network,offering software developer a good programming environment, the quite mature and stable platform in enterprise account and applications nowadays,can’t disaffirm the leader in the field. Jbuilder is the Java wacth integration developing tools by Borland company,is one of the most Java integration developing tools nowadays.It is very convenient to develope web,database,XML,JavaBeans and EJB by JBuilder.
The project developes a mail client application based on Java programming technology,using JBuilder as the developing tools,achieve the follow main functions:mainframe design,mail’s receive and send function,and develop the setup programming.Mailfrme includes inbox,send,drafts,trash and mail reading function.
The project mostly adopts Javamail module in Java to achieve mail’s receive and send function.JavaMail API is the select packge that can read,write,send mail,can use to found the commen mail user agent as Eudora,Foxmail,MS Outlook Express(Mail User Agent,MUA for short).
The project introduces the requirement analysis,general designand the whole progress of the particular design of the mail client system,based on the presentation correlation technology of Java,JavaMail and JBuilder,entirely expatiate design flow and production of every phases,debug the entire programme and exibit the running expression pictures.At last,summarize the project’s production and shortage.
Key Words: Java; Javamail; JBuilder; Mail Client
目 录
第1章 绪论 1
1.1 问题的提出 1
1.2 本设计的目的、意义、范围、应达到的技术要求 1
1.3 本文研究的主要内容、目标与方法 1
1.4 各部分主要内容 2
1.4.1 Java概述 2
1.4.2 JavaMail API详解 2
1.4.3 邮件客户端的设计和实现 2
第2章 Java概述 3
2.1 Java语言的出现 3
2.2 Java语言的发展 3
2.3 Java标准技术要点 6
2.3.1 Java的特点 6
2.3.2 Java的应用 7
第3章 JavaMail API技术研究 10
3.1 JavaMail API简介 10
3.2相关协议一览 10
3.3初次认识JavaMail API 11
3.4 使用JavaMail API 14
3.4.1 发送邮件 14
3.4.2 接收邮件 15
3.4.3删除邮件和标志 16
3.4.4 邮件认证 17
3.4.5 回复邮件 17
3.4.6 转发邮件 18
3.4.7 使用附件 18
3.4.8 处理html邮件 21
3.4.9 在邮件中搜索短语 22
第4章 邮件客户端的设计和实现 23
4.1 需求分析 23
4.2 概要设计 23
4.2.1 邮件客户端基本功能 23
4.2.2 电子邮件传输过程 24
4.2.3 邮件客户端设计概要 24
4.3 详细设计 25
4.3.1 JDK的安装 25
4.3.2 环境变量配置 28
4.3.3 JBuilder的安装配置 30
5.3.4 详细设计说明 34
4.4 安装程序的设计和制作 53
4.4.1 应用程序的设计和制作 53
4.4.2 安装应用程序 56
结论 61
致谢 62
参考文献 63
附录 64
第1章 绪论
1.1 问题的提出
电子邮件(e-mail)是因特网上使用得最多的和最受用户欢迎的一种应用,将邮件发送到ISP的邮件服务器,并放在其中的收信人邮箱(mail box)中,收信人可随时上网到ISP的邮件服务器进行读取。电子邮件不仅使用方便,而且还具有传递迅速和费用低廉的优点,不仅可传递文字信息,而且还可附上声音和图像。所以开发一个安装于PC上的邮件客户端不仅使收、发邮件方便、快捷,也可完善后作为产品投入市场。而之所以基于Java,是因为Java是当今企业级计算和应用中相当成熟和稳定的平台,在这个领域中不可否认地占据着领导地位。它的跨平台性和面向对象的设计,使程序移植方便可行,也使开发过程简单而直观。
1.2 本设计的目的、意义、范围、应达到的技术要求
本次毕业设计的目的在于学习Java程序设计基本技术,学习电子邮件收发的相关技术,熟悉JBuilder软件开发环境,熟悉基于C/S模式的程序设计技术,学习用Javamail来开发邮件收发系统,熟悉项目开发的完整过程。
通过本次毕业设计,应该学会怎样进行一个项目的需求分析、概要设计、详细设计等软件开发过程,熟练地掌握Java程序设计的基本技术和方法,熟练地掌握JBuilder环境的使用方法,培养初步的项目分析能力和程序设计能力,把理论与实践相结合,为今后工作打下坚实的基础。
应完成项目的需求分析、概要设计、详细设计等前期工作,在此基础上,采用基于Java的程序设计技术完成邮件客户端的主界面设计,包括收件箱、发件箱、草稿箱、垃圾箱以及邮件阅读功能,采用基于Javamail的程序设计技术完成邮件的发送和收取功能,最终实现邮件客户端的各项基本功能。
1.3 本文研究的主要内容、目标与方法
本文主要讨论Java的应用,Java是Sun Microsystem公司推出的新一代面向对象和面向网络的程序设计语言,特别适合于Internet/Intranet上的应用软件开发,因此也把Java语言称为新一代网络程序设计语言。Java语言将面向对象、多线程、安全和网络等特征集于一身,为软件开发人员提供了很好的程序设计环境。Java是当今企业级计算和应用中相当成熟和稳定的平台,在这个领域中不可否认地占据着领导地位。
通过采用基于Java的程序设计技术完成邮件客户端的主界面设计,包括收件箱、发件箱、草稿箱、垃圾箱以及邮件阅读功能,采用基于Javamail的程序设计技术完成邮件的发送和收取功能,提供给用户一个美观、易用的邮件客户端。
主要用到Java中的Javamail组件,实现邮件的接收与发送,也可对基本功能进行扩展,JavaMail API是读取、撰写、发送电子信息的可选包,可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)。在JBuilder开发环境下进行开发,JBuilder是Borland公司推出的Java可视化集成开发工具,是目前最优秀的Java集成开发工具之一。利用JBuilder可以很方便的进行Web、数据库、XML、JavaBean以及EJB的开发,同时JBuilder还内置了Bea公司的WebLogic服务器、IBM的WebSphere服务器等,大大提高了JBuilder对企业级应用开发以及团体开发的支持。
1.4 各部分主要内容
1.4.1 Java概述
Java是Sun Microsystem公司推出的新一代面向对象和面向网络的程序设计语言,特别适合于Internet/Intranet上的应用软件开发,Java语言将面向对象、多线程、安全和网络等特征集于一身,为软件开发人员提供了很好的程序设计环境。这部分将叙述Java的出现、发展及特点等。
1.4.2 JavaMail API详解
JavaMail是Java中的一个组件,主要实现电子邮件的读取、撰写和发送等功能。这部分将主要介绍JavaMail API。
1.4.3 邮件客户端的设计和实现
这一部分将介绍基于Java的邮件客户端的设计和实现,包括详细的过程说明、部分源代码和安装程序设计与制作。
第2章 Java概述
2.1 Java语言的出现
自从1946年世界上第一台电子计算机问世以来,计算模式的发展经历了三个阶段:集中计算模式、分散计算模式和网络计算模式。Internet的出现,为在网络计算模式下的科学计算和信息处理提供了良好平台。然而,要充分利用网络计算模式的功能与效益,平台的运行环境是个制约因素,而Java语言和Java技术则是解决这一问题的最佳途径。
1991年,SUN公司的JameGosling,BillJoe等人试图为电视、烤箱等家用电器开发一种交互式的软件系统,这种应用需要的是那种小而可靠的系统,它能够移植,并且实时性好,适用于网络分布环境。流行的C 是自然的选择。不过,开发过程中遇到的许多难以克服的困难使他们意识到必须彻底解决问题了,最终,开发成功了一个名为Oak的软件,此中蕴藏着Java的原型,当时,并未引起人们的注意。
1994年下半年,随着Internet的迅猛发展,环球信息网WWW的快速增长,促进了Java语言研制的进展,使得它逐渐成为Internet上倍受欢迎的开发与编程语言。
1995年5月Java正式问世,一些著名的计算机公司纷纷购买了Java语言的使用权,如Microsoft、IBM、Netscape、Novell、Apple、DEC、SGI等。因此,Java语言被美国著名杂志PCMagazine评为1995年十大优秀科技产品(计算机类仅此一项入选)之一,随之大量出现了用Java编写的软件产品,受到工业界的重视与好评,认为“Java是八十年代以来计算机界的一件大事”。微软总裁比尔·盖茨在认真观察了一段时间后,确认“Java是长时间以来最卓越的程序设计语言”,并确定微软整个软件的开发战略从PC单机时代向以网络为中心的计算时代转移,而购买Java则是他的重大战略决策的实施部署。
因此,Java的诞生必将对整个计算机产业发生深远的影响,对传统的计算模型提出了新的挑战。SunMicrosystem公司的总裁ScottMcNealy认为:Java对Internet和WWW开辟了一个崭新的时代。有人预言:Java将成为网络上的“世界语”,今后,用其他语言编写的软件统统都要用Java语言来改写。
2.2 Java语言的发展
Java自正式问世以来到1999年经历了四年的历程,时间虽短,发展极快。一年一度在美国旧金山召开的世界JavaOne语言开发者大会(JavaOneDeveloperConference)盛况空前正说明了这一点。四年中每年的JavaOne大会,既是了解Java最新技术动态、应用成果和下一步发展趋势的最好场所,又是推动下一年Java快速发展的重要动力。
首届JavaOne大会于1996年召开,各届简况如下:
1996年5月29-31日,第一届,出席会议者6500余人,来自工业界的超过一半。有人评价说:“这是近年计算机界最光辉的一次盛会”。工业界相当看好Java语言,认为它的使用将会引起一场软件革命:从软件的设计风格、设计方法、设计目标到设计过程,都会产生彻底的变革,“甚至会改变此星球的生活方式”。
1997年,第二届,出席会议者10000人。Java的追随者不断增加,应用开发迅速起步。
1998年3月24-27日,第三届,出席会议者14000余人(注册人数),注册门票售价1195美元,否则1395美元,即使如此,仍有不少人不惜工本,挤入会场。本次会议除了软件巨头微软未参加会议外,几乎所有的计算机公司都参加了。展厅内设300多个展台,先后举行了90场专题讨论会,每场参加的人数从千人至五六千人不等。会议的主题是:通过Java的培训来带动Java软件的开发和技术研究,从而发展生产力,获取高额利润,提高生活质量,推动信息产业的进步。会议展出的内容大致如下:Java开发工具软件,如:JMF、JDK、SymantecVisualCafe、JavaDynamicManagementKit、JFC、JNDI、JavaStudio等;企业信息管理解决方案软件,如:EJB(EnterpriseJavaBeans);基于Java技术的信息家电,如:机顶盒、Java电话等;个人信息综合服务(Java戒指)、社会信息综合查询亭(Kiosk);电子商务软件、智能卡、JavaCardAPI等;网络计算环境下的Java服务器软件、远程方法调用(RMI)、基于Java技术的移动计算设备;JMS(JavaMessageService)用于出版、票据订阅的软件;JOS(JavaOS)、基于Java技术的NC和JavaStation。
1999年6月15-18日,第四届,出席会议者达20000人,300多家厂商参展,举办400多场技术讲座,555名演讲者慷慨陈词,精彩纷呈。这次大会的主要特点是:
1)Java框架结构被梳理清晰。本次JavaOne大会上,Sun公司的一个重大举措就是公布了Java平台的最新架构。重新定义的Java平台以Java2为核心,由面向企业和服务器市场的企业版Java2(J2EE)、面向传统PC客户机市场的标准版Java2(J2SE)和面向信息电器等后PC终端设备市场的Micro版Java2(J2ME)三大部分组成。其中,J2EE包括EnterpriseJavaBeans(EJB)、JavaServerPages&JavaServlets、JavaMailAPI和JavaMassageService组成。而J2ME则是原有的PersonalJava、EmbeddedJava、JavaCard以及刚刚推出的Kjava组成。虽然新框架结构中的内容都是已有的,但这样重新定义和组合,使得Java平台的概念简单化,从而变得易于理解,更适合于进行市场推广。
2)重点放在企业平台随着Internet的飞速发展,企业计算模式正摒弃C/S结构而采用Web-Browser结构,此即瘦客户端/胖服务器、大容量数据库的3层或N层体系结构。由于Java的特点,使得它在开发服务器端的应用程序方面有着得天独厚的优势,面向服务器端的J2EE为当今逐渐流行的N层体系结构提供了一个标准的Java计算平台:界面一致、工具简易、丰富、Web页面互联便捷,从而能大大加速和简化各种应用系统的开发。
3)加速后PC时代的进程计算机的发展创造了Internet,但是计算机现在却不是访问Internet的唯一方式。正在出现的信息化、智能化的消费类电子产品打破了PC作为信息终端的垄断地位,成为人类进入Internet的新门户。信息终端的多元化预示着所谓后PC(post-PC)时代的到来。消费类的信息终端量大面广,是典型的瘦客户机,其本身的资源和能力不能与PC相比,但必须更加智能化,并对服务器端的管理提出了更高的要求。而Java平台恰恰满足了这种要求。本次大会推出的Kjava虚拟机能运行在16以上的微处理器上,占用内存少,人们可以随心所欲,在资源有限的设备上方便地开发出各种各样的应用,直接运行在不同的消费类或其它电子设备上;而Jini的出现为Java网络连接提供了公共标准,使得任何Java设备都可以连入网络中被自动识别,并可充分利用网络上已有的各种资源。大力推进Jini的发展是Sun公司加速后PC时代进程的一项重要策略。
4)应用系统异彩纷呈与上届大会一样,展出内容有:应用工具、应用系统、信息家电等。特别在实时系统开发方面,以IBM为首开发出了应用于工业实时环境的Java嵌入系统,展现出Java在工业领域的广阔应用前景。
Java语言的出现和发展,得到了IT业界的青睐,它像一面大旗,凝聚了世界众多的厂商与Sun公司一道,结成了对抗微软垄断的联盟。许多知名厂商纷纷购买Java许可证,目前已有90多万个软件开发商加入了Java阵营,1亿个Java最终用户,几千种Java应用软件产品,1500余种Java书籍(自Java问世4年来,平均每天出版一本)。这真是IT业界的盛事!IBM公司提出“高举Java大旗,全力以赴”的口号,它在全世界的11个国家有28个实验室,集聚了2500余名技术人员,全天侯24小时进行全方位开发;芯片巨人Intel提出“抓住时机,占领Java阵地”!决心使Intel芯片系统成为开发Java应用运行的最佳平台;Novell则宣称“Java是Novell的未来,未来是服务器端Java的市场”;作为Java发明者的Sun公司,坚持“保卫Java大旗,发展Java之路”的方针,通过对Java的“研究-构造-推广”的过程,从而占领市场。此外,HP、Oracle、Apple、Sybase、Netscape、Informix、3Com、Motorola等公司均是Sun的坚强同盟。
在我国,Java的引进与开发起步早,发展水平基本与世界同步。目前,Sun公司已在中国建成了由5个授权中心、20多个Internet/IntranetJava解决方案中心和10所Java大学、若干培训中心组成的三级结构。全面推动Java在中国的普及、应用、研究、开发,培养了数以十万计的Java开发人员。此外,Sun还牵头成立了中外软件厂商的开发联盟。在中国,Java的开发可以说是“人才济济,成果累累”。如清华大学王克宏教授带领的课题组面向全国,自96年开始举办了多期Java培训班和讲座,开设了数期本科生、研究生Java课程,出版了“Java系列丛书”10余册,承担了国家“九五”攻关项目“基于Java技术的交互式远程教学系统”,并与日本就Java开发进行了国际合作,成绩斐然;东大阿派下属的宝钢东软软件技术研究中心是国内是首屈一指的Java研发骨干企业,该中心从95年起就开始了Java的研发,目前,已掌握了PersonalJava的核心移植技术,并成功地将JVM移植到汽车导航平台。此外,他们还开发出支持Jini协议的即插即用网络打印机软件,以及一套Jini信息家电网络的可视化演示环境,完成了基于JavaBeans的组件化软件开发及运行支持环境等多项成果;在台湾,22家知名计算机公司成立了“Java联盟”,并在台北建立了“Java开发中心”,新竹建立了“Java语言实验室”;在香港,举行了全岛Java杯比赛,掀起了学习Java的热潮。Java的浪潮汹涌澎湃,席卷全球!
2.3 Java标准技术要点
2.3.1 Java的特点
一、Java的跨平台性,即一次编译到处运行
简单地说Java的跨平台性就是指,编译后的Java程序可直接在不同的平台上运行而不用重新编译,这一特性使得Java随着Web应用的普及而迅速普及起来。而Java的跨平台性是如何实现的呢?这就要理解Java虚拟机和字节码的概念。
实际上,编译后的Java代码并不是传统的二进制代码(如Windows下的.exe文件),而是Java字节码,这种字节码文件是不能直接在操作系统上执行的。要想在一个操作系统上运行一个Java程序必须有一个中间环节来负责将Java字节码解释成二进制码,这个中间环节就是Java虚拟机(简称JVM)。由于目前大多数操作系统已经实现了JVM,所以Java轻松实现跨平台性。
二、面向对象技术
Java全面支持面向对象技术,这体现在Class(类)是Java程序构成的基本单元,一个Java程序通常由许多Class组成,而且这些Class还会有一定的继承关系,Java支持Class的单继承,从而使类之间的继承关系更明确。继承的结果产生类的多态性,类的多态本质上讲就是可以用父类的引用访问继承类的实现(子类对象),类的这种多态性最终形成了组件对象模型的基础,即通过接口(父类)访问实现(子类)。
三、Java中的I/O操作
Java中以字节流(InputStream和OutputStream)、字符流(Reader和Writer)来分别读写二进制数据和字符数据,使用非常简单有效。Java类库中的File类不仅提供文件操作而且还包含文件夹操作,如下面这几行代码可以列出C盘根目录下的所有文件:
File f=new File("c://";
String [] m_dir= f.list();
for(int i=0;i
System.out.println(m_dir);
四、Java中的图形及事件处理
可以用awt包或swing包的Java类来进行大部分的Java图形界面设计,下面的几行代码将产生一个200*200像素的窗体:
Frame f=new Frame("Welcome";
f.setSize(200,200);
f.setVisible(true);
默认情况下,Frame窗体的关闭按钮不起作用,这也是Java初学者迷惑的地方。为了使用户按下关闭按钮时能关闭Frame窗体,需要让这个窗体响应一个WindowEvent事件,具体的做法就是给这个窗体添加一个事件监听器对象,这个事件监听器就是WindowListener接口的实现。在上面的代码中插入如下代码就可以关闭窗体:
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
这里用到一个无名内部类,无名内部类是Java中内部类的一种灵活运用方式。
五、Java中线程及同步控制
线程概念的引入是为了实现并行处理,从而提高程序的效率。Java中的线程实现非常简单,可以用两种方式来创建线程,一种是实现Runnable接口,另一种是继承Thread类重写run()方法。两种方式唯一的不同就是前者保留了继承一个类的可能(因为Java只支持类的单继承,但接口没有此限制)。
永远都用start()方法来启动一个线程,线程类中的run()可以被直接调用,但决不是启动一个线程,二者有着本质的区别。
用同步控制关键字synchronized来保护线程敏感数据,synchronized块中的内容可以保证同一时刻只能被一个线程访问,所以其中的数据是线程安全的。
用Object类中的wait()和notify()方法可以实现线程间交互,但要记住wait()和notify()方法只有发生在同一个对象上才能真正实现线程间交互。被某一对象wait()方法阻塞的线程需要另外一个调用了同一对象notify()的线程干预才能恢复运行。notify()方法一次唤醒一个被wait()方法阻塞的线程,notifyAll()方法可以一次唤醒所有被wait()方法阻塞的线程。
六、Java本地方法(native方法)的实现
Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。
可以将native方法比作Java程序同C程序的接口,其实现步骤:
1、在Java中声明native()方法,然后编译;
2、用javah产生一个.h文件;
3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件 (注意其中又包含了JDK带的jni.h文件);
4、将第三步的.cpp文件编译成动态链接库文件;
5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。
2.3.2 Java的应用
上述所提及的一些Java技术具有一定的普遍性,它们基本上是在Java各个方面的运用中都需要掌握的技术。实际上Java的运用非常广泛,而且每个方面都需要遵循不同的规范。以下是对Java应用的简要介绍。
(一)理解Java SDK的三个版本:
Java SDK Micro Edition (J2ME)
用于开发掌上电脑、手机等移动通信设备上使用的应用程序。并不是所有的移动设备都支持Java,只有具备J2ME运行环境(JVM+J2ME API)的设备才能运行Java程序。J2ME的集成开发工具(通常都有带有一些仿真器)有 Sun 的J2ME Wireless Toolkit 、IBM的Visul Age Micro Edition 等。
Java SDK Standard Edition(J2SE)
主要用于开发一般台式机应用程序。我们平时所说的JDK就指J2SE,而我们学Java就是从学习J2SE开始的。
Java SDK Enterprise Edition (J2EE)
用于开发分布式的企业级大型应用程序。其中的核心是Entetprise Java Beans(EJB,分布式Java组件)的开发。
(二)Java小程序 (Applet)
Java小程序是一个继承了Applet类并重写了init()、paint()、stop()等方法的的Java类,它被布署在Web服务器(如IIS)上,当客户端请求Web页时,浏览器从Web服务器上将其下载到本地客户端,然后,浏览器创建该Applet类的实例并调用其init()方法,从安全角度考虑,Applet没有访问本地文件的权限。由于Applet是被浏览器执行的,所以Applet不需要一个main()方法。实际上,除了Java Application之外,所有其它Java应用都不需要一个main()方法。
(三)服务器端Java小程序 (Servlet)
Servlet也是一个Java类,和Applet形成对比,Servlet是运行于服务器端的Java小程序,而且Servlet需要一个单独的Web服务器(如Tomcat)做容器。除此之外,Servlet中用到的一些类(如HttpServlet)并不包含在J2SE API中,所以需要将Servlet.jar(在Tomcat的commonlib文件夹下)加到环境变量中去。下面是一个简单的Servlet例子:
public class Myservlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response)
{
try{
response.setContentType("text/html";
PrintWriter out=response.getWriter();
out.println("");
out.println("");
out.println("Hello world");
out.println("");
out.println("");
}catch(IOException e){}
}
}
将这个Class文件编译后放至TomcatwebappsexamplesWEB-INFclasses下,然后在浏览器地址栏里输入http://127.0.0.1:8080/examples/servlet/Myservlet即可看到 Hello world出现在浏览器中。
(四)Java Server Page (JSP)
同Servlet相似的是,JSP运行于Web服务器端,并且也需要Tomcat之类的容器。不同的是,由于JSP是将Java代码嵌在html标记里(同ASP一样用),JSP的界面设计同后台开发人员的工作可以有效分离。可以想像让开发人员用Servlet写一个花捎的Web页面有多困难,所以JSP+Servlet混合Web应用是比较理想的选择。
看起来JSP同ASP的实现机制大同小异,其实也存在着本质的区别。所有的ASP页面都是解释运行的,而JSP页在第一次被请求时会被编译,再以后的客户请求都是直接运行服务器上的.class文件(在Tomcat的Work文件夹下),所以JSP要比ASP速度上快许多。
(五)Java Beans
Java Bean 是可复用的组件,对Java Bean并没有严格的规范,理论上讲,任何一个Java类都可以是一个Bean。但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。
(六)Enterprise Java Beans (EJB)
Java Bean实际上相当于微软COM模型中的本地进程内COM组件,它是不能被跨进程访问的。Enterprise Java Bean 相当于DCOM,即分布式组件。它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是EJB组件的代理,EJB组件由容器所创建和管理。客户通过容器来访问真正的EJB组件。
这种模型很像COM+管理器,其实EJB容器正是起到COM+管理器的作用,只是EJB组件相对COM组件来说更易用、更安全。
总的说来,Java作为面向对象技术的一个代表,在当今商业应用中更容易开发出高效的、多层的分布式应用程序,而且,由于Java技术有很强的健壮性和易用性,加上同UML应用的结合,开发一个商业应用软件的周期会大大缩短,所以Java会有不错的前景。
第3章 JavaMail API技术研究
3.1 JavaMail API简介
JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Agent,简称MUA)。而不是像sendmail或者其它的邮件传输代理(Mail Transfer Agent,简称MTA)程序那样可以传送、递送、转发邮件。从另外一个角度来看,我们这些电子邮件用户日常用MUA程序来读写邮件,而MUA依赖着MTA处理邮件的递送。
JavaMail API被设计用于以不依赖协议的方式去发送和接收电子信息,这个API被分为两大部分:基本功能:如何以不依赖于协议的方式发送接收电子信息,不过这只是一厢情愿而已。第二个部分则是依赖特定协议的,比如SMTP、POP、IMAP、NNTP协议。
3.2相关协议一览
在正式了解JavaMail API之前,先看一下API所涉及的协议。以下便是大家日常所知、所乐于使用的4大信息传输协议:SMTP、POP、IMAP、MIME。
当然,上面的4个协议,并不是全部,还有NNTP和其它一些协议可用于传输信息,但是不常用到。理解这4个基本的协议有助于更好的使用JavaMail API。然而JavaMail API是被设计为与协议无关的,目前并不能克服这些协议的束缚。确切的说,如果使用的功能并不被选择的协议支持,那么JavaMail API并不可能实现这种能力。
1. SMTP
简单邮件传输协议定义了递送邮件的机制。在下文中,将使用基于Java-Mail的程序与公司或者ISP的SMTP服务器进行通讯。这个SMTP服务器将邮件转发到接收者的SMTP服务器,直至最后被接收者通过POP或者IMAP协议获取。这并不需要SMTP服务器使用支持授权的邮件转发,但是却的确要注意SMTP服务器的正确设置(SMTP服务器的设置与JavaMail API无关)。
2. POP
POP是一种邮局协议,目前为第3个版本,即众所周知的POP3。POP定义了一种用户如何获得邮件的机制。它规定了每个用户使用一个单独的邮箱。大多数人在使用POP时所熟悉的功能并非都被支持,例如查看邮箱中的新邮件数量。而这个功能是微软的Outlook内建的,那么就说明微软Outlook之类的邮件客户端软件是通过查询最近收到的邮件来计算新邮件的数量来实现前面所说的功能。因此在使用JavaMail API时需要注意,当需要获得如前面所讲的新邮件数量之类的信息时,不得不自己进行计算。
3. IMAP
IMAP使用在接收信息的高级协议,目前版本为第4版,所以也被称为IMAP4。需要注意的是在使用IMAP时,邮件服务器必须支持该协议。从这个方面讲,并不能完全使用IMAP来替代POP,不能期待IMAP在任何地方都被支持。假如邮件服务器支持IMAP,那么邮件程序将能够具有以下被IMAP所支持的特性:每个用户在服务器上可具有多个目录,这些目录能在多个用户之间共享。
其与POP相比高级之处显而易见,但是在尝试采取IMAP时,认识到它并不是十分完美的:由于IMAP需要从其它服务器上接收新信息,将这些信息递送给用户,维护每个用户的多个目录,这都为邮件服务器带来了高负载。并且IMAP与POP的一个不同之处是POP用户在接收邮件时将从邮件服务器上下载邮件,而IMAP允许用户直接访问邮件目录,所以在邮件服务器进行备份作业时,由于每个长期使用此邮件系统的用户所用的邮件目录会占有很大的空间,这将直接导致邮件服务器上磁盘空间暴涨。
4. MIME
MIME并不是用于传送邮件的协议,它作为多用途邮件的扩展定义了邮件内容的格式:信息格式、附件格式等等。一些RFC标准都涉及了MIME:RFC 822, RFC 2045, RFC 2046, RFC 2047。作为JavaMail API的开发者,并不需关心这些格式定义,但是这些格式被用在了程序中。
5. NNTP和其它的第三方协议
正因为JavaMail API在设计时考虑到与第三方协议实现提供商之间的分离,故可以很容易的添加一些第三方协议。SUN维护着一个第三方协议实现提供商的列表:http://java.sun.com/products/javamail/Third_Party.html,通过此列表可以找到所需要的而又不被SUN提供支持的第三方协议:比如NNTP这个新闻组协议和S/MIME这个安全的MIME协议。
3.3初次认识JavaMail API
A.纵览JavaMail核心类结构
打开JavaMail.jar文件,将发现在javax.mail的包下面存在着一些核心类:Session、Message、Address、Authenticator、Transport、Store、Folder。而且在javax.mail.internet包中还有一些常用的子类。
B.Session
Session类定义了基本的邮件会话。就像Http会话那样,进行收发邮件的工作都是基于这个会话的。Session对象利用了java.util.Properties对象获得了邮件服务器、用户名、密码信息和整个应用程序都要使用到的共享信息。
Session类的构造方法是私有的,所以可以使用Session类提供的getDefaultInstance()这个静态工厂方法获得一个默认的Session对象:
Properties props = new Properties();
// fill props with any information
Session session = Session.getDefaultInstance(props, null);
或者使用getInstance()这个静态工厂方法获得自定义的Session:
Properties props = new Properties();
// fill props with any information
Session session = Session.getInstance(props, null);
从上面的两个例子中不难发现,getDefaultInstance()和getInstance()方法的第二个参数都是null,这是因为在上面的例子中并没有使用到邮件授权,下文中将对授权进行详细介绍。
从很多的实例看,在对mail server进行访问的过程中使用共享的Session是足够的,即使是工作在多个用户邮箱的模式下也不例外。
C.Message
当我们建立了Session对象后,便可以构造被发送的信息体了。在这里SUN提供了Message类型来帮助开发者完成这项工作。由于Message是一个抽象类,大多数情况下,使用javax.mail.internet.MimeMessage这个子类,该类是使用MIME类型、MIME信息头的邮箱信息。信息头只能使用US-ASCII字符,而非ASCII字符将通过编码转换为ASCII的方式使用。
为了建立一个MimeMessage对象,必须将Session对象作为MimeMessage构造方法的参数传入:
MimeMessage message = new MimeMessage(session);
注意:对于MimeMessage类来讲存在着多种构造方法,比如使用输入流作为参数的构造方法。
在建立了MimeMessage对象后,需要设置它的各个part,对于MimeMessage类来说,这些part就是MimePart接口。最基本的设置信息内容的方法就是通过表示信息内容和什么类型的参数调用setContent()方法:
message.setContent("Hello", "text/plain");
然而,如果所使用的MimeMessage中信息内容是文本的话,便可以直接使用setText()方法来方便的设置文本内容。
message.setText("Hello");
前面所讲的两种方法,对于文本信息,后者更为合适。而对于其它的一些信息类型,比如HTML信息,则要使用前者。
使用setSubject()方法对邮件设置邮件主题:
message.setSubject("First");
D.Address
到这里,已经建立了Session和Message,下面将介绍如何使用邮件地址类:Address。像Message一样,Address类也是一个抽象类,所以将使用javax.mail.internet.InternetAddress这个子类。
通过传入代表邮件地址的字符串,可以建立一个邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov");
如果要在邮件地址后面增加名字的话,可以通过传递两个参数:代表邮件地址和名字的字符串来建立一个具有邮件地址和名字的邮件地址类:
Address address = new InternetAddress("president@whitehouse.gov", "George Bush");
这里所讲的邮件地址类是为了设置邮件信息的发信人和收信人而准备的,在建立了邮件地址类后,通过message的setFrom()和setReplyTo()两种方法设置邮件的发信人:
message.setFrom(address);
message.setReplyTo(address);
若在邮件中存在多个发信人地址,可用addForm()方法增加发信人:
Address address[] = ...;
message.addFrom(address);
为了设置收信人,使用addRecipient()方法增加收信人,此方法需要使用Message.RecipientType的常量来区分收信人的类型:
message.addRecipient(type, address)
下面是Message.RecipientType的三个常量:
Message.RecipientType.TO
Message.RecipientType.CC
Message.RecipientType.BCC
因此,如果要发送邮件给总统,并发用一个副本给第一夫人的话,下面的方法将被用到:
Address toAddress = new InternetAddress("vice.president@whitehouse.gov");
Address ccAddress = new InternetAddress("first.lady@whitehouse.gov");
message.addRecipient(Message.RecipientType.TO, toAddress);
message.addRecipient(Message.RecipientType.CC, ccAddress);
JavaMail API并没有提供检查邮件地址有效性的机制。当然我们可以自己完成这个功能:验证邮件地址的字符是否按照RFC822规定的格式书写或者通过DNS服务器上的MX记录验证等。
E.Authenticator
像java.net类那样,JavaMail API通过使用授权者类(Authenticator)以用户名、密码的方式访问那些受到保护的资源,在这里“资源”就是指邮件服务器。在javax.mail包中可以找到这个JavaMail的授权者类(Authenticator)。 在使用Authenticator这个抽象类时,我们必须采用继承该抽象类的方式,并且该继承类必须具有返回PasswordAuthentication对象(用于存储认证时要用到的用户名、密码)getPasswordAuthentication()方法。并且要在Session中进行注册,使Session能够了解在认证时该使用哪个类。
下面代码片断中的MyAuthenticator就是一个Authenticator的子类。
Properties props = new Properties();
// fill props with any information
Authenticator auth = new MyAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
F.Transport
在发送信息时,Transport类将被用到。这个类实现了发送信息的协议(通称为SMTP),此类是一个抽象类,我们可以使用这个类的静态方法send()来发送消息:
Transport.send(message);
当然,方法是多样的。我们也可由Session获得相应协议对应的Transport实例。并通过传递用户名、密码、邮件服务器主机名等参数建立与邮件服务器的连接,并使用sendMessage()方法将信息发送,最后关闭连接:
message.saveChanges(); // implicit with send()
Transport transport = session.getTransport("smtp");
transport.connect(host, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
评论:上面的方法是一个很好的方法,尤其是在我们在同一个邮件服务器上发送多个邮件时。因为这时我们将在连接邮件服务器后连续发送邮件,然后再关闭掉连接。send()这个基本的方法是在每次调用时进行与邮件服务器的连接的,对于在同一个邮件服务器上发送多个邮件来讲可谓低效的方式。
注意:如果需要在发送邮件过程中监控mail命令的话,可以在发送前设置debug标志:
session.setDebug(true)。
G.Store和Folder
接收邮件和发送邮件很类似都要用到Session。但是在获得Session后,我们需要从Session中获取特定类型的Store,然后连接到Store,这里的Store代表了存储邮件的邮件服务器。在连接Store的过程中,极有可能需要用到用户名、密码或者Authenticator。
// Store store = session.getStore("imap");
Store store = session.getStore("pop3");
store.connect(host, username, password);
在连接到Store后,一个Folder对象即目录对象将通过Store的getFolder()方法被返回,我们可从这个Folder中读取邮件信息:
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
Message message[] = folder.getMessages();
上面的例子首先从Store中获得INBOX这个Folder(对于POP3协议只有一个名为INBOX的Folder有效),然后以只读(Folder.READ_ONLY)的方式打开Folder,最后调用Folder的getMessages()方法得到目录中所有Message的数组。
注意:对于POP3协议只有一个名为INBOX的Folder有效,而对于IMAP协议,我们可以访问多个Folder(想想前面讲的IMAP协议)。而且SUN在设计Folder的getMessages()方法时采取了很智能的方式:首先接收新邮件列表,然后再需要的时候(比如读取邮件内容)才从邮件服务器读取邮件内容。
在读取邮件时,我们可以用Message类的getContent()方法接收邮件或是writeTo()方法将邮件保存,getContent()方法只接收邮件内容(不包含邮件头),而writeTo()方法将包括邮件头。
System.out.println(((MimeMessage)message).getContent());
在读取邮件内容后,别忘记了关闭Folder和Store。
folder.close(aBoolean);
store.close();
传递给Folder.close()方法的boolean 类型参数表示是否在删除操作邮件后更新Folder。
3.4 使用JavaMail API
3.4.1 发送邮件
在获得了Session后,建立并填入邮件信息,然后发送它到邮件服务器。这便是使用Java Mail API发送邮件的过程,在发送邮件之前,需要设置SMTP服务器:通过设置Properties的mail.smtp.host属性。
String host = ...;
String from = ...;
String to = ...;
// Get system properties
Properties props = System.getProperties();
// Setup mail server
props.put("mail.smtp.host", host);
// Get session
Session session = Session.getDefaultInstance(props, null);
// Define message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail");
message.setText("Welcome to JavaMail");
// Send message
Transport.send(message);
由于建立邮件信息和发送邮件的过程中可能会抛出异常,所以需要将上面的代码放入到try-catch结构块中。
3.4.2 接收邮件
为了读取邮件,获得session,并且连接到了邮箱的相应store,打开相应的Folder,然后得到想要的邮件,当然别忘记了在结束时关闭连接。
String host = ...;
String username = ...;
String password = ...;
// Create empty properties
Properties props = new Properties();
// Get session
Session session = Session.getDefaultInstance(props, null);
// Get the store
Store store = session.getStore("pop3");
store.connect(host, username, password);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": " + message[i].getFrom()[0]
+ " " + message[i].getSubject());
}
// Close connection
folder.close(false);
store.close();
上面的代码所作的是从邮箱中读取每个邮件,并且显示邮件的发信人地址和主题。从技术角度讲,这里存在着一个异常的可能:当发信人地址为空时,getFrom()[0]将抛出异常。
下面的代码片断有效的说明了如何读取邮件内容,在显示每个邮件发信人和主题后,将出现用户提示从而得到用户是否读取该邮件的确认,如果输入YES的话,可用Message.writeTo(java.io.OutputStream os)方法将邮件内容输出到控制台上。
BufferedReader reader = new BufferedReader (
new InputStreamReader(System.in));
// Get directory
Message message[] = folder.getMessages();
for (int i=0, n=message.length; i<n; i++) {
System.out.println(i + ": " + message[i].getFrom()[0]
+ " " + message[i].getSubject());
System.out.println("Do you want to read message? " +
"[YES to read/QUIT to end]");
String line = reader.readLine();
if ("YES".equals(line)) {
message[i].writeTo(System.out);
} else if ("QUIT".equals(line)) {
break;
}
}
3.4.3删除邮件和标志
设置与message相关的Flags是删除邮件的常用方法。这些Flags表示了一些系统定义和用户定义的不同状态。在Flags类的内部类Flag中预定义了一些标志:
Flags.Flag.ANSWERED
Flags.Flag.DELETED
Flags.Flag.DRAFT
Flags.Flag.FLAGGED
Flags.Flag.RECENT
Flags.Flag.SEEN
Flags.Flag.USER
但需要在使用时注意的:标志存在并非意味着这个标志被所有的邮件服务器所支持。例如,对于删除邮件的操作,POP协议不支持上面的任何一个。所以要确定哪些标志是被支持的——通过访问一个已经打开的Folder对象的getPermanetFlags()方法,它将返回当前被支持的Flags类对象。
删除邮件时,可以设置邮件的DELETED标志:
message.setFlag(Flags.Flag.DELETED, true);
但是首先要采用READ_WRITE的方式打开Folder:
folder.open(Folder.READ_WRITE);
在对邮件进行删除操作后关闭Folder时,需要传递一个true作为对删除邮件的擦除确认。
folder.close(true);
Folder类中另一种用于删除邮件的方法expunge()也同样可删除邮件,但是它并不为sun提供的POP3实现支持,而其它第三方提供的POP3实现支持或者并不支持这种方法。
另外,介绍一种检查某个标志是否被设置的方法:Message.isSet(Flags.Flag flag)方法,其中参数为被检查的标志。
3.4.4 邮件认证
前面已经介绍了如何使用Authenticator类来代替直接使用用户名和密码这两字符串作为Session.getDefaultInstance()或者Session.getInstance()方法的参数,现在将全面认识一下邮件认证。
在此取代了直接使用邮件服务器主机名、用户名、密码这三个字符串作为连接到POP3 Store的方式,使用存储了邮件服务器主机名信息的属性文件,并在获得Session时传入自定义的Authenticator实例:
// Setup properties
Properties props = System.getProperties();
props.put("mail.pop3.host", host);
// Setup authentication, get session
Authenticator auth = new PopupAuthenticator();
Session session = Session.getDefaultInstance(props, auth);
// Get the store
Store store = session.getStore("pop3");
store.connect();
PopupAuthenticator类继承了抽象类Authenticator,并且通过重载Authenticator类的getPasswordAuthentication()方法返回PasswordAuthentication类对象。而getPasswordAuthentication()方法的参数param是以逗号分割的用户名、密码组成的字符串。
import javax.mail.*;
import java.util.*;
public class PopupAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication(String param) {
String username, password;
StringTokenizer st = new StringTokenizer(param, ",");
username = st.nextToken();
password = st.nextToken();
return new PasswordAuthentication(username, password);
}
}
3.4.5 回复邮件
回复邮件的方法很简单:使用Message类的reply()方法,通过配置回复邮件的收件人地址和主题(如果没有提供主题的话,系统将默认将“Re:”作为邮件的主体),这里不需要设置任何的邮件内容,只要复制发信人或者reply-to到新的收件人。而reply()方法中的boolean参数表示是否将邮件回复给发送者(参数值为false),或是回复给所有人(参数值为true)。
补充一下,reply-to地址需要在发信时使用setReplyTo()方法设置。
MimeMessage reply = (MimeMessage)message.reply(false);
reply.setFrom(new InternetAddress("president@whitehouse.gov"));
reply.setText("Thanks");
Transport.send(reply);
3.4.6 转发邮件
转发邮件的过程不如前面的回复邮件那样简单,它将建立一个转发邮件,这并非一个方法就能做到。每个邮件是由多个部分组成,每个部分称为一个邮件体部分,是一个BodyPart类对象,对于MIME类型邮件来讲就是MimeBodyPart类对象。这些邮件体包含在成为Multipart的容器中对于MIME类型邮件来讲就是MimeMultiPart类对象。在转发邮件时,建立一个文字邮件体部分和一个被转发的文字邮件体部分,然后将这两个邮件体放到一个Multipart中。说明一下,复制一个邮件内容到另一个邮件的方法是仅复制它的DataHandler(数据处理者)即可。这是由JavaBeans Activation Framework定义的一个类,它提供了对邮件内容的操作命令的访问、管理了邮件内容操作,是不同的数据源和数据格式之间的一致性接口。
// Create the message to forward
Message forward = new MimeMessage(session);
// Fill in header
forward.setSubject("Fwd: " + message.getSubject());
forward.setFrom(new InternetAddress(from));
forward.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(
"Here you go with the original message:
");
// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Create and fill part for the forwarded content
messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(message.getDataHandler());
// Add part to multi part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
forward.setContent(multipart);
// Send message
Transport.send(forward);
3.4.7 使用附件
附件作为与邮件相关的资源经常以文本、表格、图片等格式出现,如流行的邮件客户端一样,可以用JavaMail API从邮件中获取附件或是发送带有附件的邮件。
发送带有附件的邮件
发送带有附件的邮件的过程有些类似转发邮件,需要建立一个完整邮件的各个邮件体部分,在第一个部分(即邮件内容文字)后,增加一个具有DataHandler的附件而不是在转发邮件时那样复制第一个部分的DataHandler。
如果将文件作为附件发送,那么要建立FileDataSource类型的对象作为附件数据源;如果从URL读取数据作为附件发送,那么将要建立URLDataSource类型的对象作为附件数据源。
然后将这个数据源(FileDataSource或是URLDataSource)对象作为DataHandler类构造方法的参数传入,从而建立一个DataHandler对象作为数据源的DataHandler。
接着将这个DataHandler设置为邮件体部分的DataHandler。这样就完成了邮件体与附件之间的关联工作,下面的工作就是BodyPart的setFileName()方法设置附件名为原文件名。
最后将两个邮件体放入到Multipart中,设置邮件内容为这个容器Multipart,发送邮件。
// Define message
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject("Hello JavaMail Attachment");
// Create the message part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText("Pardon Ideas");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
// Put parts in message
message.setContent(multipart);
// Send the message
Transport.send(message);
如果使用servlet实现发送带有附件的邮件,则必须上传附件给servlet,这时需要注意提交页面form中对编码类型的设置应为multipart/form-data。
<FORM ENCTYPE="multipart/form-data"
method=post action="/myservlet">
<INPUT TYPE="file" NAME="thefile">
<INPUT TYPE="submit" VALUE="Upload">
</FORM>
读取邮件中的附件
读取邮件中的附件的过程要比发送它的过程复杂一点。因为带有附件的邮件是多部分组成的,必须处理每一个部分获得邮件的内容和附件。
但是如何辨别邮件信息内容和附件呢?Sun在Part类(BodyPart类实现的接口类)中提供了getDisposition()方法让开发者获得邮件体部分的部署类型,当该部分是附件时,其返回之将是Part.ATTACHMENT。但附件也可以没有部署类型的方式存在或者部署类型为Part.INLINE,无论部署类型为Part.ATTACHMENT还是Part.INLINE,都能把该邮件体部分导出保存。
Multipart mp = (Multipart)message.getContent();
for (int i=0, n=multipart.getCount(); i<n; i++) {
Part part = multipart.getBodyPart(i));
String disposition = part.getDisposition();
if ((disposition != null) &&
((disposition.equals(Part.ATTACHMENT) ||
(disposition.equals(Part.INLINE))) {
saveFile(part.getFileName(), part.getInputStream());
}
}
下列代码中使用了saveFile方法是自定义的方法,它根据附件的文件名建立一个文件,如果本地磁盘上存在名为附件的文件,那么将在文件名后增加数字表示区别。然后从邮件体中读取数据写入到本地文件中(代码省略)。
// from saveFile()
File file = new File(filename);
for (int i=0; file.exists(); i++) {
file = new File(filename+i);
}
以上是邮件体部分被正确设置的简单例子,如果邮件体部分的部署类型为null,那么通过获得邮件体部分的MIME类型来判断其类型作相应的处理,代码结构框架如下:
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
// Handle plain
} else {
// Special non-attachment cases here of
// image/gif, text/html, ...
}
...
}
3.4.8 处理HTML邮件
前面的例子中发送的邮件都是以文本为内容的(除了附件),下面将介绍如何接收和发送基于HTML的邮件。
发送HTML邮件
假如需要发送一个HTML文件作为邮件内容,并使邮件客户端在读取邮件时获取相关的图片或者文字的话,只要设置邮件内容为html代码,并设置内容类型为text/html即可:
String htmlText = "<H1>Hello</H1>" +
"<img src="http://www.jguru.com/images/logo.gif">";
message.setContent(htmlText, "text/html"));
请注意:这里的图片并不是在邮件中内嵌的,而是在URL中定义的。邮件接收者只有在线时才能看到。
在接收邮件时,如果使用JavaMail API接收邮件的话是无法实现以HTML方式显示邮件内容的。因为JavaMail API邮件内容视为二进制流。所以要显示HTML内容的邮件,必须使用JEditorPane或者第三方HTML展现组件。
以下代码显示了如何使用JEditorPane显示邮件内容:
if (message.getContentType().equals("text/html")) {
String content = (String)message.getContent();
JFrame frame = new JFrame();
JEditorPane text = new JEditorPane("text/html", content);
text.setEditable(false);
JScrollPane pane = new JScrollPane(text);
frame.getContentPane().add(pane);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.show();
}
在邮件中包含图片
如果在邮件中使用HTML作为内容,那么最好将HTML中使用的图片作为邮件的一部分,这样无论是否在线都会正确的显示HTML中的图片。处理方法就是将HTML中用到的图片作为邮件附件并使用特殊的cid URL作为图片的引用,这个cid就是对图片附件的Content-ID头的引用。
处理内嵌图片就像向邮件中添加附件一样,不同之处在于必须通过设置图片附件所在的邮件体部分的header中Content-ID为一个随机字符串,并在HTML中img的src标记中设置为该字符串。这样就完成了图片附件与HTML的关联。
String file = ...;
// Create the message
Message message = new MimeMessage(session);
// Fill its headers
message.setSubject("Embedded Image");
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// Create your new message part
BodyPart messageBodyPart = new MimeBodyPart();
String htmlText = "<H1>Hello</H1>" +
"<img src="cid:memememe">";
messageBodyPart.setContent(htmlText, "text/html");
// Create a related multi-part to combine the parts
MimeMultipart multipart = new MimeMultipart("related");
multipart.addBodyPart(messageBodyPart);
// Create part for the image
messageBodyPart = new MimeBodyPart();
// Fetch the image and associate to part
DataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID","<memememe>");
// Add part to multi-part
multipart.addBodyPart(messageBodyPart);
// Associate multi-part with message
message.setContent(multipart);
3.4.9 在邮件中搜索短语
JavaMail API提供了过滤器机制,它被用来建立搜索短语。这个短语由javax.mail.search包中的SearchTerm抽象类来定义,在定义后便可以使用Folder的Search()方法在Folder中查找邮件:
SearchTerm st = ...;
Message[] msgs = folder.search(st);
下面有22个不同的类(继承了SearchTerm类)供使用:
AND terms (class AndTerm)
OR terms (class OrTerm)
NOT terms (class NotTerm)
SENT DATE terms (class SentDateTerm)
CONTENT terms (class BodyTerm)
HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
使用这些类定义的断语集合,可以构造一个逻辑表达式,并在Folder中进行搜索。下面是一个实例:在Folder中搜索邮件主题含有“ADV”字符串或者发信人地址为friend@public.com的邮件。
SearchTerm st =
new OrTerm(
new SubjectTerm("ADV:"),
new FromStringTerm("friend@public.com"));
Message[] msgs = folder.search(st);
第4章 邮件客户端的设计和实现
4.1 需求分析
实时通信的电话有两个严重缺点:第一,电话通信的主叫和被叫双方必须同时在场;第二,一些不是十分紧迫的电话也常常不必要地打断人们的工作或休息。
电子邮件(e-mail)是因特网上使用得最多的和最受用户欢迎的一种应用。电子邮件将邮件发送到ISP的邮件服务器,并放在其中的收信人邮箱(mail box)中,收信人可随时上网到ISP的邮件服务器进行读取。上述的性质相当于利用因特网为用户建立了存放邮件的信箱,因此e-mail有时也称为“电子信箱”。电子邮件不仅使用方便,而且还具有传递迅速和费用低廉的优点。据有的公司报道,使用电子邮件后可提高劳动生产率30%以上。现在电子邮件不仅可传递文字信息,而且还可附上声音和图像。
本设计是基于Java的邮件客户端,是一个实现电子邮件收、发功能的应用程序,可直接安装于PC机上执行,无需进行任何配置,只要在相应位置输入用户名和密码,即可享受电子通信的便捷,功能与OutLook Express、FoxMail等专业邮件客户端相仿。之所以使用Java语言开发,是因为其跨平台性及面向对象设计等优点,便于开发及使用。
4.2 概要设计
电子邮件的主要组成构件如图4-1所示:
图4-1 电子邮件主要组成构件
用户代理就是用户与电子邮件系统的接口,大多情况下就是在用户PC机中运行的程序,也就是本设计的邮件客户端。
4.2.1 邮件客户端基本功能
(1) 撰写,给用户提供很方便地编辑信件的环境。例如,应让用户能共创建便于使用的通讯录(有常用的人名和地址)。回信时不仅能方便地从来信中提取出对方地址,并自动地将此地址写入到邮件中合适的位置,而且还能方便地对来信提出的问题进行答复(系统自动将来信复制一份在用户撰写回信的窗口中,因而用户不需要再输入来信中的问题)
(2)显示,能方便地在计算机屏幕上显示出来信(包括来信附上的声音和图像)。
(3)处理,处理包括发送邮件和接收邮件。收信人应能根据情况按不同方式对来信进行处理。例如,阅读后删除、存盘、打印、转发等,以及自建目录对来信进行分类保存。有时还可在读取信件之前先查看一下邮件的发信人和长度,对于不愿收的信件可直接在邮箱中删除。
4.2.2 电子邮件传输过程
邮件服务器是电子邮件系统的核心构件,因特网上所有的ISP都有邮件服务器。邮件服务器的功能是发送和接收邮件,同时还要向发信人报告邮件传送的情况(已交付、被拒绝、丢失等)。邮件服务器按照客户服务器方式工作。邮件服务器需要使用两个不同的协议。一个协议用于发送邮件,即SMTP协议,而另一个协议用于接收邮件,即邮局协议POP(Post Office Protocol)。
下面是一封电子邮件的发送和接收工程(结合图5-1)。
(1)发信人调用用户代理编辑要发送的邮件,用户代理用SMTP将邮件传送给发送端服务器;
(2)发送端邮件服务器把邮件收入邮件缓存队列中,等待发送;
(3)运行在发送端邮件服务器的SMTP客户进程,发现在邮件缓存中有待发送的邮件,就向运行在接收端邮件服务器的SMTP服务器进程发起TCP连接的建立;
(4)当TCP连接建立后,SMTP客户进程开始向远程的SMTP服务器进程发送邮件,如果有多个邮件在邮件缓存中,则SMTP客户一一把它们发送到远程的SMTP服务器,当所有的待发送邮件发完了,SMTP就关闭所建立的TCP连接;
(5)运行在接收端邮件服务器中的SMTP服务器进程收到邮件后,把邮件放入收信人的用户邮箱中,等待收信人在他方便时进行读取;
(6)收信人在打算收信时,调用用户代理,使用POP3 (或IMAP)协议把自己的邮件从接收端邮件服务器的用户邮件箱中取回(如果邮箱中有来信的话)。
4.2.3 邮件客户端设计概要
本设计之邮件客户端由一树形结构构成主界面,内含收件箱、发件箱、草稿箱和垃圾箱,彼此间之关联如图4-2所示:
在邮件系统主界面输入登录名和密码,登陆成功后,可看到树形结构的收件箱、发件箱、草稿箱和垃圾箱。
收件箱主要通过POP3协议来接收、查看邮件,并可存储发件人地址到通讯录,对无需保存的邮件可直接删除,发到垃圾箱,对需要回复的邮件则转到发件箱发送邮件;
发件箱则通过SMTP协议发送邮件,可以从通讯录中查找收件人或自己输入收件人以及直接回复邮件,发送时也可将新输入的收信人地址存入通讯录,对发送后的邮件,有需要保留的,可存草稿到草稿箱;
草稿箱主要用来编辑不待立即发送的邮件和发件时的草稿,也可对保存的已发邮件进行修改后或不需任何更改直接发送,转到发件箱,对无保存需要的草稿可进行删除,转到垃圾箱;
垃圾箱主要用来存放无用的、被删除的邮件,可再次删除确无价值的邮件,执行彻底删除,也可对误删或仍有用的邮件进行还原,转到邮件的先前存放处。
图4-2 邮件客户端结构图
4.3 详细设计
由于本设计是基于Java的,所以先要安装Java环境——JDK;安装好JDK后,要对环境变量进行配置,否则系统无法识别或经常报错;接着就要安装配置具体用到的开发环境JBuilder 9,在它的帮助下,程序的以较为方便的开发。前期工作准备完毕,就是具体、详细的设计过程,其中包括了各部分的结构图、流程图及UML框图。各部分内容分别介绍如下:
4.3.1 JDK的安装
下面使用图解的形式进行JDK安装的演示,使大家有个较为直观的认识。
1) 先在网上下载好源文件,然后安装,点击“Next”,如图4-3;
2) 选择安装或删除(对已安装用户来说),点击“Next”,如图4-4;
3) 选择安装内容,点击“Next”,如图4-5;
4) 安装完成,点击“Finish”,如图4-6。
图4-3 JDK安装第1步
图4-4 JDK安装第2步
图4-5 JDK安装第3步
图4-6 JDK安装第4步
4.3.2 环境变量配置
1. 设置环境变量
环境变量是包含诸如驱动器、路径或文件名之类的字符串。它们控制着多种程序的行为。例如,TEMP 环境变量指定程序放置临时文件的位置。
任何用户都可以添加、修改或删除用户的环境变量。但是,只有管理员才能添加、修改或删除系统环境变量。
JDK中的javac是进行编译java源程序的,其实可以在dos下通过把路径改到jdk的BIN目录下执行或者是在编译时就带上这些路径,但是经常这样肯定是很麻烦的。于是可以通过path来设置这个路径,这样每次进行编译时系统就能自动来寻找这个目录即“path=x:……jdkin”,这样只要是在bin目录下的任何命令就可以直接在dos下执行,这样设置后就可以通过javac命令来编译程序了(前提是程序没错),接着就是通过java来执行已经经过编译得到的class文件,这是可能也会有问题就是提示不能发现类之类的错误,这就和classpath有关系了,classpath是来寻找class文件的如果没有设置这个变量直接通过java来运行程序就会出现这个问题,这时也可通过上面所说的把路径改到jdk的lib下,但是显然也很不方便,通过classpath也能解决这个问题即“classpath=x:……jdklib ools.jar;.”,注意后面的分号是来分隔路径的“.”是指的当前路径,为什么要指明当前路径呢,因为分号前面的是jdk的公共类库所在路径,而我们的程序总会用自己的类,所以程序得到的类存放的当前路径也要放在里面。
2. 添加或更改环境变量的数值
1) 在“控制面板”中打开“系统”,如图4-7;
图4-7 配置环境变量第1步
2)在“系统属性”中打开“高级”,如图4-8;
图4-8 配置环境变量第2步
3) 在“高级”选项卡上单击“环境变量”,如图4-9;
图4-9 配置环境变量第3步
(4)在“环境变量”卡中的“系统变量”单击“新建”并输入变量名:Path和变量值: D:j2sdk1.4.2_05in;%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32Wbem,然后点击“确定”,如图4-10。
图4-10 配置环境变量第4步
注意:
l 如果不是以管理员身份登录到本地计算机,则唯一能更改的环境变量是用户变量。
l 要打开“系统”,请依次单击“开始”、“控制面板”、“性能和维护”,然后单击“系统”。
l Windows 将更改保存在注册表中,从而下次启动计算机时这些更改将自动生效。
l 可能需要关闭正在运行的程序然后重新将其打开,新设置才能生效。
4.3.3 JBuilder的安装配置
1、Jbuilder 9的软硬件系统需求
在Windows平台上,JBuilder 9的系统需求如下:
(1)最少256MB内存(recommended minimum)、推荐512MB(recommended)。根据经验,256MB内存可以运行,对学习JBuilder 9来说,稍微有点慢。
(2)700MB硬盘剩余空间。
(3)Microsoft Windows 2000(SP2)/2003,XP,or NT4.0(SP6)。
所以建议大家不要把JBuilder 9安装在非服务器版本的Windows平台例如Windows 2000 Professional上。
(4)Intel(r)Pentium(r)II 233MHz以上CPU。
2、Jbuilder 9的下载
JBuilder9可以从Borand网站上下载,共包括下面3个文件:
(1)程序文件JBuilder9.zip。
(2)联机手册JB9docs.zip。
(3)实例代码jb9samples.zip。
3、Jbuilder 9的安装
Jbuilder9的安装较简单,下面就简单介绍之。首先将jbuilder9.zip文件解包后,运行ent_trial_install.exe文件,开始jbuilder9的安装过程,如图4-11、4-12所示;
图4-11 解压文件
图4-12 安装文件提取
在图4-13中点击"Next"按钮;
图4-13 “Jbuilder9安装”对话框
在图4-14中选中"I accept the terms of the License Agreement",点击"Next"按钮;
图4-14 软件认证
选择安装jbuilder9的路径为F:jbuilder9,如图4-15所示,点击"Next"按钮;
图4-15 选择安装目录
在图4-16中选择"Install"按钮,开始jbuilder9的安装,如图4-17所示;
图4-16 Jbuilder9安装前配置报告
图4-17 “Jbuilder9自动安装”对话框
安装好后出现图4-18的画面,点击"Done"按钮,至此Borland jbuilder 9 Enterprise Trial版本安装就算全部完成。
图4-18 “安装完成”对话框
Jbuilder 9的启动
1)获得试用授权文件或者序列号
需要在Borland网站上注册,获得一个trial license key,这样才可合法地试用JBuilder9。这个key通过电子邮件发到用户注册时提供的信箱上,通常这个key是个文本文件而不是序列号,称为activate file,可以试用JBuilder 9一个月(31天),不过有时这个key不一定可用,可能需要上网寻找合法的key。
2)第一次启动JBuilder9
第一次启动JBuilder9时,会出现一个界面,要求提供JBuilder 9产品的serial number(序列号)或者activate file(产品激活文件),应该选择activate file,然后根据提示选择activate file所在的目录和文件名。如果没有错误,JBuilder 9开始启动,会显示还有多少天的试用期,然后出现JBuilder 9的界面。 第一次启动JBuilder 9时,会出现如图4-19所示的界面,提示界面中的文件类型是否由JBuilder9打开。
图4-19 选择打开文件类型对话框
看到的最前面的是Tip of th eDay(每日一诀)窗口,每次启动时会显示使用JBuilder 9的一个窍门(tip),如果在Show tip of the day after launching前的方框打勾,那么以后启动JBuilder9时,就不会出现Tip of the Day窗口。单击Close按钮就关闭Tip of the Day窗口,此时开始正式使用JBuilder 9,这时看到的界面中,JBuilder9会自动打开一个后缀名为jpx的文件Welcome.jpx,见屏幕左上部鼠标所指处,jpx可能是java project(Java工程或者项目)文件的缩写。
最好安装联机手册jb9docs.zip和实例代码jb9samples.zip,这对于通过手册辅助学习JBuilder9是必须的。
5.3.4 详细设计说明
下面将对本设计的各个部分作详细说明。本设计如图4-2所示,由主界面的树形结构连接收件箱、发件箱、草稿箱和垃圾箱,与服务器间通过POP3和SMTP协议连接。
主界面设计如图4-20所示:
图4-20 邮件客户端主界面
设计中用jSplitPane将窗口分为左右两部分,可左右拖动,改变两边所占区域大小。在左边加入树形结构,作为控制菜单,在邮件系统的根目录下分别包含了收件箱、发件箱、草稿箱和垃圾箱,点击相应信箱,在右边区域显示相应内容。其结构图如图4-21所示:
图4-21 邮件客户端总体结构图
其UML框图如图4-22所示:
收件箱设计如图4-23所示:设计中用Panel1嵌于窗口右侧,在Panel1上再加一个jSplitPane,分上、下两部分。上部分加入Panel5,用于输入服务器、端口、用户名和密码(系统默认服务器为pop.163.com,端口为110,也可在相应框内进行修改,所用服务器必须与用户注册的邮箱服务器相同),连接服务器,当登录成功后,在右边的邮件列表中列出收件箱中的邮件;下部分加入Panel6,用于查看邮件列表中邮件的具体内容,包括发件人、收件人、时间、标题和内容框。其结构图如图4-24所示:
图4-22 邮件客户端主界面UML图
图4-23邮件客户端收件箱
图4-24 邮件客户端收件箱结构图
Panel1、Panel5、Panel6的UML框图分别如图4-25、4-26、4-27所示:
图4-25邮件客户端收件箱UML图
发件箱设计如图4-28所示:
设计中将Panel2嵌于窗口右侧,用于输入收件人、发件人、主题、邮件内容、服务器和端口(系统默认服务器为smtp.163.com,端口为25,也可在相应框内进行修改,所用服务器必须与用户注册的邮箱服务器相同),还要输入用户名和密码,连接服务器,验证登录的同时发送邮件,非常便捷,如果想看发送时的计算机传输代码,则可以点击“显示Log”按钮,会弹出一个窗口用于显示。其结构图如图4-29所示:Panel2的UML框图分别如图4-30所示:
草稿箱的结构类似收件箱,如图4-31所示:用Panel3嵌于窗口右侧,在Panel3上再加一个jSplitPane,分上、下两部分。上部分加入Panel7,用于显示草稿箱中的邮件列表,下部分加入Panel8,用于查看邮件列表中邮件的具体内容,包括收件人、主题和内容框,在内容框下面还有“发送”和“删除”两个按钮,分别对应发件箱和垃圾箱,在发件箱中进行部分修改或直接发送,无用的邮件删除到垃圾箱中。其结构图如图4-32所示:Panel3、 Panel7、Panel8的UML框图分别如图4-33、4-34、4-35所示:
垃圾箱结构也类似于收件箱,不过更简单,如图4-36所示:用Panel4嵌于窗口右侧,在Panel4上再加一个jSplitPane,分上、下两部分。上部分加入Panel9,用于显示垃圾箱中的邮件列表,下部分加入Panel10,只有“还原”和“删除”两个按钮,分别对应将可用邮件恢复到原来位置和彻底删除无用邮件,节省资源。其结构图如图4-37所示:Panel4、 Panel9、Panel10的UML框图分别如图4-38、4-39、4-40所示:
图4-26邮件客户端收件列表UML图
图4-27邮件客户端收件箱查看邮件内容UML图
图4-28邮件客户端发件箱
图4-29邮件客户端发件箱结构图
以上便是邮件客户端的主体框架设计,简约而便捷,在此过程中系统自动生成了Application1,产生一个应用,是本设计的一个总声明;ConnectMessageFrame,用于显示Log对话框,也就是可以查看邮件在发送过程中的系统信息;mail则定义了收件人、发件人、主题、时间和连接等,只有先行定义,才可对其进行后续操作;还有Client定义了用户界面,使用户可以得到一个简单、实用的操作界面,真正为用户负责。其对应UML框图分别如图4-41、4-42、4-43、4-44所示:
图4-30邮件客户端发件箱UML图
图4-31邮件客户端草稿箱
图4-32邮件客户端草稿箱结构图
图4-33邮件客户端草稿箱UML图
图4-34邮件客户端草稿箱邮件列表UML图
图4-35邮件客户端草稿箱查看邮件内容UML图
图4-36邮件客户端垃圾箱
图4-37邮件客户端垃圾箱结构图
图4-38邮件客户端垃圾箱UML图
图4-39邮件客户端垃圾箱邮件列表UML图
图4-40邮件客户端垃圾箱操作UML图
图4-41邮件客户端系统生成应用UML图
图4-42邮件客户端显示LOG框图UML图
图4-43邮件客户端mail定义UML图
图4-44邮件客户端Client定义UML图
在收、发邮件的过程中,起核心作用的是pop3mail和smtpmail。
pop3mail的流程图如图4-45所示:
图4-45 pop3mail流程图
邮件客户端首先向服务器发送连接请求,连接不成功则提示“服务器返回未知响应”,如连接成功则读取服务器返回的信息数据流,同时设定一用来临时保存数据流的容器,可保存邮件列表或邮件内容; 连接建立后,输入用户名和密码,不成功则提示“无效的用户名或密码”,登陆成功则得到邮件列表;如果列表中无显示,则提示“未知错误”,成功则点击查看邮件内容;如内容为空,提示“没有邮件”,否则查看完毕后,关闭连接。pop3mail的UML框图如图4-46 所示:
Smtpmail为发送邮件主函数,其中主要设计了出错提示:
220:无法解析主机 250:未知错误,请查看LOG 334:也许你的服务器不需要身份验证 334:注册失败,无效的用户名 250:错误,可能你还没有注册,或者输入的发件人地址不正确 25:错误,无效的发件人地址 250 未知错误,请查看LOG 221:未知错误,请查看LOG。其中还有其他提示:无效的收件人地址,无效的寄件人地址,主机不能为空,端口不能为空,用户名不能为空等,错误提示会使系统更健壮,更便于使用。smtpmail的UML框图如图4-47 所示:
图4-46邮件客户端pop3mail协议UML图
图4-47邮件客户端smtpmail协议UML图
至此,邮件客户端的详细设计已具体说明,用图示的方法便于读者理解、分析,希望我的设计能给大家带来便利。
4.4 安装程序的设计和制作
源程序虽已完成,但要使用户方便使用,就要将其制作成安装程序,只需用户点击安装后,即可享受该程序带来的方便。
4.4.1 应用程序的设计和制作
1)在JBuilder中打开邮件客户端的jpx文件,点击“File”中的“New”, 点击Build中的Native Executable Builder,点“OK”,如图4-48所示;
2)点“Next”, 如图4-49所示;
3)选中第一个单选框,点“Next”, 如图4-50所示;
4)将几个选择项全改为Include All, 点“Next”, 如图4-51所示;
5)点“Finish”, 如图4-52所示,点击“Run/Run Project”,生成了MailClient.jar和MailClientW.exe两个文件,再将JDK中的jre文件夹加入到程序所在文件夹中;
6)使用Inno Setup 3软件生成Setup.iss文件,点击绿色按钮运行,如图4-53所示,生成setup.exe文件。
图4-48 应用程序制作第1步
图4-49 应用程序制作第2步
图4-50 应用程序制作第3步
图4-51 应用程序制作第4步
图4-52 应用程序制作第5步
图4-53 应用程序制作第6步
4.4.2 安装应用程序
1) 安装程序生成后,点击setup.exe文件进行安装,跳出对话框,选择“是”继续安装,如图4-54所示;
2)跳出安装对话框,点击“Next”继续安装,如图4-55所示;
3)选择安装目录,点击“Next”, 如图4-56所示;
4)点击“Next”, 如图4-57所示;
5)是否在桌面建立图标,点击“Next”, 如图4-58所示;
6)准备安装,点击“Install”, 如图4-59所示;
7)程序安装中,如图4-60所示;
8)安装完成,点击“Fininsh”,如图4-61所示。
现在桌面上就生成了邮件客户端的图标,点击即可运行,享受网上通讯的便利吧!
图4-54 安装应用程序第1步
图4-55 安装应用程序第2步
图4-56 安装应用程序第3步
图4-57 安装应用程序第4步
图4-58 安装应用程序第5步
图4-59 安装应用程序第6步
图4-60 安装应用程序第7步
图4-61 安装应用程序第8步
结论
本次设计“基于JAVA的邮件客户端”分为收件箱、发件箱、草稿箱和垃圾箱四个子模块,各子模块分别包含不同的子功能,实现了邮件的接收、查看和发送,在最后完成了安装程序的设计和制作。总体上来说,通过本次设计,我掌握了一个系统的开发过程,特别是对JAVA有了较为深入的了解。此次设计让我学会了如何从功能上分析一个系统、如何从结构上设计一个系统。同时我也深深的体会到开发一个系统并不是一项技术的单独使用,它需要各种技术的相互渗透和交叉,例如JAVA是本系统设计的主角,但是如果没有JavaMail、JBuilder等的辅助,本系统的实现将是一句空话。
由于自身能力有限,没有开发软件的经验,所以本次毕业设计还存在不少不尽人意的地方,虽然程序结构比较完整,但在功能上有所欠缺,如客户端与通讯录的结合不是很完善,垃圾箱与草稿箱中的邮件列表功能还有待改进,对Java和JBuilder的相关知识还有待进一步的学习与提高。
通过本次毕业设计,使我对软件开发有了较为深刻的认识,增强了动手与用脑的能力。当然,在毕业设计中,由于并没有处理好部分功能模块之间的联系与耦合,设计出来的功能与实际应用还存在一定的差距,使我的设计存在着一些失误与不足,但从另一方面来说,这无疑也增加了我的经验,让我在以后的工作中对软件的整个开发流程有了更加清晰地认识。在本次的设计中,我学习了许多新知识和编程中的技巧,尤其是JAVA技术的不依赖于任何操作平台的极大优势和便利,并且深深体会到新技术在网络上成功使用的便利。
致谢
本文从选题到论文的最后完稿,一直都是在黄进老师的严格要求和热情帮助下完成的。黄老师学识渊博,为人热情,给与了我许多指导和帮助。我在毕业设计中的每一点进步都与黄老师的热心帮助和严格要求是分不开的。在此,谨向黄进老师表示由衷的感谢!黄老师严谨的治学态度、一丝不苟的工作作风,将使我终身受益。
感谢西南交通大学为我创造的良好的学习和生活环境,感谢电气工程学院各位老师在学习和生活上给予的关心、帮助。
还要感谢大学四年来与我朝夕相处、一起求学、相互帮助的同学,他们给了我支持与鼓励、信心与力量,我们一起分享了四年来的成功与失败、欢笑和泪水。他们给我留下了美好的回忆,是我人生中无价的财富。
最后,向远在家乡的父母表示感谢,感谢四年来他们对我的支持和关心。
参考文献
【1】 沈耀,郝萍,李扬.JBuilder基础开发篇.清华大学出版社,2005
【2】 邓良松,刘海岩,陆丽娜.软件工程.西安电子科技大学出版社,2000
【3】 谢希仁.计算机网络(第四版).大连理工大学出版社,2004
【4】 胡伏湘,雷军环.Java程序设计实用教程.清华大学出版社,2005
【5】 魏伟,陈维军,张烨.Jbuilder开发人员指南.机械工业出版社,2001
【6】 SwanTom.Java2快速解决方案.卢建山.北京:中国水利水电出版社, 2002
附录
本设计各主要板块源程序如下所示:
Pop3Mail
package mailclient;
import java.net.*;
import java.io.*;
import javax.swing.*;
import java.util.*;
public class pop3mail {
String host;
int port;
String user;
String password;
Socket popSocket;
int list=0;
String[] listContent;
boolean connected=false;
mailclient.mail popMail=new mailclient.mail();
ConnectMessageFrame messageFrame=new ConnectMessageFrame();
DataOutputStream outToServer;//向服务器发送信息的数据流
DataInputStream inFromServer;//读取服务器返回的信息的数据流
BufferedReader inData;//读取服务器返回数据的数据流
byte[] inByte;//用来临时保存inFromServer流数据字节
//保存邮件列表或邮件内容
public void setHost(String h){host=new String(h);}
public void setPort(int p){port=p;}
public void setUser(String u){user=u;}
public void setPassword(String p){password=p;}
public int getList(){return list;}
public String[] getListContent(){return listContent;}
public boolean popConnected(){return connected;}
public String getMailFrom(){return popMail.getMailFrom();}
public String getMailTo(){return popMail.getMailTo();}
public String getSubject(){return popMail.getSubject();}
public String getDate(){return popMail.getDate();}
public String getContent(){return popMail.getContent();}
public void showMessageFrame(){messageFrame.setVisible(true);}
public void hideMessageFrame(){messageFrame.setVisible(false);}
public void addItemToMessageFrame(String s){messageFrame.addMessageToMessageFrame(s);}
public pop3mail() {
try {
jbInit();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
//-----------------------------------------------------------------------
//协议的主要部分,连接服务器并获得邮件列表
public boolean transfer(){
if(host.equals("")||port<=0){
JOptionPane.showMessageDialog(messageFrame, "请输入正确的主机名和端口", "Warnning",
JOptionPane.WARNING_MESSAGE);
return false;
}
addItemToMessageFrame("Connecting to "+host+" : "+port);
//与服务器建立联系
try{
popSocket=new Socket(host,port);
connected=true;
outToServer=new DataOutputStream(
popSocket.getOutputStream());
inFromServer=new DataInputStream(
popSocket.getInputStream());
inData=new BufferedReader(
new InputStreamReader(popSocket.getInputStream()));
if(!getResponseFromServer("服务器返回未知响应")){
return false;
}
//校对用户名和密码
sendCommandToServer("USER "+user);
if(!getResponseFromServer("无效的用户名"))
return false;
sendCommandToServer("PASS "+password);
if(!getResponseFromServer("无效的密码"))
return false;
//得到关于邮件列表的信息
getListFromServer();
}
catch (UnknownHostException ex){
JOptionPane.showMessageDialog(
messageFrame,"无法解析主机","Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ex.toString());
connected=false;
return false;
}
catch (IOException ee){
JOptionPane.showMessageDialog(
messageFrame,ee.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ee.toString());
connected=false;
return false;
}
finally{
try {
popSocket.close();
addItemToMessageFrame("连接断开");
connected=false;
return false;
}
catch (IOException ioe) {
JOptionPane.showMessageDialog(
messageFrame, ioe.toString(), "Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ioe.toString());
addItemToMessageFrame("连接断开");
connected=false;
return false;
}
}
}
//得到列表
public void getListFromServer(){
if(connected=false)
return;
sendCommandToServer("STAT");
String listSentence=new String(getOneMessageFromServer());
StringTokenizer listS=new StringTokenizer(listSentence);
if(!listS.nextToken().equals("+OK")){
JOptionPane.showMessageDialog(
messageFrame,"未知错误getListFromServer()","Error",
JOptionPane.ERROR_MESSAGE);
return;
}
list=Integer.parseInt(listS.nextToken());
listContent=new String[list+1];
//listContent
if(list==0)
listContent[0]="没有邮件";
else
listContent[0]="有"+list+"封邮件";
sendCommandToServer("LIST");
if(!getResponseFromServer("无法实现邮件列表,可能你的邮件服务器并不是POP3服务器"))
return;
for(int i=1;i<=list+1;i++){
listContent[i]=new String(getOneMessageFromServer());
}
}
public void receiveMail(int mailnumber){
if(connected==true)//单线程
return;
try{
popSocket=new Socket(host,port);
connected=true;
outToServer=new DataOutputStream(
popSocket.getOutputStream());
inFromServer=new DataInputStream(
popSocket.getInputStream());
inData=new BufferedReader(
new InputStreamReader(popSocket.getInputStream()));
if(!getResponseFromServer("服务器返回未知响应"))
return;
//校对用户名和密码
sendCommandToServer("USER "+user);
if(!getResponseFromServer("无效的用户名"))
return;
sendCommandToServer("PASS "+password);
if(!getResponseFromServer("无效的密码"))
return;
sendCommandToServer("RETR "+mailnumber);
if(!getResponseFromServer("无法得到指定的邮件"))
return;
String mailContentString=new String(getOneMessageFromServer());
while(!mailContentString.trim().equals("")){//邮件的相关信息
if(mailContentString.startsWith("From"))
popMail.setMailFrom(mailContentString.substring(5));
if(mailContentString.startsWith("To"))
popMail.setMailTo(mailContentString.substring(3));
if(mailContentString.startsWith("Subject"))
popMail.setSubject(mailContentString.substring(8));
if(mailContentString.startsWith("Date"))
popMail.setDate(mailContentString.substring(5));
mailContentString=new String(getOneMessageFromServer());
}
mailContentString=new String(getOneMessageFromServer());//跳过空行
String mailC=new String("");
while(!(mailContentString.startsWith(".")
&&mailContentString.trim().equals("."))){
mailC=new String(mailC.concat(mailContentString+" "));
mailContentString=new String(getOneMessageFromServer());
}
popMail.setContent(mailC);
}
catch (UnknownHostException ex){
JOptionPane.showMessageDialog(
messageFrame,"无法解析主机","Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ex.toString());
connected=false;
return;
}
catch (IOException ee){
JOptionPane.showMessageDialog(
messageFrame,ee.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ee.toString());
connected=false;
}
finally{
try {
popSocket.close();
addItemToMessageFrame("连接断开");
connected=false;
}
catch (IOException ioe) {
JOptionPane.showMessageDialog(
messageFrame, ioe.toString(), "Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ioe.toString());
addItemToMessageFrame("连接断开");
connected=false;
}
}
Panel6 popMailFrame=new Panel6(popMail);
popMailFrame.show();
// popMailFrame.setVisible(true);
}
public boolean sendCommandToServer(String s){
try{
outToServer.writeBytes(s+‘ ‘+‘ ‘);
if(s.startsWith("PASS"))
addItemToMessageFrame("PASS ************");
else
addItemToMessageFrame(s);
}
catch(IOException ioex){
JOptionPane.showMessageDialog(
messageFrame,ioex.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ioex.toString());
}
return true;
}
public boolean getResponseFromServer(String err){
//发出指令后察看服务器回应指令
String mfs=new String(getOneMessageFromServer());
if(!mfs.startsWith("+OK")){
JOptionPane.showMessageDialog(
messageFrame,err,"Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
return true;
}
public String getOneMessageFromServer(){
//从服务器读取一句信息,并返回
String oneSentenceFromServer=new String("");
try{
oneSentenceFromServer=new String(inData.readLine());
addItemToMessageFrame(oneSentenceFromServer);
}
catch(IOException ioeX){
JOptionPane.showMessageDialog(
messageFrame,"失却连接","Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ioeX.toString());
}
return oneSentenceFromServer;
}
public String getMessagesFromServer(){
//从服务器接收不止一句的数据流,如列表并返回,本程序中未用
String inByteString=null;
try{
inByte = new byte[1024];
inFromServer.read(inByte);
inByteString=new String(inByte,0,inByte.length);
}
catch(IOException ioeX){
JOptionPane.showMessageDialog(
messageFrame,ioeX.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
addItemToMessageFrame(ioeX.toString());
}
return inByteString;
}
private void jbInit() throws Exception {
}
}
SmtpMail
package mailclient;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.util.*;
import sun.misc.*;
import java.io.*;
import java.awt.event.*;
import sun.misc.*;
public class smtpMail {
String sentence;
String modifiedSentence;
String mailfrom;
String mailto;
String subject;
String content;
String host;
int port;
boolean authorization=false;
String user;
String password;
ConnectMessageFrame messageFrame=new ConnectMessageFrame();
Socket clientSocket;
DataOutputStream outToServer;
BufferedReader inData;
public void setMailFrom(String m){mailfrom=new String(m);}
public void setMailTo(String m){mailto=new String(m);}
public void setSubject(String s){subject=new String(s);}
public void setContent(String c){content=new String(c);}
public void setHost(String h){host=new String(h);}
public void setPort(int p){port=p;}
public void setAuthorization(boolean a){authorization=a;}
public void setUser(String u){user=new String(u);}
public void setPassword(String p){password=new String(p);}
public void showMessageFrame(){messageFrame.setVisible(true);}
public void hideMessageFrame(){messageFrame.setVisible(false);}
public smtpMail() {
try {
jbInit();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
//----------------------------------------------------------------------------
//发送邮件主函数
void transfer(){
if(!connectable())
return;
sentence=new String("Trying to connect to"+host+":"+port);
messageFrame.addMessageToMessageFrame(sentence);
try{
clientSocket=new Socket(host,port);
outToServer=
new DataOutputStream(
clientSocket.getOutputStream());
inData=
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
if(!responseFromServer("220","无法解析主机"))
return;
if(!sendToServer("EHLO stmp.taohoo.com"))
return;
if(!responseFromServer("250","未知错误,请查看LOG!"))
return;
if(authorization==true){
if(!sendToServer("AUTH LOGIN"))
return;
if(!responseFromServer("334",
"未知错误,也许你的服务器不需要身份验证!"))
return;
user=new BASE64Encoder().encode(user.getBytes());
if(!sendToServer(user))
return;
if(!responseFromServer("334",
"注册失败,无效的用户名!"))
return;
password=new BASE64Encoder().encode(password.getBytes());
if(!sendToServer(password))
return;
if(!responseFromServer("235",
"注册失败,请检查你的用户名和密码!"))
return;
}
if(!sendToServer("MAIL FROM:<"+mailfrom+">"))
return;
if(!responseFromServer("250","错误!可能你还没有注册,或者输入的发件人地址不正确"))
return;
if(!sendToServer("RCPT TO:<"+mailto+">"))
return;
if(!responseFromServer("25","错误!无效的发件人地址"))//回复应该是250或者251
return;
if(!sendToServer("DATA"))
return;
if(!responseFromServer("354","未知错误,请查看LOG!"))
return;
if(!sendToServer("To:"+mailto))
return;
if(!sendToServer("From:"+mailfrom))
return;
if(!sendToServer("Subject:"+subject))
return;
if(!sendToServer(content))
return;
String msgEnd=new String(String.valueOf("."));
if(!sendToServer(msgEnd))
return;
if(!responseFromServer("250","未知错误,请查看LOG!"))
return;
if(!sendToServer("QUIT"))
return;
if(!responseFromServer("221","未知错误,请查看LOG!"))
return;
inData.close();
outToServer.close();
clientSocket.close();
JOptionPane.showMessageDialog(messageFrame,"邮件已成功发出!");
}
catch (UnknownHostException ex){
JOptionPane.showMessageDialog(
messageFrame,ex.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
}
catch (IOException ee){
JOptionPane.showMessageDialog(
messageFrame,ee.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
}
finally{
try{
clientSocket.close();
messageFrame.addMessageToMessageFrame("连接断开");
}
catch(IOException ioe){
JOptionPane.showMessageDialog(
messageFrame,ioe.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
messageFrame.addMessageToMessageFrame("连接断开");
}
}
}
//检查邮件发送设置是否正确
boolean connectable(){
if(mailto.indexOf((int)‘@‘)==-1){
JOptionPane.showMessageDialog(
messageFrame,"无效的收件人地址!","Warning",
JOptionPane.WARNING_MESSAGE);
return false;
}
if(mailfrom.indexOf((int)‘@‘)==-1){
JOptionPane.showMessageDialog(
messageFrame,"无效的寄件人地址!","Warning",
JOptionPane.WARNING_MESSAGE);
return false;
}
if(subject.equals("")){
if(JOptionPane.showConfirmDialog(
messageFrame,"没有主题,你确定吗!","Confirm",
JOptionPane.OK_CANCEL_OPTION)==JOptionPane.CANCEL_OPTION)
return false;
}
if(host.equals("")){
JOptionPane.showMessageDialog(
messageFrame,"主机不能为空!","Warning",
JOptionPane.WARNING_MESSAGE);
return false;
}
if(port<=0){
JOptionPane.showMessageDialog(
messageFrame,"端口不能为空!","Warning",
JOptionPane.WARNING_MESSAGE);
return false;
}
if(authorization==true){
if(user.equals("")){
JOptionPane.showMessageDialog(
messageFrame,"用户名不能为空!","Warning",
JOptionPane.WARNING_MESSAGE);
return false;
}
}
return true;
}
//服务器的反应,
boolean responseFromServer(String cmd,String errorMessage){
String responseSentence;
try {
responseSentence = new String(inData.readLine());
messageFrame.addMessageToMessageFrame(responseSentence);
if (!responseSentence.startsWith(cmd)) {
JOptionPane.showMessageDialog(messageFrame,
errorMessage,
"Error", JOptionPane.ERROR_MESSAGE);
return false;
}
}
catch (IOException ioex) {
JOptionPane.showMessageDialog(
messageFrame, ioex.toString(), "Error",
JOptionPane.ERROR_MESSAGE);
messageFrame.addMessageToMessageFrame(ioex.toString());
return false;
}
while(responseSentence.startsWith("-",3)){
try{
responseSentence = new String(inData.readLine());
messageFrame.addMessageToMessageFrame(responseSentence);
}
catch(IOException ioeX){
JOptionPane.showMessageDialog(
messageFrame,ioeX.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
messageFrame.addMessageToMessageFrame(ioeX.toString());
return false;
}
}
return true;
}
//向服务器发送一个命令
boolean sendToServer(String msg){
messageFrame.jList1.setSelectionBackground(new Color(205, 157, 56));
messageFrame.addMessageToMessageFrame(msg);
try{
outToServer.writeBytes(msg+‘ ‘+‘ ‘);
}
catch(IOException ioex){
JOptionPane.showMessageDialog(
messageFrame,ioex.toString(),"Error",
JOptionPane.ERROR_MESSAGE);
messageFrame.addMessageToMessageFrame(ioex.toString());
return false;
}
return true;
}
private void jbInit() throws Exception {
}
}
Frame1
package mailclient;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.util.*;
/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2006</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Frame1 extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
JSplitPane jSplitPane1 = new JSplitPane();
JTree jTree1;
private Panel1 p1 = new Panel1();
private Panel2 p2 = new Panel2();
private Panel3 p3 = new Panel3();
private Panel4 p4 = new Panel4();
public Frame1() {
try {
setDefaultCloseOperation(EXIT_ON_CLOSE);
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
Frame1 Frame1 = new Frame1();
Frame1.show();
}
/**
* Component initialization.
*
* @throws java.lang.Exception
*/
private void jbInit() throws Exception {
contentPane = (JPanel) getContentPane();
contentPane.setLayout(borderLayout1);
setSize(new Dimension(531, 322));
setTitle("Frame Title");
contentPane.add(jSplitPane1, java.awt.BorderLayout.CENTER);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("邮件系统");
DefaultMutableTreeNode root1 = new DefaultMutableTreeNode("收件箱");
DefaultMutableTreeNode root2 = new DefaultMutableTreeNode("发件箱");
DefaultMutableTreeNode root3 = new DefaultMutableTreeNode("草稿箱");
DefaultMutableTreeNode root4 = new DefaultMutableTreeNode("垃圾箱");
root.add(root1);
root.add(root2);
root.add(root3);
root.add(root4);
jTree1 = new JTree(root);
jTree1.addTreeSelectionListener(new Frame1_jTree1_treeSelectionAdapter(this));
jSplitPane1.add(jTree1, JSplitPane.LEFT);
jSplitPane1.add(p1, JSplitPane.RIGHT);
}
public void jTree1_valueChanged(TreeSelectionEvent e) {
String node = jTree1.getLastSelectedPathComponent().toString();
if (node.equals("收件箱")) {
jSplitPane1.remove(jSplitPane1.getRightComponent());
jSplitPane1.add(p1, JSplitPane.RIGHT);
}
if (node.equals("发件箱")) {
jSplitPane1.remove(jSplitPane1.getRightComponent());
jSplitPane1.add(p2, JSplitPane.RIGHT);
}
if (node.equals("草稿箱")) {
jSplitPane1.remove(jSplitPane1.getRightComponent());
jSplitPane1.add(p3, JSplitPane.RIGHT);
}
if (node.equals("垃圾箱")) {
jSplitPane1.remove(jSplitPane1.getRightComponent());
jSplitPane1.add(p4, JSplitPane.RIGHT);
}
}
class Frame1_jTree1_treeSelectionAdapter implements TreeSelectionListener {
private Frame1 adaptee;
Frame1_jTree1_treeSelectionAdapter(Frame1 adaptee) {
this.adaptee = adaptee;
}
public void valueChanged(TreeSelectionEvent e) {
adaptee.jTree1_valueChanged(e);
}
}
}
Panel1
package mailclient;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import java.awt.*;
/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2006</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Panel1 extends JPanel {
JSplitPane jSplitPane1 = new JSplitPane();
BorderLayout borderLayout1 = new BorderLayout();
private Panel5 p5 = new Panel5(this);
private Panel6 p6 = new Panel6();
public Panel1() {
try {
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void jbInit() throws Exception {
jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
this.setLayout(borderLayout1);
this.add(jSplitPane1, java.awt.BorderLayout.CENTER);
jSplitPane1.add(p5, JSplitPane.TOP);
jSplitPane1.add(p6, JSplitPane.BOTTOM);
}
}
Panel2
package mailclient;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.beans.*;
/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2006</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Panel2 extends JPanel {
smtpMail smtp=new smtpMail();
pop3mail pop=new pop3mail();
JButton jButton2 = new JButton();
JLabel jLabel6 = new JLabel();
JTextField sMailTojTextField = new JTextField();
JLabel jLabel7 = new JLabel();
JTextField sMailFromjTextField = new JTextField();
JLabel jLabel8 = new JLabel();
JTextField sSubjectjTextField = new JTextField();
JScrollPane jScrollPane2 = new JScrollPane();
JTextArea sjTextArea = new JTextArea();
JLabel jLabel9 = new JLabel();
JTextField sHostjTextField = new JTextField();
JLabel jLabel10 = new JLabel();
JTextField sPortjTextField = new JTextField();
JRadioButton jRadioButton1 = new JRadioButton();
JLabel jLabel11 = new JLabel();
JTextField sUserjTextField = new JTextField();
JLabel jLabel12 = new JLabel();
JPasswordField sPasswordjPasswordField = new JPasswordField();
JButton jButton3 = new JButton();
JButton jButton4 = new JButton();
public Panel2() {
try {
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void jbInit() throws Exception {
this.setLayout(null);
jButton2.setBounds(new Rectangle(30, 229, 135, 41));
jButton2.setFont(new java.awt.Font("Dialog", 1, 16));
jButton2.setText("显示LOG");
jButton2.addActionListener(new Panel2_jButton2_actionAdapter(this));
//jList1.addMouseListener(new Panel2_jList1_mouseAdapter(this));
jLabel6.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel6.setRequestFocusEnabled(true);
jLabel6.setText("收件人:");
jLabel6.setBounds(new Rectangle(1, 10, 66, 24));
sMailTojTextField.setText("");
sMailTojTextField.setBounds(new Rectangle(79, 8, 341, 24));
sMailTojTextField.addActionListener(new
Panel2_sMailTojTextField_actionAdapter(this));
jLabel7.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel7.setText("发件人:");
jLabel7.setBounds(new Rectangle(1, 36, 79, 24));
sMailFromjTextField.setText("");
sMailFromjTextField.setBounds(new Rectangle(79, 36, 341, 24));
sMailFromjTextField.addActionListener(new
Panel2_sMailFromjTextField_actionAdapter(this));
sMailFromjTextField.addKeyListener(new Panel2_sMailFromjTextField_keyAdapter(this));
jLabel8.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel8.setText("主题:");
jLabel8.setBounds(new Rectangle(0, 62, 65, 24));
sSubjectjTextField.setText("");
sSubjectjTextField.setBounds(new Rectangle(79, 63, 340, 24));
jScrollPane2.setBounds(new Rectangle(4, 95, 420, 124));
jLabel9.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel9.setText("服务器:");
jLabel9.setBounds(new Rectangle(3, 222, 64, 24));
sHostjTextField.setText("smtp.163.com");
sHostjTextField.setBounds(new Rectangle(70, 223, 242, 26));
sHostjTextField.addActionListener(new
Panel2_sHostjTextField_actionAdapter(this));
jLabel10.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel10.setRequestFocusEnabled(true);
jLabel10.setVerifyInputWhenFocusTarget(true);
jLabel10.setText("端口:");
jLabel10.setBounds(new Rectangle(316, 221, 53, 30));
sPortjTextField.setText("25");
sPortjTextField.setBounds(new Rectangle(370, 223, 44, 24));
sPortjTextField.addActionListener(new
Panel2_sPortjTextField_actionAdapter(this));
jRadioButton1.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jRadioButton1.setActionCommand("我的服务器需要身份验证:");
jRadioButton1.setText("需要身份验证");
jRadioButton1.setBounds(new Rectangle(2, 253, 222, 27));
jRadioButton1.addActionListener(new Panel2_jRadioButton1_actionAdapter(this));
jRadioButton1.addItemListener(new Panel2_jRadioButton1_itemAdapter(this));
jLabel11.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel11.setText("用户名:");
jLabel11.setBounds(new Rectangle(0, 281, 65, 23));
sUserjTextField.setEnabled(false);
sUserjTextField.setText("");
sUserjTextField.setBounds(new Rectangle(60, 282, 117, 23));
jLabel12.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel12.setDebugGraphicsOptions(0);
jLabel12.setText("密码:");
jLabel12.setBounds(new Rectangle(187, 281, 51, 27));
sPasswordjPasswordField.setEnabled(false);
sPasswordjPasswordField.setText("");
sPasswordjPasswordField.setBounds(new Rectangle(236, 282, 110, 26));
sPasswordjPasswordField.addActionListener(new
Panel2_sPasswordjPasswordField_actionAdapter(this));
jButton3.setBackground(new Color(42, 221, 48));
jButton3.setBounds(new Rectangle(353, 282, 84, 29));
jButton3.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jButton3.setForeground(Color.black);
jButton3.setText("发送");
jButton3.addActionListener(new Panel2_jButton3_actionAdapter(this));
jButton4.setBounds(new Rectangle(345, 249, 92, 31));
jButton4.setFont(new java.awt.Font("华文行楷", Font.BOLD, 12));
jButton4.setActionCommand("查看LOG");
jButton4.setText("显示LOG");
jButton4.addActionListener(new Panel2_jButton4_actionAdapter(this));
this.add(sMailTojTextField, null);
this.add(jLabel6, null);
this.add(sMailFromjTextField, null);
this.add(jLabel7, null);
this.add(jLabel8, null);
this.add(sSubjectjTextField, null);
this.add(jScrollPane2, null);
jScrollPane2.getViewport().add(sjTextArea, null);
this.add(jLabel9, null);
this.add(sHostjTextField, null);
this.add(jLabel10, null);
this.add(sPortjTextField, null);
this.add(jRadioButton1, null);
this.add(jLabel11, null);
this.add(jButton3, null);
this.add(jButton4, null);
this.add(sUserjTextField, null);
this.add(jLabel12, null);
this.add(sPasswordjPasswordField, null);
this.setSize(new Dimension(447, 458));
Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize=this.getSize();
this.setLocation(screenSize.width/2-frameSize.width/2,screenSize.height/2-frameSize.height/2);
}
void jButton2_actionPerformed(ActionEvent e) {
pop.showMessageFrame();
}
void jButton3_actionPerformed(ActionEvent e) {
smtp.setMailTo(sMailTojTextField.getText());
smtp.setMailFrom(sMailFromjTextField.getText());
smtp.setSubject(sSubjectjTextField.getText());
smtp.setContent(sjTextArea.getText());
smtp.setHost(sHostjTextField.getText());
smtp.setPort(Integer.parseInt(sPortjTextField.getText()));
if(smtp.authorization==true){
smtp.setUser(sUserjTextField.getText());
smtp.setPassword(new String(sPasswordjPasswordField.getPassword()));
}
smtp.transfer();
}
void jRadioButton1_itemStateChanged(ItemEvent e) {
if(e.getStateChange()==e.SELECTED){
sUserjTextField.setEnabled(true);
sPasswordjPasswordField.setText("");
sPasswordjPasswordField.setEnabled(true);
smtp.authorization=true;
}
else{
sUserjTextField.setEnabled(false);
sPasswordjPasswordField.setEnabled(false);
smtp.authorization=false;
}
}
void jButton4_actionPerformed(ActionEvent e) {
smtp.showMessageFrame();
}
void sMailFromjTextField_keyReleased(KeyEvent e) {
String shost=new String("smtp");
String temph=new String(sMailFromjTextField.getText());
int pos=temph.indexOf("@");
if(pos!=-1)
shost=new String(shost.concat("."+temph.substring(pos+1)));
sHostjTextField.setText(shost);
}
public void sMailTojTextField_actionPerformed(ActionEvent e) {
}
public void sMailFromjTextField_actionPerformed(ActionEvent e) {
}
public void sHostjTextField_actionPerformed(ActionEvent e) {
}
public void jRadioButton1_actionPerformed(ActionEvent e) {
}
public void sPasswordjPasswordField_actionPerformed(ActionEvent e) {
}
public void sPortjTextField_actionPerformed(ActionEvent e) {
}
}
class Panel2_sPasswordjPasswordField_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_sPasswordjPasswordField_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sPasswordjPasswordField_actionPerformed(e);
}
}
class Panel2_jRadioButton1_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_jRadioButton1_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jRadioButton1_actionPerformed(e);
}
}
class Panel2_sHostjTextField_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_sHostjTextField_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sHostjTextField_actionPerformed(e);
}
}
class Panel2_sMailFromjTextField_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_sMailFromjTextField_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sMailFromjTextField_actionPerformed(e);
}
}
class Panel2_jButton2_actionAdapter implements java.awt.event.ActionListener {
Panel2 adaptee;
Panel2_jButton2_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton2_actionPerformed(e);
}
}
class Panel2_jButton3_actionAdapter implements java.awt.event.ActionListener {
Panel2 adaptee;
Panel2_jButton3_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton3_actionPerformed(e);
}
}
class Panel2_sPortjTextField_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_sPortjTextField_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sPortjTextField_actionPerformed(e);
}
}
class Panel2_jRadioButton1_itemAdapter implements java.awt.event.ItemListener {
Panel2 adaptee;
Panel2_jRadioButton1_itemAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void itemStateChanged(ItemEvent e) {
adaptee.jRadioButton1_itemStateChanged(e);
}
}
class Panel2_jButton4_actionAdapter implements java.awt.event.ActionListener {
Panel2 adaptee;
Panel2_jButton4_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton4_actionPerformed(e);
}
}
class Panel2_sMailTojTextField_actionAdapter
implements ActionListener {
private Panel2 adaptee;
Panel2_sMailTojTextField_actionAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sMailTojTextField_actionPerformed(e);
}
}
class Panel2_sMailFromjTextField_keyAdapter extends java.awt.event.KeyAdapter {
Panel2 adaptee;
Panel2_sMailFromjTextField_keyAdapter(Panel2 adaptee) {
this.adaptee = adaptee;
}
public void keyReleased(KeyEvent e) {
adaptee.sMailFromjTextField_keyReleased(e);
}
}
Panel5
package mailclient;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2006</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Panel5 extends JPanel {
JLabel jLabel1 = new JLabel();
JTextField hostjTextField = new JTextField();
JLabel jLabel2 = new JLabel();
JTextField portjTextField = new JTextField();
JLabel jLabel3 = new JLabel();
JTextField userjTextField = new JTextField();
JLabel jLabel4 = new JLabel();
JButton jButton1 = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel model = new DefaultListModel();
JList jList1 = new JList(model);
JLabel jLabel5 = new JLabel();
JPasswordField jPasswordField = new JPasswordField();
pop3mail pop = new pop3mail();
Panel1 p1;
public Panel5(Panel1 p_1) {
try {
jbInit();
p1=p_1;
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void jbInit() throws Exception {
this.setLayout(null);
jLabel1.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 18));
jLabel1.setText("端口:");
jLabel1.setBounds(new Rectangle(21, 42, 54, 20));
jLabel2.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 18));
jLabel2.setText("服务器:");
jLabel2.setBounds(new Rectangle(20, 13, 64, 24));
jLabel3.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 18));
jLabel3.setText("用户名:");
jLabel3.setBounds(new Rectangle(18, 66, 63, 22));
jLabel4.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 18));
jLabel4.setText("密码:");
jLabel4.setBounds(new Rectangle(20, 93, 53, 22));
hostjTextField.setText("pop.163.com");
hostjTextField.setBounds(new Rectangle(85, 15, 93, 21));
portjTextField.setText("110");
portjTextField.setBounds(new Rectangle(85, 42, 62, 21));
userjTextField.setText("");
userjTextField.setBounds(new Rectangle(85, 67, 93, 21));
jButton1.setBounds(new Rectangle(85, 133, 96, 38));
jButton1.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 20));
jButton1.setActionCommand("收邮件");
jButton1.setText("连接");
jButton1.addActionListener(new Panel5_jButton1_actionAdapter(this));
jScrollPane1.setBounds(new Rectangle(279, 55, 143, 227));
jPasswordField.setText("");
jPasswordField.setBounds(new Rectangle(85, 95, 95, 23));
jLabel5.setFont(new java.awt.Font("华文行楷", Font.PLAIN, 20));
jLabel5.setText("邮件列表");
jLabel5.setBounds(new Rectangle(251, 8, 84, 27));
jList1.addMouseListener(new Panel5_jList1_mouseAdapter(this));
this.add(jLabel2);
this.add(jLabel1, null);
this.add(jLabel3);
this.add(jLabel4);
this.add(hostjTextField);
this.add(portjTextField);
this.add(userjTextField);
this.add(jPasswordField);
this.add(jButton1);
//this.add(jButton2, null);
this.add(jLabel5);
this.add(jScrollPane1, null);
jScrollPane1.getViewport().add(jList1, null);
this.setSize(new Dimension(447, 458));
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = this.getSize();
this.setLocation(screenSize.width / 2 - frameSize.width / 2,
screenSize.height / 2 - frameSize.height / 2);
}
public void jButton1_actionPerformed(ActionEvent e) {
model.removeAllElements();
pop.setHost(hostjTextField.getText());
pop.setPort(Integer.parseInt(portjTextField.getText()));
pop.setUser(userjTextField.getText());
pop.setPassword(new String(jPasswordField.getPassword()));
pop.transfer();
String[] mailList = new String[pop.getList() + 1];
mailList = pop.getListContent();
for (int count = 0; count <= pop.getList(); count++) {
model.addElement(mailList[count]);
}
}
void jList1_mouseClicked(MouseEvent e) {
int index;
index = jList1.locationToIndex(e.getPoint());
if (index >= 1)
pop.receiveMail(index);
p1.jSplitPane1.remove(p1.jSplitPane1.getBottomComponent());
Panel6 p6 = new Panel6(pop.popMail);
p1.jSplitPane1.add(p6, p1.jSplitPane1.BOTTOM);
}
public void sHostjTextField_actionPerformed(ActionEvent e) {
}
public void sPasswordjPasswordField_actionPerformed(ActionEvent e) {
}
public void sPortjTextField_actionPerformed(ActionEvent e) {
}
}
class Panel5_sPasswordjPasswordField_actionAdapter
implements ActionListener {
private Panel5 adaptee;
Panel5_sPasswordjPasswordField_actionAdapter(Panel5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sPasswordjPasswordField_actionPerformed(e);
}
}
class Panel5_sHostjTextField_actionAdapter
implements ActionListener {
private Panel5 adaptee;
Panel5_sHostjTextField_actionAdapter(Panel5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sHostjTextField_actionPerformed(e);
}
}
class Panel5_jButton1_actionAdapter implements java.awt.event.ActionListener {
Panel5 adaptee;
Panel5_jButton1_actionAdapter(Panel5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton1_actionPerformed(e);
}
}
class Panel5_jList1_mouseAdapter extends java.awt.event.MouseAdapter {
Panel5 adaptee;
Panel5_jList1_mouseAdapter(Panel5 adaptee) {
this.adaptee = adaptee;
}
public void mouseClicked(MouseEvent e) {
adaptee.jList1_mouseClicked(e);
}
}
class Panel5_sPortjTextField_actionAdapter
implements ActionListener {
private Panel5 adaptee;
Panel5_sPortjTextField_actionAdapter(Panel5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.sPortjTextField_actionPerformed(e);
}
}
Panel6
package mailclient;
import java.awt.*;
import javax.swing.*;
import mailclient.mail;
import com.borland.jbcl.layout.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* <p>Title: </p>
*
* <p>Description: </p>
*
* <p>Copyright: Copyright (c) 2006</p>
*
* <p>Company: </p>
*
* @author not attributable
* @version 1.0
*/
public class Panel6 extends JPanel {
JLabel jLabel1 = new JLabel();
JTextField mailFromjTextField = new JTextField();
JLabel jLabel2 = new JLabel();
JTextField mailTojTextField = new JTextField();
JLabel jLabel3 = new JLabel();
JTextField subjectjTextField = new JTextField();
JScrollPane jScrollPane1 = new JScrollPane();
JTextField datejTextField = new JTextField();
JLabel jLabel4 = new JLabel();
JPanel Panel5 = new JPanel();
OverlayLayout2 overlayLayout21 = new OverlayLayout2();
JTextArea contentjTextArea = new JTextArea();
public Panel6(mailclient.mail m) {
try {
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
mailFromjTextField.setText(m.getMailFrom());
mailTojTextField.setText(m.getMailTo());
subjectjTextField.setText(m.getSubject());
datejTextField.setText(m.getDate());
contentjTextArea.setText(m.getContent());
}
public Panel6() {
try {
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void jbInit() throws Exception {
jLabel1.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel1.setText("发件人:");
jLabel1.setBounds(new Rectangle(9, 37, 63, 27));
this.setLayout(null);
mailFromjTextField.setText("");
mailFromjTextField.setBounds(new Rectangle(82, 39, 352, 24));
mailFromjTextField.addActionListener(new
Panel6_mailFromjTextField_actionAdapter(this));
jLabel2.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel2.setText("收件人:");
jLabel2.setBounds(new Rectangle(7, 71, 62, 27));
mailTojTextField.setText("");
mailTojTextField.setBounds(new Rectangle(81, 68, 352, 26));
jLabel3.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel3.setToolTipText("");
jLabel3.setText("标题:");
jLabel3.setBounds(new Rectangle(9, 137, 62, 25));
subjectjTextField.setText("");
subjectjTextField.setBounds(new Rectangle(81, 137, 353, 28));
datejTextField.setBounds(new Rectangle(82, 102, 354, 28));
datejTextField.addActionListener(new Panel6_datejTextField_actionAdapter(this));
jLabel4.setFont(new java.awt.Font("华文行楷", Font.BOLD, 15));
jLabel4.setOpaque(false);
jLabel4.setText("时间:");
jLabel4.setBounds(new Rectangle(9, 102, 61, 25));
Panel5.setBounds(new Rectangle(7, 176, 435, 206));
Panel5.setLayout(overlayLayout21);
this.add(mailFromjTextField, null);
this.add(mailTojTextField, null);
this.add(subjectjTextField, null);
this.add(datejTextField, null);
this.add(jLabel4, null);
this.add(jLabel3, null);
this.add(jLabel2, null);
this.add(jLabel1, null);
this.add(Panel5, null);
Panel5.add(jScrollPane1, null);
jScrollPane1.getViewport().add(contentjTextArea, null);
this.setSize(new Dimension(450, 400));
Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize=this.getSize();
this.setLocation(screenSize.width/2-frameSize.width/2,
screenSize.height/2-frameSize.height/2);
}
public void mailFromjTextField_actionPerformed(ActionEvent e) {
}
public void datejTextField_actionPerformed(ActionEvent e) {
}
}
class Panel6_datejTextField_actionAdapter
implements ActionListener {
private Panel6 adaptee;
Panel6_datejTextField_actionAdapter(Panel6 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.datejTextField_actionPerformed(e);
}
}
class Panel6_mailFromjTextField_actionAdapter
implements ActionListener {
private Panel6 adaptee;
Panel6_mailFromjTextField_actionAdapter(Panel6 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.mailFromjTextField_actionPerformed(e);
}
}
以上是关于基于JAVA的邮件客户端的设计和实现的主要内容,如果未能解决你的问题,请参考以下文章