JavaMail是API 是一个标准的Java扩展,它是J2EE的范畴,在J2EE开发过程中可能会需要用到这个API。在学习JavaMail之前,有必须要对现在的互联网的邮件协议进行有个大体的了解。

邮件协议

在Internet中,常用的邮件操作相关的协议有3个—SMTP、POP、IMAP。

简单邮件传输协议(simple mail transferprotocol,SMTP),这个协议是邮件服务器之间相互发送邮件的协议,也是客户端利用该协议向邮件服务器端发送邮件的协议。一般一个邮件首先会被传送到某一个邮件服务器,再被邮件服务器分发到一个或多个目标邮件服务器。

邮局协议第3版(postoffice protocol version 3,POP3),协议主要用于从邮件服务器检索以得到新的邮件,大量的客户机从邮件服务器接收邮件就是使用POP3协议。

因特网消息访问协议(internet messager accessprotocol,IMAP),该协议比POP3功能更加强大,它可在接收邮件时,把邮件保存在邮件服务器中,既可在服务器中保留邮件也可把邮件下载

安装与配置JavaMail

由于JavaMail是一个扩展的部分,要进行发送接收邮件,需要两个包:

一个是JavaMail,这个包含了对SMTP、POP3、IMAP提供了支持,封装了电子邮件功能中的邮件对象、发送功能、身份认证、接收等。当前最新的版本是1.5

一个是JAF(JavaBeans Activation Framework),主要用来描述和显示邮件中的相关内容的,当前最新的版本是1.1.1

  具体所需要的包,可以在本文的附件中直接下载。

邮件发送与接收

JavaMail包中的类比较多,主要用到的有会话类、地址类、邮件类、邮件发送类、邮件接收类和邮件文件夹类这些常用的类。

会话类(Session),主要用来创建邮件对象、实现邮件对象中数据的封装并可指定邮件服务器认证的客户端属性。它表示程序与某一个邮件服务器即将建立通信,在建立的过程可以进行口令认证。

地址类(Address),这个地址类主要是表示邮件发送人和邮件接收人的地址,一般主要用的是InternetAddress。

邮件类(Message),邮件消息的主要类,它包含了邮件中的所有部分,继承自一个接口Part,一般在使用的过程中直接是利用它的子类MimeMessage

邮件发送类(Transport),一般是从一个会话中获取一个邮件发送类的实例,将已经写好的邮件利用SMTP协议发送到指定的邮件服务器,在发送的过程中,首先根据指定口令连接到邮件服务器,再发送邮件。

邮件接收类(Store),这个其实就是邮件服务器中的存储库,里面放着所有的邮件文件夹

邮件文件夹类(Folder),该文件夹就是消息的具体所在文件夹,默认的邮件均在INBOX文件中。

发送邮件

基本步骤:

1 利用Properties来设置Session,一般主要设置两个mail.smtp.host和mail.smtp.auth,第一个主要是设置邮件服务器名,第二个是设置口令true或者false

2 利用Session.getInstance(Properties)启动一个与邮件服务器的连接

3 根据获取的Session来传建一个消息Message

4 定义消息的发信人地址InternetAddress和消息的收信人地址。

5 设置消息发送的主题和内容

6 利用Message.saveChanges()来存储填写的邮件信息

7 根据Session.getTransport("smtp")获取邮件发送类

8 利用发送人的用户名和密码连接到指定的邮件服务器

9 将该消息发送

注意:发送消息最重要的是要正确的找到发送消息的邮件服务器名,至于收信人的邮箱无所谓,可以是任意正确的邮件,譬如发送人是163邮件,可以发送给搜狐邮箱,新浪邮箱,QQ邮箱。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package whut.mailsender;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import whut.mailreceiver.MailAuthenticator;
public class SimpleSMTPSender
{
    public static void main(String[]
args) {
        try{
            Properties
props=
new Properties();
            //传递一个邮件服务器名smtp.163.com
            //mail.smtp.host代表是发信人所在的邮箱服务器名
            props.put("mail.smtp.host""smtp.163.com");
            props.put("mail.smtp.auth"true);
            //对于发送邮件,只需要保证发送人所在的邮件服务器正确打开就可以了
            //收信人的邮箱可以是任意地址,如@163.com,@qq.com,@126.com
                                
            //创建一个程序与邮件服务器的通信
            Session
mailConnection=Session.getInstance(props,
null);
            Message
msg=
new MimeMessage(mailConnection);
                                
            //创建一个要输入用户名和指令的
            //Session
mailConnection=Session.getInstance(props,new MailAuthenticator());
                                
                                
            //设置发送人和接受人
            Address
sender=
new InternetAddress("yyyy@163.com");
            Address
receiver=
new InternetAddress("xxx@163.com");
                                
            /*
             *
群发邮件的方法
             *
StringBuffer buffer=new StringBuffer();
             *
buffer.append("11@163.com,")
             *
buffer.append("22@163.com")
             *
String all=buffer.toString();
             *
Address[] allre=InternetAddress.parse(all);
             *
msg.setRecipient(Message.RecipientType.TO, allre);
             */
            msg.setFrom(sender);
            msg.setRecipient(Message.RecipientType.TO,
receiver);
            msg.setSubject("You
must comply"
);
                                
            //msg.setContent("Hello",
"text/plain");
                                
                                
            //下面是模拟发送带附件的邮件
            //新建一个MimeMultipart对象用来存放多个BodyPart对象
            Multipart
mtp=
new MimeMultipart();
            //------设置信件文本内容------
            //新建一个存放信件内容的BodyPart对象
            BodyPart
mdp=
new MimeBodyPart();
            //给BodyPart对象设置内容和格式/编码方式
            mdp.setContent("hello","text/html;charset=gb2312");
            //将含有信件内容的BodyPart加入到MimeMultipart对象中
            mtp.addBodyPart(mdp);
                                
            //设置信件的附件(用本地机上的文件作为附件)
            mdp=new MimeBodyPart();
            FileDataSource
fds=
new FileDataSource("f:/webservice.doc");
            DataHandler
dh=
new DataHandler(fds);
            mdp.setFileName("webservice.doc");//可以和原文件名不一致
            mdp.setDataHandler(dh);
            mtp.addBodyPart(mdp);
            //把mtp作为消息对象的内容
            msg.setContent(mtp);
                                
            //以上为发送带附件的方式
            //先进行存储邮件
            msg.saveChanges();
                                
            Transport
trans=mailConnection.getTransport(
"smtp");
            String
username=
"yyyy@163.com";
            String
pw=
"";
            //邮件服务器名,用户名,密码
            trans.connect("smtp.163.com",
username,  pw);
            trans.sendMessage(msg,
msg.getAllRecipients());
            trans.close();
        }catch(Exception
e)
        {
            System.err.println(e);
        }
        finally{
            System.exit(0);
        }
    }
}

接受邮件

基本步骤:

1 利用Properties创建一个属性,不需要设置任何属性,之间传递Session使用

2 Session.getDefaultInstance()获取一个邮件会话

3 使用该会话向某种提供者请求一个存储库,ss.getStore("pop3");获取一个Store

4 存储库向指定的邮件服务器建立连接

5 通过getFolder("INBOX"),获取该存储库中INBOX文件夹

6 打开INBOX文件夹

7 消息处理

8 关闭文件夹

9 关闭存储库

注意:从服务器返回的邮件有可能在发送者或者接受者出现中文乱码,这里进行了乱码处理

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package whut.mailreceiver;
import java.io.InputStreamReader;
import java.io.Reader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
//利用POP3来读取邮件
//主要用来检测消息Message的基本信息,如发送者,收信者,时间
public class POP3Client
{
    public static void main(String[]
args) {
        Properties
props = System.getProperties();
        String
host = 
"pop3.163.com";
        String
username = 
"22222222@163.com";
        String
password = 
"312313121";
        String
provider = 
"pop3";
        try {
            //
连接到POP3服务器
            Session
ss = Session.getDefaultInstance(props, 
null);
            //
向回话"请求"一个某种提供者的存储库,是一个POP3提供者
            Store
store = ss.getStore(provider);
            //
连接存储库,从而可以打开存储库中的文件夹,此时是面向IMAP的
            store.connect(host,
username, password);
            //
打开文件夹,此时是关闭的,只能对其进行删除或重命名,无法获取关闭文件夹的信息
            //
从存储库的默认文件夹INBOX中读取邮件
            Folder
inbox = store.getFolder(
"INBOX");
            if (inbox
== 
null)
{
                System.out.println("NO
INBOX"
);
                System.exit(1);
            }
            //
打开文件夹,读取信息
            inbox.open(Folder.READ_ONLY);
            System.out.println("TOTAL
EMAIL:"
 +
inbox.getMessageCount());
            //
获取邮件服务器中的邮件
            Message[]
messages = inbox.getMessages();
            for (int i
0;
i < messages.length; i++) {
                System.out.println("------------Message--" +
(i + 
1)
                        "------------");
                //
解析地址为字符串
                String
from = InternetAddress.toString(messages[i].getFrom());
                if (from
!= 
null)
{
                    String
cin = getChineseFrom(from);
                    System.out.println("From:" +
cin);
                }
                String
replyTo = InternetAddress.toString(messages[i]
                        .getReplyTo());
                if (replyTo
!= 
null)
                    {
                    String
rest = getChineseFrom(replyTo);
                    System.out.println("Reply
To"
 +
rest);
                    }
                String
to = InternetAddress.toString(messages[i]
                        .getRecipients(Message.RecipientType.TO));
                if (to
!= 
null)
{
                    String
tos = getChineseFrom(to);
                    System.out.println("To:" +
tos);
                }
                String
subject = messages[i].getSubject();
                if (subject
!= 
null)
                    System.out.println("Subject:" +
subject);
                SimpleDateFormat
sdf = 
new SimpleDateFormat(
                        "yyyy-MM-dd
HH:mm:ss"
);
                Date
sent = messages[i].getSentDate();
                if (sent
!= 
null)
                    System.out.println("Sent
Date:"
 +
sdf.format(sent));
                Date
ress = messages[i].getReceivedDate();
                if (ress
!= 
null)
                    System.out.println("Receive
Date:"
 +
sdf.format(ress));
                //
显示消息的所有首部信息
                //
Enumeration headers=messages[i].getAllHeaders();
                //
while(headers.hasMoreElements())
                //
{
                //
Header h=(Header)headers.nextElement();
                //
String res=h.getName();
                //
String val=h.getValue();
                //
System.out.println(res+":"+val);
                //
}
                //
System.out.println();
                //
读取消息主题部分
                //
Object content=messages[i].getContent();
                //
System.out.println(content);
                //
根据指定的编码格式读出内容
                //
Reader read=new
                //
InputStreamReader(messages[i].getInputStream());
                //
int a=0;
                //
while((a=read.read())!=-1)
                //
{
                //
System.out.print((char)a);
                //
}
                //
获取该消息的类型
                //
String type=messages[i].getContentType();
                //
String
                //
sender=InternetAddress.toString(messages[i].getFrom());
                //
System.out.println("Sender:"+sender);
                //
System.out.println("Content-type:"+type);
            }
            //
关闭连接,但不删除服务器上的消息
            //
false代表不是删除
            inbox.close(false);
            store.close();
        catch (Exception
e) {
            System.err.println(e);
        }
    }
    //
解决中文乱码问题
    public static String
getChineseFrom(String res) {
        String
from = res;
        try {
            if (from.startsWith("=?GB")
|| from.startsWith(
"=?gb")
                    ||
from.startsWith(
"=?UTF"))
{
                from
= MimeUtility.decodeText(from);
            else {
                from
new String(from.getBytes("ISO8859_1"), "GBK");
            }
        catch (Exception
e) {
            e.printStackTrace();
        }
        return from;
    }
}

一般在读取邮件的时候会有个口令验证,可以在访问的过程中设置用于用户口令输入提示框:此时要修改一下Session的获取方法,传递一个继承了Authenticator,连接到POP3服务器,当提供者需要用户名和密码的时候,则会回调Authenticator的子类的getPasswordAuthentication必,同时须在connect中口令字段为null才能行

Session ss=Session.getDefaultInstance(props, new MailAuthenticator());

//向回话请求一个某种提供者的存储库,是一个POP3提供者

Store store=ss.getStore(provider);

//连接存储库,从而可以打开存储库中的文件夹,此时是面向IMAP的store.connect(host, null, null);

口令弹出框代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package whut.mailreceiver;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
//口令验证
public class MailAuthenticator extends Authenticator
{
    private JDialog
passwordDialog=
new JDialog(new JFrame(),true);
    private JLabel
mainLabel=
new JLabel("Please
enter your user name and password:"
);
    private JLabel
userLabel=
new JLabel("User
name:"
);
    private JLabel
passwordLabel=
new JLabel("Password:");
    private JTextField
usernameField=
new JTextField(20);
    private JPasswordField
passwordField=
new JPasswordField(20);
    private JButton
okButton=
new JButton("OK");
    public MailAuthenticator()
    {
        this("");
    }
                                                                                                                                                                                                                                                                                                                                                                                                     
    public MailAuthenticator(String
username)
    {
        Container
pane=passwordDialog.getContentPane();
        pane.setLayout(new GridLayout(4,1));
        pane.add(mainLabel);
                                                                                                                                                                                                                                                                                                                                                                                                         
        JPanel
p2=
new JPanel();
        p2.add(userLabel);
        p2.add(usernameField);
        pane.add(p2);
                                                                                                                                                                                                                                                                                                                                                                                                         
        JPanel
p3=
new JPanel();
        p3.add(passwordLabel);
        p3.add(passwordField);
        pane.add(p3);
        JPanel
p4=
new JPanel();
        p4.add(okButton);
        pane.add(p4);
                                                                                                                                                                                                                                                                                                                                                                                                         
        passwordDialog.setSize(400200);
                                                                                                                                                                                                                                                                                                                                                                                                         
        ActionListener
al=
new HideDialog();
        okButton.addActionListener(al);
        usernameField.addActionListener(al);
        passwordField.addActionListener(al);
    }
                                                                                                                                                                                                                                                                                                                                                                                                     
    class HideDialog implements ActionListener
    {
        public void actionPerformed(ActionEvent
e)
        {
            passwordDialog.hide();
        }
    }
                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                     
    @Override
    protected PasswordAuthentication
getPasswordAuthentication() {
        //
TODO Auto-generated method stub
        passwordDialog.show();
        //getPassword是返回的字符数组
        String 
username=usernameField.getText();
        String
password=
new String(passwordField.getPassword());
        passwordField.setText("");
        return new PasswordAuthentication(username,password);
    }
}

邮件传输中的几个类说明

Addres类,一般直接使用它的子类InternetAddress邮箱的地址,有两个特别重要的方法toString(),y用于将地址数组转换为字符串,并且多个地址以逗号隔开,parse()用于将以逗号隔开的地址解析为地址数组,这个可以为群发邮件用。

URLName类,这个目的是为了构造一个不需要该模式的协议处理器,它不会尝试连接,可以用于方便的标识文件夹和非标准的URL的存储库

Message类,主要是消息的抽象类,一般使用其子类MimeMessage,可以通过它来获取邮件的发送者,接受者,时间,主题,内容等邮件首部,查看邮件查收情况。

Part接口,一般包括了部分属性的方法、首部的方法、和内容的方法。实际运用中都是通过它的子类来调用的,可以根据属性来判断一个邮件是否含有附件。利用getAllHeaders()获得邮件的所有首部名和值,它返回的是Enumeration。

查看邮件的内容,查看MIME内容的类型是getContentType(),如返回"text/plain;charset="GBK",

一般通过getContent()来查看返回具体的内容,这里利用了JAF来自动的调整类型为java可识别的类型,当是text/plain的时候,返回是String,内容是多部分的时候,返回的是Multipart对象。如果是其他JAF也会将其转换为Java适当的对象。如果类型不能识别,则返回一个InputStream。

写入邮件的内容,一般文本型直接调用setText();也可以使用setContent(string,chartype);当要发送多个部分的时候,就需要setContent(Multipart p);每一个部分必须是MimeBodyPart,然后将其添加到MimeMultipart.在邮件的传输过程中,如果想要传输文件的话,必须将数据包装到BodyPart中,然后再添加到Multipart
中。

Folder文件,一般都是通过Session、Store或另一个Folder获得,一般获取的文件夹并不确保一定存在,要利用exists()判断。对于文件夹的一些操作必须要注意,检索和获取文件夹信息,必须要打开文件夹上才能操作。删除或者重命名文件夹,只能在文件夹关闭的时候完成。

题外:

国内常见的几个免费邮件服务器名如下:

网易免费邮箱:发送服务器:smtp.163.com     接收服务器:pop.163.com

新浪免费邮箱:发送服务器:smtp.sina.com.cn 接收服务器:pop3.sina.com.cn

搜狐邮箱:发送服务器:smtp.sohu.com        接收服务器:pop3.sohu.com

常见乱码处理方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package whut.mailsender;
import javax.mail.Part;
import javax.mail.internet.MimeUtility;
import sun.misc.BASE64Decoder;
public class StringUtil
{
       
    //发信人,收信人,回执人邮件中有中文处理乱码,res为获取的地址
    //http默认的编码方式为ISO8859_1
    //对含有中文的发送地址,使用MimeUtility.decodeTex方法
    //对其他则把地址从ISO8859_1编码转换成gbk编码
    public static String
getChineseFrom(String res) {
        String
from = res;
        try {
            if (from.startsWith("=?GB")
|| from.startsWith(
"=?gb")
                    ||
from.startsWith(
"=?UTF"))
{
                from
= MimeUtility.decodeText(from);
            else {
                from
new String(from.getBytes("ISO8859_1"), "GBK");
            }
        catch (Exception
e) {
            e.printStackTrace();
        }
        return from;
    }
       
    //转换为GBK编码
    public static String
toChinese(String strvalue) {
        try {
            if (strvalue
== 
null)
                return null;
            else {
                strvalue
new String(strvalue.getBytes("ISO8859_1"), "GBK");
                return strvalue;
            }
        catch (Exception
e) {
            return null;
        }
    }
    //接收邮件时,获取某个邮件的中文附件名,出现乱码
    //对于用base64编码过的中文,则采用base64解码,
    //否则对附件名进行ISO8859_1到gbk的编码转换
    public static String
getFileChinese(Part part) 
throws Exception
{
        String
temp = part.getFileName();
//
part为Part实例
        if ((temp.startsWith("=?GBK?")
&& temp.endsWith(
"?="))
                ||
(temp.startsWith(
"=?gbk?b?")
&& temp.endsWith(
"?=")))
{
            temp
= StringUtil.getFromBASE64(temp.substring(
8,
temp.indexOf(
"?=")
1));
        else {
            temp
= StringUtil.toChinese(temp);
        }
        return temp;
    }
    public static String
getFromBASE64(String s) {
        if (s
== 
null)
            return null;
        BASE64Decoder
decoder = 
new BASE64Decoder();
        try {
            byte[]
b = decoder.decodeBuffer(s);
            return new String(b);
        catch (Exception
e) {
            return null;
        }
    }
}

本文出自 “在云端的追梦” 博客,请务必保留此出处http://computerdragon.blog.51cto.com/6235984/1197390

Java网络编程之JavaMail发送邮件和接受邮件的更多相关文章

  1. Java网络编程之TCP、UDP

    Java网络编程之TCP.UDP 2014-11-25 15:23 513人阅读 评论(0) 收藏 举报 分类: java基础及多线程(28) 版权声明:本文为博主原创文章,未经博主允许不得转载.   ...

  2. Java网络编程之UDP

    Java网络编程之UDP 一.C/S架构中UDP网络通信流程 ①创建DatagramSocket与DatagramPacket对象 ②建立发送端,接收端 ③建立数据包 ④调用Socket的发送.接收方 ...

  3. Java网络编程之URLConnection

    Java网络编程之URLConnecton 一.URLConnection简介 URLConnection是一个抽象类,表示指向URL指定资源的活动连接.URLConnection有两个不同但相关的用 ...

  4. Java网络编程之URL和URI

    Java网络编程之URL与URI 一.URL与URI简介 URI = Universal Resource Identifier 统一资源标志符 URL = Universal Resource Lo ...

  5. Java网络编程之InetAddress浅析

    Java网络编程之InetAddress浅析 一.InetAddress综述 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetA ...

  6. Java网络编程之TCP

    Java网络编程之TCP ​ TCP主要需要两个类:Socket和ServerSocket,Socket是客户端连接服务器时创建,参数需要指定服务器的ip和端口,ServerSocket是服务器端创建 ...

  7. java网络编程之TCP通讯

    java中的网络编程之TCP协议的详细介绍,以及如何使用,同时我在下面举2例说明如何搭配IO流进行操作, /* *TCP *建立连接,形成传输数据的通道: *在连接中进行大数据量传输: *通过三次握手 ...

  8. 使用JavaMail发送邮件和接受邮件

    转载:http://blog.csdn.net/zdp072/article/details/30977213 一. 为什么要学习JavaMail 为什么要学习JavaMail开发? 现在很多WEB应 ...

  9. 3.Java网络编程之IP

    前面两篇博文我们已经简单了解了IP.端口.协议以及两种参考模型,我们现在重新从程序角度来看下这个参考模型. 如果我们从事的是Web网站开发,那么我们应该知道HTML是一种超文本标记语言 (Hyper ...

  10. java网络编程之UDP通讯

    详细介绍了java中的网络通信机制,尤其是UDP协议,通过对UDP的基本使用进行举例说明如何使用UDP进行数据的发送接收,并举了两个小demo说明UDP的使用注意事项. UDP协议原理图解: UDP协 ...

随机推荐

  1. 最常用集合 - arraylist详解

    ArrayList介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外,其余跟Vector大致相同.每 ...

  2. Echarts + 低代码 :可视化如何赋能企业的创新之路?

    前言 数据驱动已经成为企业决策和业务优化的关键所在,在数字化时代,高效的数据分析与可视化呈现是实现智能决策的关键.利用低代码开发平台,企业可以快速构建满足业务需求的应用系统,实现对各类数据源的便捷接入 ...

  3. 开源问卷调查和考试系统 SurveyKing 安装和使用教程

    最近公司又要搞什么满意度调查了,我这个小菜鸟又要头疼了.上次用那个破系统,界面丑不说,功能还少得可怜,搞得我加班到半夜.这回非得找个好用的不可. 正发愁呢,突然想起来前两天同事小王推荐了一个叫 &qu ...

  4. 钉钉H5微应用本地开发调试记录

    准备工具: 手机(ios,安卓) 安卓手机可以用网易Mumu模拟器,下载一个移动版钉钉 钉钉开放文档 本地开发的话,可以去钉钉后台管理系统,将你的本地ip地址配置成应用的首页,比如 10.xx.xx. ...

  5. [JS设计模式]:鸭子类型与多态

    鸭子类型 编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言. 动态类型语言对变量类型的宽容给实际编码带来了很大的灵活性.由于无需进行类型检测,我们可以尝试调用任何对象的任 ...

  6. C++ const常量指针

    const常量指针 const是C++关键字,译为常量,const指针即为常量指针. 分为三类 指向const的指针 const指针 指向const的const指针 指向const的指针 表示指向区域 ...

  7. `std::string_view`(c++17) 和 `std::stringstream` 使用区别·

    std::string_view 和 std::stringstream 都是 C++ 中处理字符串的工具,但它们的设计目标和使用场景非常不同.我们可以通过几方面进行对比. 1. 设计目的和核心功能 ...

  8. Android Qcom USB Driver学习(六)

    眼图基础知识与详解 10分钟教会你看眼图 USB2.0 HUB眼图调试经验总结 一篇文章教你如何全面了解眼图测试! 预加重与去加重对眼图的影响 关于 USB 通信阻抗匹配的问题 硬件调试--眼图几个经 ...

  9. linux那些事之页迁移(page migratiom)

    Page migration 页迁移技术是内核中内存管理的一种比较重要的技术,最早该技术诞生于NUMA系统中(Page migration [LWN.net]),后续由于内存规整以及CMA和COW技术 ...

  10. 基于 Nginx 的大型互联网集群架构与实战方案

    1. Nginx 负载均衡基础配置 首先,搭建一个基础的 Nginx 负载均衡器,用于将流量分发到多个后端服务器上. 步骤 1.1:安装 Nginx 在每台要作为负载均衡器的服务器上,安装 Nginx ...