1.实验要求.
- 编写图形用户界面,实现邮件客户端软件的设计与开发。用实际的邮箱账号密码进行登录。
- 客户端要求可以完成邮件编辑。
- 客户端要求可以配置与标准邮件服务器的连接。
- 客户端可以发送邮件,并可以粘贴附件。
- 客户端可以接受并且下载邮件、删除邮件。
- 选择一特定的邮件服务器建立邮件账户,编程实现与服务器的通信建立、利用SMTP协议完成邮件发送,利用POP3完成邮件接收。
2.实验平台及语言.
实验选择语言为Java,开发平台为Eclipse IDE for Enterprise Java Developers.
Version: 2019-06 (4.12.0)
3.项目完整代码.
JavaMail编程实现邮件客户端InLook.
4.设计思路.
- 这个实验中,我们是需要使用实际的邮箱账号进行登录的,我们设计的客户端需要建立到该类型邮箱的服务器的连接。本次项目中,我们选择的是网易公司的163邮箱作为服务器端,对应地进行第三方邮箱客户端的开发。由于我们需要从自己的电脑连接到163邮箱的服务器,然后完成依赖于SMTP协议的邮件发送操作和依赖于POP3协议的邮件读取操作,所以我们首先要打开163邮箱中的POP3/SMTP服务。
上图是网易163邮箱中打开POP3/IMAP协议的流程,打开后我们会获得一个授权码。因为出于安全考虑,所以在第三方的邮箱客户端登录时,我们并不是直接输入密码,而是输入这个授权码。服务器根据账号和授权码也能够区分出我们是谁。 - 服务器端并不需要我们去考虑,说实话一个人也很难考虑这件事。我们只需要使用已经存在的服务器端。本项目中使用的网易163邮箱,对应于SMTP以及POP3的服务器地址分别为
smtp.163.com
pop.163.com
- 具体的客户端设计,我们平时也见到了不少邮箱的登录界面以及完成登录之后的主界面,本项目也是参照这些常见的模式进行设计的。我们的思路是从登录界面到主界面,再到发件箱界面以及收件箱界面一层一层地进行设计,并且在每一层地界面设计后,进行功能的实现和绑定。Java-awt和Java-Swing自然不可缺少,但我们本项目开发的主要武器,还是Java为邮件开发专门提供的JavaMail库。
- JavaMail包是我们本次开发中一个很重要的包,关于Eclipse中导入JavaMail的问题,可以阅读《Eclipse项目导入javax.mail(Java Mail 1.6.2 Final Release)》。JavaMail中的API可以分为三种类型:创建和解析邮件、发送邮件、接收邮件。虽然JavaMail中的class数量众多,但我们在开发过程中,只需要对于四个核心类眼熟即可,剩下的工作都可以在使用时再查询具体的用法。这四个核心类是:Message、Transport、Store和Session.
- Message:javax.mail.Message 是创建和解析邮件的核心 API,并且它是一个抽象类,我们通常使用的是其扩展类MimeMessage。Mime代表的是一个互联网标准,全称是Multipurpose Internet Mail Extensions,它扩展了电子邮件的标准,使得我们不再是仅仅能传送文本消息,而让视频、音频、文件等消息的传递成为了可能。MimeMessage的实例化对象表示了一封邮件,当我们的客户端程序要发送一封邮件时,首先使用JavaMail中创建邮件的API实例化一个封装了邮件数据的Message对象,而后将其传递给发送邮件的API——Transport类进行发送。客户端接收邮件时,接收邮件的API将收到的邮件数据也封装在一个Message对象中,而后通过解析邮件API获得其中的内容。
- Transport:javax.mail.Transport是发送邮件的核心类,它的实例化对象表示了某种邮件传输协议(例如最常见的SMTP协议)的传输对象。当我们需要发送邮件时,将待发送的Message对象交付给Transport对象后,调用Transport对象的发送方法,就能够实现将Message对象发送给指定的邮件服务器(例如前面说到的smtp.163.com)。
- Store:javax.mail.Store是接受邮寄的核心类,和Transport对应地,它的实例化对象表示了某种邮件接收协议(例如POP3协议)的接收对象。当客户端接收邮件时,只需要通过Store对象调用其接受方法,就能够从指定的邮件服务器(例如前面说到的pop.163.com)中获得邮件数据,后续再将其封装在Message对象中。
- Session:session是会话的意思,javax.mail.Session是定义整个客户端程序的环境信息以及收集客户端与邮件服务器建立网络连接的会话信息的类,例如邮件服务器的主机名、端口号、采用的邮件发送和接收协议等。Session类的实例对象根据这些信息来创建Transport和Store类的实例对象,以及为创建Message类的对象时提供信息支持。
5.代码细节.
ClientLauncher.
ClientLauncher是整个项目的启动类,并没有什么内容,其完整的代码如下:
public class ClientLauncher
{public static void main(String[] args) {JFrame.setDefaultLookAndFeelDecorated(true);JDialog.setDefaultLookAndFeelDecorated(true);try{String LookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();UIManager.setLookAndFeel(LookAndFeel);}catch(Exception e){e.printStackTrace();}new ClientLogin();}
}
不能看出,当中只做了两件事:1、设置整个界面的显示风格为CrossPlatform,这是一种Java特有的风格,不依赖于具体的操作系统,所以具有了跨平台的显示效果;2、调出了ClientLogin的界面。最后关于Java界面显示风格的问题,有兴趣的可以参看《Java界面观感LookAndFeel》.
ClientLogin.
ClientLauncher的最后一句代码创建了一个ClientLogin对象,ClientLogin的构造器很简单,Initialize()方法中负责设计界面以及绑定各种功能到界面上的控件中,而后setVisible()方法让界面可以被看见。
public ClientLogin()
{Initialize();setVisible(true);
}
ClientLogin的最终GUI效果展示如下:
ClientLogin的界面设计很简单,并没有什么特殊控件的使用,仅仅限于JLabel、JTextField和JButton这三种控件的使用。需要注意的几个界面设计的问题如下:
图片的插入.
- ClientLogin最上面这种带有’InLook’字样的图片实际上是作为JLabel插入的。我们将图片放在一个Icon对象中,而后基于这一Icon对象构造一个JLabel,就能够得到这样的效果。
//Create a Icon.
Icon Back = new ImageIcon("D:\\Eclipse_Workspace\\InLook.png");//Create a JLabel based on Icon 'Back'.
JLabel BackLabel = new JLabel(Back);//Set JLabel 'BackLabel' preferred size.
BackLabel.setPreferredSize(new Dimension(400,200));
带有提示性文字的边框效果.
- 上述GUI中,待输入部分的外围,有一圈很明显的,带着’Login Mail’文字的边框效果。这是JavaBorder类中的一种效果,这种蚀刻效果的边框叫做EtchedBorder,我们基于这样的边框风格,可以在其上构造带有Title的TitledBorder,其代码如下(关于更多边框风格的信息,可以参看这篇文章):
Border border=BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
MainLoginPanel.setBorder(BorderFactory.createTitledBorder(border,"Login"+ "Mail",TitledBorder.CENTER,TitledBorder.TOP));
设置背景色.
- 无法通过直接调用setBackground(Color)来实现,虽然调用这一方法确实设置了背景色,但你却无法看到它,因为呈现出来的是contentPane的背景色。问题的关键在于,JComponent控件中的Opaque属性默认是false的,Opaque意为不透明,该属性为false也就意味着这一控件透明,所以最终的GUI会透过该控件而显示出底层的颜色。关于Java中的Color类型,我们可以使用Java预定义的值,例如Color.BLUE、Color.BLACK,也可以向上述代码中,通过RGB值来创建一个Color实例。至于如何查看某处颜色的RGB值,可以参看图片任意点的RGB值。
JPanel MainLoginPanel=new JPanel();
MainLoginPanel.setOpaque(true);
MainLoginPanel.setBackground(new Color(179, 220, 241));
设置界面上的字体.
- 示例代码以JLabel为例,实际上很多控件都可以通过setFonts()方法来进行字体更改。至于自己的电脑上已经安装了哪些字体,以Win10为例,可以在
C:\Windows\Fonts
文件夹中查看。
final Font myFont = new Font("Arial Rounded MT Bold",Font.BOLD,18);
Account_IN = new JTextField();
Account_IN.setFont(myFont);
JButton的事件监听器绑定.
- 这是GUI程序中很常见的一种操作。通过addActionListener()方法,我们可以将一个"动作"绑定到一个按钮上,当这个按钮被点击时,就执行绑定到上面的动作。其中关于匿名内部类的语法,就不再赘述。
RegisterButton.addActionListener(new ActionListener()
{@Overridepublic void actionPerformed(ActionEvent e) {new ClientRegister();}
});
★设计时的纰漏.
- 在ClientLogin界面输入了账号和授权码(为什么是授权码而不是实际的密码,前面已经说过)之后,点击【Enter】按钮会直接进入主界面ClientMainPage而不进行正确性的验证,而只是进行一些简单的检查,例如完全不符合邮箱账户规范的用户就会被拒绝进入。如果用户输入的邮箱账号(形式上正确)和授权码是错误的,会在进入ClientMainPage时给出异常信息。根本原因是在ClientLogin中没有进行从本地客户端到网易邮箱服务器的连接,但由于后面的设计已经完成了,再整改这里的验证会很麻烦,而且在这里建立到服务器的连接并完成账号的验证,会很费时间(已经尝试过了),不过好处是后续进行邮件发送和接收时可以使用这里的连接。
ClientMainPage.
用户输入了正确的邮箱账号和授权码之后,ClientLogin会创建一个ClientMainPage并对自己调用dispose()方法来释放自己。ClientMainPage页面上提供了到发件箱OutBox和收件箱InBox的入口,还包括一些简单的页面设计,其最终的GUI效果如下所示:
JSplitPane分割窗格的使用.
创建图标JButton.
创建计时器.
- 计时器是指整个GUI界面最下方显示日期的那部分,它会显示此时此刻真实的日期。计时器的创建利用了Java中的Timer类,我们首先创建一个JLabel作为时间显示的载体,而后创建一个Timer执行计时的任务,这个任务就是定时(比如说1000ms)地刷新JLabel上的显示内容,从而造成一种时间动态变化的效果。关于Timer中scheduleAtFixedRate()方法的详细讲述,可以看这篇文章。
//Create JLael 'TimeLabel'.
final JLabel TimeLabel = new JLabel("",SwingConstants.RIGHT);//Create a task for timer.
TimerTask thisTask = new TimerTask()
{DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");@Overridepublic void run() {TimeLabel.setText("Welcome, and now is "+dateFormat.format(new Date()));TimeLabel.setFont(myFont);}};//Timer conduct task at 0ms delay and 1000ms period.
new Timer().scheduleAtFixedRate(thisTask, 0, 1000);
LookAhead.
当我们在ClientMainPage中点击OutBox按钮时,就会进入发件箱界面;相应地,点击InBox按钮就会进入收件箱界面,同时ClientMainPage还会得到保留。在后续的JavaMail编程实现邮件客户端-OutBox & InBox中,会详细介绍收件箱与发件箱的细节。