[Java核心技术] Java网络编程
目录
Java 核心技术读书笔记——Java网络编程
1 Java UDP编程
笔记
TCP:Transmission Control Protocol
- 传输控制协议,面向连接的协议
- 两台机器的可靠无差错的数据传输
- 双向字节流传递
UDP:User Datagram Protocol
- 用户数据报协议,面向无连接协议
- 不保证可靠的数据传输
- 速度快,也可以在较差网络下使用
- 计算机通讯:数据从一个IP的 port 出发(发送方),运输到 另外一个IP的 port(接收方)
- UDP:无连接无状态的通讯协议,
- 发送方发送消息,如果接收方刚好在目的地,则可以接受。如果 不在,那这个消息就丢失了
- 发送方也无法得知是否发送成功
- UDP 的好处就是简单,节省,经济
1.1 DatagramSocket 通讯的数据管道
send
和receive
方法- (可选,多网卡)绑定一个 IP 和 Port
1.2 DatagramPacket
- 集装箱:封装数据
- 地址标签:目的地 IP+Port
1.3 实例
- 接收消息
|
|
- 发送消息
|
|
2 TCP 编程
TCP协议:有链接、保证可靠的无误差通讯
- ① 服务器:创建一个
ServerSocket
,等待连接 - ② 客户机:创建一个
Socket
,连接到服务器 - ③ 服务器:
ServerSocket
接收到连接,创建一个Socket
和客户的Socket
建立专线连接,后续服务器和客户机的对话(这一对Socket
)会在一个单独的线程(服务器端)上运行 - ④ 服务器的
ServerSocket
继续等待连接,返回 ①
2.1 ServerSocket
: 服务器码头
- 需要绑定
port
- 如果有多块网卡,需要绑定一个IP地址
2.2 Socket
: 运输通道
- 客户端需要绑定服务器的地址和
Port
- 客户端往
Socket
输入流写入数据,送到服务端 - 客户端从
Socket
输出流取服务器端过来的数据 - 服务端反之亦然
2.3 相关规则
- 服务端等待响应时,处于阻塞状态
- 服务端可以同时响应多个客户端
- 服务端每接受一个客户端,就启动一个独立的线程与之对 应
- 客户端或者服务端都可以选择关闭这对Socket的通道
- 实例
- 服务端先启动,且一直保留
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
import java.net.*; import java.io.*; public class TcpServer { public static void main(String [] args) { try { ServerSocket ss=new ServerSocket(8001); //驻守在8001端口 Socket s=ss.accept(); //阻塞,等到有客户端连接上来 System.out.println("welcome to the java world"); InputStream ips=s.getInputStream(); //有人连上来,打开输入流 OutputStream ops=s.getOutputStream(); //打开输出流 //同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流 ops.write("Hello, Client!".getBytes()); //输出一句话给客户端 BufferedReader br = new BufferedReader(new InputStreamReader(ips)); //从客户端读取一句话 System.out.println("Client said: " + br.readLine()); ips.close(); ops.close(); s.close(); ss.close(); } catch(Exception e) { e.printStackTrace(); } } } /** * * * 输入:Hello Server * I want to send: Hello Server * Server said: Hello, Client! * * */
- 客户端后启动,可以先退出
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
import java.net.*; import java.io.*; public class TcpClient { public static void main(String[] args) { try { Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); //需要服务端先开启 //同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流 InputStream ips = s.getInputStream(); //开启通道的输入流 BufferedReader brNet = new BufferedReader(new InputStreamReader(ips)); OutputStream ops = s.getOutputStream(); //开启通道的输出流 DataOutputStream dos = new DataOutputStream(ops); BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in)); while (true) { String strWord = brKey.readLine(); if (strWord.equalsIgnoreCase("quit")) { break; } else { System.out.println("I want to send: " + strWord); dos.writeBytes(strWord + System.getProperty("line.separator")); System.out.println("Server said: " + brNet.readLine()); } } dos.close(); brNet.close(); brKey.close(); s.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * * welcome to the java world * Client said: Hello Server * * */
3 Java HTTP编程
HTTP
HTTP
- 超文本传输协议(HyperText Transfer Protocol)
- 用于从WWW(World Wide Web)服务器传输超文本到本地浏览 器的传输协议
- 1989年蒂姆•伯纳斯•李(Tim Berners Lee)提出了一种能让远隔两 地的研究者们共享知识的设想
- 借助多文档之间相互关联形成的超文本 (HyperText),连成可 相互参阅的 WWW
- 1990年问世,1997年发布版本1.1,2015年发布版本2.0
- 资源文件采用HTML编写,以URL形式对外提供
3.1 HTTP访问方式
GET
:从服务器获取资源到客户端POST
:从客户端向服务器发送数据PUT
:上传文件DELETE
:删除文件HEAD
:报文头部OPTIONS
:询问支持的方法TRACE
:追踪路径CONNECT
:用隧道协议连接代理
Java HTTP编程(java.net包)
-
支持模拟成浏览器的方式去访问网页
-
URL , Uniform Resource Locator,代表一个资源
-
URLConnection
- 获取资源的连接器
- 根据URL的o
penConnection()
方法获得URLConnection
connect
方法,建立和资源的联系通道getInputStream
方法,获取资源的内容
-
GET
实例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
import java.io.*; import java.net.*; import java.util.*; public class URLConnectionGetTest { public static void main(String[] args) { try { String urlName = "http://www.baidu.com"; URL url = new URL(urlName); URLConnection connection = url.openConnection(); // 建立连接通道 connection.connect(); // 打印http的头部信息 Map<String, List<String>> headers = connection.getHeaderFields(); for (Map.Entry<String, List<String>> entry : headers.entrySet()) { String key = entry.getKey(); for (String value : entry.getValue()) System.out.println(key + ": " + value); } // 输出将要收到的内容属性信息 System.out.println("----------"); System.out.println("getContentType: " + connection.getContentType()); System.out.println("getContentLength: " + connection.getContentLength()); System.out.println("getContentEncoding: " + connection.getContentEncoding()); System.out.println("getDate: " + connection.getDate()); System.out.println("getExpiration: " + connection.getExpiration()); System.out.println("getLastModifed: " + connection.getLastModified()); System.out.println("----------"); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); // 输出收到的内容 String line = ""; while((line=br.readLine()) != null) { System.out.println(line); } br.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * * null: HTTP/1.1 200 OK * Server: bfe * Content-Length: 2381 * Date: Tue, 01 Mar 2022 16:27:49 GMT * Content-Type: text/html * ---------- * getContentType: text/html * getContentLength: 2381 * getContentEncoding: null * getDate: 1646152069000 * getExpiration: 0 * getLastModifed: 0 * ---------- * <!DOCTYPE html> * ...... * * * */
-
POST
实例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
import java.io.*; import java.net.*; import java.nio.file.*; import java.util.*; public class URLConnectionPostTest { public static void main(String[] args) throws IOException { String urlString = "https://tools.usps.com/go/ZipLookupAction.action"; Object userAgent = "HTTPie/0.9.2"; Object redirects = "1"; CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL)); Map<String, String> params = new HashMap<String, String>(); params.put("tAddress", "1 Market Street"); params.put("tCity", "San Francisco"); params.put("sState", "CA"); String result = doPost(new URL(urlString), params, userAgent == null ? null : userAgent.toString(), redirects == null ? -1 : Integer.parseInt(redirects.toString())); System.out.println(result); } public static String doPost(URL url, Map<String, String> nameValuePairs, String userAgent, int redirects) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); if (userAgent != null) connection.setRequestProperty("User-Agent", userAgent); if (redirects >= 0) connection.setInstanceFollowRedirects(false); connection.setDoOutput(true); //输出请求的参数 try (PrintWriter out = new PrintWriter(connection.getOutputStream())) { boolean first = true; for (Map.Entry<String, String> pair : nameValuePairs.entrySet()) { //参数必须这样拼接 a=1&b=2&c=3 if (first) { first = false; } else { out.print('&'); } String name = pair.getKey(); String value = pair.getValue(); out.print(name); out.print('='); out.print(URLEncoder.encode(value, "UTF-8")); } } String encoding = connection.getContentEncoding(); if (encoding == null) { encoding = "UTF-8"; } if (redirects > 0) { int responseCode = connection.getResponseCode(); System.out.println("responseCode: " + responseCode); if (responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_SEE_OTHER) { String location = connection.getHeaderField("Location"); if (location != null) { URL base = connection.getURL(); connection.disconnect(); return doPost(new URL(base, location), nameValuePairs, userAgent, redirects - 1); } } } else if (redirects == 0) { throw new IOException("Too many redirects"); } //接下来获取html 内容 StringBuilder response = new StringBuilder(); try (Scanner in = new Scanner(connection.getInputStream(), encoding)) { while (in.hasNextLine()) { response.append(in.nextLine()); response.append("\n"); } } catch (IOException e) { InputStream err = connection.getErrorStream(); if (err == null) throw e; try (Scanner in = new Scanner(err)) { response.append(in.nextLine()); response.append("\n"); } } return response.toString(); } } /** * * * responseCode: 200 * <html lang="en"> * ...... * */
4 HttpClient
HttpClient
HttpClient
包含一下两个包:
JDK HTTP Client
(JDK自带,从9开始)Apache HttpComponents的HttpClient
(Apache出品)
4.1 JDK HttpClient
- JDK 9 新增,JDK10更新,JDK11正式发布
- 收录在
java.net.http
包 - 取代
URLConnection
- 支持HTTP/1.1和HTTP/2
- 实现大部分HTTP方法
主要类
HttpClient
HttpRequest
HttpResponse
JDK HttpClient GET 实例
|
|
JDK HttpClient POST 实例
|
|
4.2 HttpComponents
hc.apache.org, Apache
出品
- 从
HttpClient
进化而来 - 是一个集成的
Java HTTP
工具包- 实现所有HTTP方法:
get/post/put/delete
- 支持自动转向
- 支持https协议
- 支持代理服务器等
- 实现所有HTTP方法:
HttpComponents GET 实例
|
|
HttpComponents POST 实例
|
|
5 Java NIO 编程
- 传统的TCP和UDP通讯属于
Blocking I/O
- NIO(
Non-Blocking I/O
,非阻塞I/O,又名 New I/O)提供非阻塞通讯等方式,避免同步I/O通讯效率过低,一个线程可以管理多个连接,减少线程多的压力,不是真异步。
笔记
- 并发编程的同步:是指多个线程需要以一种同步的方式来访问某一个数据结构。这里同步的反义词是非同步的,即线程不安全的。
- 网络通讯的同步:是指客户端和服务端直接的通讯等待方式。这里的同步的反义词是异步,即无需等待另一端操作完成。
- JDK 1.4引入,1.7升级 NIO 2.0 (包括了AIO)
- 主要在
java.nio
包中 - 主要类
Buffer
缓存区Channel
通道Selector
多路选择器
5.1 Buffer 缓冲区
Buffer 缓冲区:一个可以读写的内存区域
ByteBuffer
CharBuffer
DoubleBuffer
IntBuffer
LongBuffer
ShortBuffer
- 注意:
StringBuffer
不是 Buffer缓冲区
四个主要属性:
capacity
容量position
读写位置limit
界限mark
标记,用于重复一个读/写操作
5.3 Channel 通道
- 全双工的,支持读/写(而**
Stream
流是单向的**) - 支持异步读写
- 和
Buffer
配合,提高效率 ServerSocketChannel
服务器TCP Socket 接入通道,接收客户端SocketChannel
TCP Socket通道,可支持阻塞/非阻塞通讯DatagramChannel
UDP 通道FileChannel
文件通道
5.4 Selector多路选择器
- 每隔一段时间,不断轮询注册在其上的
Channel
- 如果有一个
Channel
有接入、读、写操作,就会被轮询出来 - 根据
SelectionKey
可以获取相应的Channel
,进行后续IO操作 - 避免过多的线程
SelectionKey
四种类型OP_CONNECT
OP_ACCEPT
OP_READ
OP_WRITE
5.5 实例
NioServer
|
|
NioClient
|
|
6 Java AIO 编程
- Asynchronous I/O, 异步I/O
- JDK 1.7引入,主要在java.nio包中
- 异步I/O,采用回调方法进行处理读写操作
6.1 主要类
AsynchronousServerSocketChannel
服务器接受请求通道bind
绑定在某一个端口accept
接受客户端请求
AsynchronousSocketChannel
Socket通讯通道read
读数据write
写数据
CompletionHandler
异步处理类completed
操作完成后异步调用方法failed
操作失败后异步调用方法
6.2 三种 I/O 的区别
BIO | NIO | AIO | |
---|---|---|---|
阻塞方式 | 阻塞 | 非阻塞 | 非阻塞 |
同步方式 | 同步 | 同步 | 异步 |
编程难度 | 简单 | 较难 | 困难 |
客户机/服务器线程对比 | 1:1 | N:1 | N:1 |
性能 | 低 | 高 | 高 |
6.3 实例
AioServer
|
|
AioClient
|
|
7 Netty 编程
- Netty, http://netty.io
- 最早由韩国 Trustin Lee 设计开发的,后来由 JBoss 接手开发,现在是独立的 Netty Project
- 一个非阻塞的客户端-服务端网络通讯框架
- 基于异步事件驱动模型
- 简化Java的 TCP 和 UDP 编程
- 支持 HTTP/2, SSL 等多种协议
- 支持多种数据格式,如 JSON 等
7.1 关键技术
7.1.1 通道 Channel
ServerSocketChannel
/NioServerSocketChannel
/…SocketChannel
/NioSocketChannel
7.1.2 事件 EventLoop
- 为每个通道定义一个
EventLoop
,处理所有的I/O事件 EventLoop
注册事件EventLoop
将事件派发给ChannelHandler
EventLoop
安排进一步操作
7.1.3 事件
- 事件按照数据流向进行分类
- 入站事件:连接激活/数据读取/……
- 出站事件:打开到远程连接/写数据/……
7.1.4 事件处理 ChannelHandler
Channel
通道发生数据或状态改变EventLoop
会将事件分类,并调用ChannelHandler
的回调函数- 程序员需要实现
ChannelHandler
内的回调函数 ChannelInboundHandler
/ChannelOutboundHandler
7.1.5 ChannelHandler工作模式:责任链
- 责任链模式:
- 将请求的接收者连成一条链
- 在链上传递请求,直到有一个接收者处理该请求
- 避免请求者和接收者的耦合
ChannelHandler
可以有多个,依次进行调用ChannelPipeline
作为容器,承载多个ChannelHandler
7.1.6 ByteBuf
- 强大的字节容器,提供丰富API进行操作
7.1.7 实例
- EchoServer
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
// EchoServer.java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import java.net.InetSocketAddress; public class EchoServer { public static void main(String[] args) throws Exception { int port = 8001; final EchoServerHandler serverHandler = new EchoServerHandler(); EventLoopGroup group = new NioEventLoopGroup(); try { //ServerBootstrap是netty中的一个服务器引导类 ServerBootstrap b = new ServerBootstrap(); b.group(group) .channel(NioServerSocketChannel.class) //设置通道类型 .localAddress(new InetSocketAddress(port)) //设置监听端口 .childHandler(new ChannelInitializer<SocketChannel>() { //初始化责任链 @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(serverHandler); //添加处理类 } }); ChannelFuture f = b.bind().sync(); //开启监听 if(f.isSuccess()){ System.out.println(EchoServer.class.getName() + " started and listening for connections on " + f.channel().localAddress()); } f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); } } } // EchoServerHandler.java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.CharsetUtil; public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg; String content = in.toString(CharsetUtil.UTF_8); System.out.println("Server received: " + content); ByteBuf out = ctx.alloc().buffer(1024); out.writeBytes((content + " 666").getBytes()); ctx.write(out); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) .addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } } /** * * * MOOC1808.EchoServer started and listening for connections on /0:0:0:0:0:0:0:0:8001 * Server received: Netty rocks! * * */
- EchoClient
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
// EchoClient.java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import java.net.InetSocketAddress; public class EchoClient { public static void main(String[] args) throws Exception { String host = "localhost"; int port = 8001; EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .remoteAddress(new InetSocketAddress(host, port)) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); } } } // EchoClientHandler.java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.CharsetUtil; public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override public void channelActive(ChannelHandlerContext ctx) { ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); } @Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) { System.out.println( "Client received: " + in.toString(CharsetUtil.UTF_8)); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } } /** * * * * Client received: Netty rocks! 666 * * * */
7.2 书籍推荐
- 《Netty 实战》,Norman Maurer 著,何品 译,人民邮电出版社,2017.
- 《Netty权威指南》,李林锋,电子工业出版社,2015
8 Java Mail 编程
8.1 Java Mail 服务器配置
- 邮件服务器支持
- 需要在邮件服务内设置,可以查看相关邮件帮助
- 需要知道pop服务器和smtp服务器信息
8.2 Java Mail 工具包
- javax.mail 包和javax.mail.internet 包
- https://javaee.github.io/javamail
- mvn dependency
1 2 3 4 5
<dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>
8.3 关键类
- Session: 邮件会话 和HttpSession不同
- Store: 邮件存储空间
- Folder: 邮件文件夹
- Message: 电子邮件
- Address: 邮件地址
- Transport: 发送协议类
8.4 实例
接收邮件
|
|
发送邮件
-
文本邮件
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
// messages/TextMessage.java package messages; import java.util.Date; import java.util.Properties; import javax.mail.Message; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.FileOutputStream; public class TextMessage { public static MimeMessage generate() throws Exception { String from = "ieblyang@qq.com "; // 发件人地址 String to = "ieblyang@163.com"; // 收件人地址 String subject = "test"; String body = "您好,这是来自一封ieblyang的测试邮件"; // 创建Session实例对象 Session session = Session.getDefaultInstance(new Properties()); // 创建MimeMessage实例对象 MimeMessage message = new MimeMessage(session); // 设置发件人 message.setFrom(new InternetAddress(from)); // 设置收件人 message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // 设置发送日期 message.setSentDate(new Date()); // 设置邮件主题 message.setSubject(subject); // 设置纯文本内容的邮件正文 message.setText(body); // 保存并生成最终的邮件内容 message.saveChanges(); // 把MimeMessage对象中的内容写入到文件中 //msg.writeTo(new FileOutputStream("e:/test.eml")); return message; } }
-
网页邮件
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
// messages/ package messages; import java.util.Date; import java.util.Properties; import javax.mail.Message; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.FileOutputStream; public class HtmlMessage { public static MimeMessage generate() throws Exception { String from = "ieblyang@qq.com "; // 发件人地址 String to = "ieblyang@163.com"; // 收件人地址 String subject = "多附件邮件"; //邮件主题 String body = "<a href=https://ieblyang.tech>" + "欢迎大家访问我的网站</a></br>"; // 创建Session实例对象 Session session = Session.getDefaultInstance(new Properties()); // 创建MimeMessage实例对象 MimeMessage message = new MimeMessage(session); // 设置发件人 message.setFrom(new InternetAddress(from)); // 设置收件人 message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // 设置发送日期 message.setSentDate(new Date()); // 设置邮件主题 message.setSubject(subject); // 设置HTML格式的邮件正文 message.setContent(body, "text/html;charset=gb2312"); // 保存并生成最终的邮件内容 message.saveChanges(); // 把MimeMessage对象中的内容写入到文件中 //msg.writeTo(new FileOutputStream("e:/HtmlMessage.eml")); return message; } }
-
附件邮件
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
// messages/ import java.io.FileOutputStream; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Message; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; public class AttachmentMessage { public static MimeMessage generate() throws Exception { String from = "ieblyang@qq.com "; // 发件人地址 String to = "ieblyang@163.com"; // 收件人地址 String subject = "多附件邮件"; //邮件主题 String body = "<a href=https://ieblyang.tech>" + "欢迎大家访问我的网站</a></br>"; // 创建Session实例对象 Session session = Session.getDefaultInstance(new Properties()); // 创建MimeMessage实例对象 MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress(from)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); message.setSubject(subject); //创建代表邮件正文和附件的各个MimeBodyPart对象 MimeBodyPart contentPart = createContent(body); MimeBodyPart attachPart1 = createAttachment("c:/temp/ieblyang1.jpg"); MimeBodyPart attachPart2 = createAttachment("c:/temp/ieblyang2.jpg"); //创建用于组合邮件正文和附件的MimeMultipart对象 MimeMultipart allMultipart = new MimeMultipart("mixed"); allMultipart.addBodyPart(contentPart); allMultipart.addBodyPart(attachPart1); allMultipart.addBodyPart(attachPart2); //设置整个邮件内容为最终组合出的MimeMultipart对象 message.setContent(allMultipart); message.saveChanges(); //message.writeTo(new FileOutputStream("e:/ComplexMessage.eml")); return message; } public static MimeBodyPart createContent(String body) throws Exception { MimeBodyPart htmlBodyPart = new MimeBodyPart(); htmlBodyPart.setContent(body,"text/html;charset=gb2312"); return htmlBodyPart; } public static MimeBodyPart createAttachment(String filename) throws Exception { //创建保存附件的MimeBodyPart对象,并加入附件内容和相应信息 MimeBodyPart attachPart = new MimeBodyPart(); FileDataSource fds = new FileDataSource(filename); attachPart.setDataHandler(new DataHandler(fds)); attachPart.setFileName(fds.getName()); return attachPart; } }
-
发送邮件
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
import javax.mail.*; import java.util.*; import messages.*; public class MailClientSend { private Session session; private Transport transport; private String username = "ieblyang@qq.com"; private String password = "1234567899"; private String smtpServer = "smtp.qq.com"; public void init()throws Exception { //设置属性 Properties props = new Properties(); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.class", "com.sun.mail.smtp.SMTPTransport"); props.put("mail.smtp.host", smtpServer); //设置发送邮件服务器 props.put("mail.smtp.port", "25"); props.put("mail.smtp.auth", "true"); //SMTP服务器需要身份验证 // 创建Session对象 session = Session.getInstance(props,new Authenticator(){ //验账账户 public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); session.setDebug(true); //输出跟踪日志 // 创建Transport对象 transport = session.getTransport(); } public void sendMessage()throws Exception{ //创建一个邮件 //Message msg = TextMessage.generate(); //Message msg = HtmlMessage.generate(); Message msg = AttachmentMessage.generate(); //发送邮件 transport.connect(); transport.sendMessage(msg, msg.getAllRecipients()); //打印结果 System.out.println("邮件已经成功发送"); } public void close()throws Exception { transport.close(); } public static void main(String[] args)throws Exception { MailClientSend client=new MailClientSend(); //初始化 client.init(); //发送邮件 client.sendMessage(); //关闭连接 client.close(); } }