java入坑之网络编程
一、 网络基础知识
1.1网卡

1.2IP地址
1.3端口

1.4保留IP
1.5网络协议
二、UDP 编程
2.1相关概念
计算机通讯:数据从一个IP的port出发(发送方),运输到另外一个IP的port(接收方)
UDP:无连接无状态的通讯协议,
-发送方发送消息,如果接收方刚好在目的地,则可以接受。如果不在,那这个消息就丢失了
-发送方也无法得知是否发送成功
-UDP的好处就是简单,节省,经济
2.2相关类
2.3实现代码
package org.example;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UdpRecv {public static void main(String[] args) throws Exception {// 创建 DatagramSocket 并绑定到端口 3000DatagramSocket ds = new DatagramSocket(3000);// 创建一个字节数组缓冲区来接收数据byte[] buf = new byte[1024];// 创建 DatagramPacket 用于接收数据DatagramPacket dp = new DatagramPacket(buf, 1024);System.out.println("UdpRecv:我在等待信息");// 接收来自发送者的数据,此处可能会抛出 IOExceptionds.receive(dp);System.out.println("UdpRecv:我接收到信息");// 解析接收到的数据并构建消息字符串String strRecv = new String(dp.getData(), 0, dp.getLength()) +" from " + dp.getAddress().getHostAddress() + ":" + dp.getPort();System.out.println(strRecv);// 休眠 1 秒Thread.sleep(1000);System.out.println("UdpRecv:我要发送信息");// 要发送的字符串消息String str = "hello world 222";// 创建 DatagramPacket 用于发送数据DatagramPacket dp2 = new DatagramPacket(str.getBytes(), str.length(),InetAddress.getByName("127.0.0.1"), dp.getPort());// 发送消息数据,此处可能会抛出 IOExceptionds.send(dp2);System.out.println("UdpRecv:我发送信息结束");// 关闭 DatagramSocketds.close();}
}
package org.example;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UdpSend {public static void main(String[] args) throws Exception {// 创建 DatagramSocket,不需要绑定到指定端口,系统会自动分配一个可用端口DatagramSocket ds = new DatagramSocket();// 要发送的字符串消息String str = "hello world";// 创建 DatagramPacket 用于发送数据DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(),InetAddress.getByName("127.0.0.1"), 3000);System.out.println("UdpSend: 我要发送信息");// 发送消息数据,此处可能会抛出 IOExceptionds.send(dp);System.out.println("UdpSend: 我发送信息结束");// 休眠 1 秒Thread.sleep(1000);// 创建一个字节数组缓冲区来接收数据byte[] buf = new byte[1024];// 创建 DatagramPacket 用于接收数据DatagramPacket dp2 = new DatagramPacket(buf, 1024);System.out.println("UdpSend: 我在等待信息");// 接收来自接收方的数据,此处可能会抛出 IOExceptionds.receive(dp2);System.out.println("UdpSend: 我接收到信息");// 解析接收到的数据并构建消息字符串String str2 = new String(dp2.getData(), 0, dp2.getLength()) +" from " + dp2.getAddress().getHostAddress() + ":" + dp2.getPort();System.out.println(str2);// 关闭 DatagramSocketds.close();}
}
UdpSend 类:
创建了一个 DatagramSocket 对象 ds,它用于发送UDP数据包。由于未指定端口,系统会自动分配一个可用的端口。
构建了要发送的字符串消息 str。
创建了一个 DatagramPacket 对象 dp,用于封装要发送的数据。
通过 ds.send(dp) 发送数据包到指定的目标主机 IP 地址和端口。
程序暂停 1 秒(Thread.sleep(1000)),然后准备接收来自接收者的数据。
创建一个字节数组缓冲区 buf 和一个用于接收数据的 DatagramPacket 对象 dp2。
使用 ds.receive(dp2) 接收来自接收者的数据。
解析接收到的数据,构建消息字符串 str2,包括发送者的 IP 地址和端口。
关闭 ds。
UdpRecv 类:
创建了一个 DatagramSocket 对象 ds,它用于接收UDP数据包,绑定到端口 3000。
创建了一个字节数组缓冲区 buf 和一个用于接收数据的 DatagramPacket 对象 dp。
使用 ds.receive(dp) 接收来自发送者的数据。
解析接收到的数据,构建消息字符串 strRecv,包括发送者的 IP 地址和端口。
程序暂停 1 秒(Thread.sleep(1000)),然后准备发送数据。
构建要发送的字符串消息 str。
创建一个用于发送数据的 DatagramPacket 对象 dp2,并发送数据包到之前发送者的 IP 地址和端口。
关闭 ds。
三、TCP 编程
3.1相关概念

3.2相关类

3.3实现代码
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServer {public static void main(String[] args) {try {// 创建服务器套接字,驻守在8001端口ServerSocket ss = new ServerSocket(8001);System.out.println("Server: Waiting for client to connect...");// 阻塞,等待客户端连接Socket s = ss.accept();// 打开输入流(从客户端接收数据)InputStream ips = s.getInputStream();// 打开输出流(向客户端发送数据)OutputStream ops = s.getOutputStream();System.out.println("Server: Welcome to the Java world");// 向客户端发送一句话ops.write("Hello, Client!".getBytes());// 从客户端读取一句话BufferedReader br = new BufferedReader(new InputStreamReader(ips));String clientMessage = br.readLine();System.out.println("Client said: " + clientMessage);// 关闭输入流、输出流和套接字ips.close();ops.close();s.close();ss.close();} catch (Exception e) {e.printStackTrace();}}
}
这是一个简单的TCP服务器,它通过创建 ServerSocket 对象在8001端口驻守,等待客户端的连接。一旦有客户端连接,它会打开输入流来接收客户端的数据,同时打开输出流来发送数据给客户端。这种方式实现了简单的单向通信
package org.example;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;public class TcpClient {public static void main(String[] args) {try {// 创建套接字,连接到服务器的 IP 地址和端口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);// 创建键盘输入的 BufferedReaderBufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));System.out.println("Type your message (type 'quit' to exit):");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();}}
}
这是一个简单的TCP客户端,它连接到服务器的IP地址和端口,通过输入流接收服务器的响应,并通过输出流发送用户输入的数据。用户可以输入消息,程序会将消息发送到服务器并等待服务器的回复。输入"quit"后,程序退出。
四、HTTP 编程
4.1相关概念


4.2相关类

4.3相关代码
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;public class JDKHttpClientGetTest {public static void main(String[] args) throws IOException, InterruptedException {doGet();}public static void doGet() {try {// 创建 HttpClient 实例HttpClient client = HttpClient.newHttpClient();// 创建 HttpRequest 请求对象,指定请求的 URIHttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();// 发送 GET 请求并获取响应HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());// 输出响应内容System.out.println(response.body());} catch (Exception e) {e.printStackTrace();}}
}
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;public class JDKHttpClientPostTest {public static void main(String[] args) throws IOException, InterruptedException {doPost();}public static void doPost() {try {// 创建 HttpClient 实例HttpClient client = HttpClient.newBuilder().build();// 构建 POST 请求的参数String requestBody = "tAddress=" + URLEncoder.encode("1 Market Street", "UTF-8") +"&tCity=" + URLEncoder.encode("San Francisco", "UTF-8") +"&sState=CA";// 创建 HttpRequest 请求对象,指定请求的 URI、请求方法和请求体HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://tools.usps.com/go/ZipLookupAction.action")).header("User-Agent", "HTTPie/0.9.2").header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8").POST(HttpRequest.BodyPublishers.ofString(requestBody)).build();// 发送 POST 请求并获取响应HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());// 输出响应内容System.out.println("Status Code: " + response.statusCode());System.out.println("Headers: " + response.headers());System.out.println("Body: " + response.body());} catch (Exception e) {e.printStackTrace();}}
}
4.4扩展
五、NIO 编程(同步非阻塞)
5.1相关概念

5.2相关类

5.3原理图

5.4相关代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;public class NioServer {public static void main(String[] args) throws IOException {int port = 8001;Selector selector = null;ServerSocketChannel servChannel = null;try {// 打开选择器,用于监控通道上的事件selector = Selector.open();// 打开服务器通道servChannel = ServerSocketChannel.open();// 配置服务器通道为非阻塞模式servChannel.configureBlocking(false);// 绑定端口并设置最大连接数servChannel.socket().bind(new InetSocketAddress(port), 1024);// 将服务器通道注册到选择器上,监听连接事件servChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("服务器在8001端口守候");} catch (IOException e) {e.printStackTrace();System.exit(1);}while (true) {try {// 阻塞等待就绪的事件,select()方法会返回就绪的通道数量selector.select(1000);Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> it = selectedKeys.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();it.remove();try {handleInput(selector, key);} catch (Exception e) {if (key != null) {// 出现异常时取消选择键,并关闭通道key.cancel();if (key.channel() != null)key.channel().close();}}}} catch (Exception ex) {ex.printStackTrace();}}}// 处理通道上的事件public static void handleInput(Selector selector, SelectionKey key) throws IOException {if (key.isValid()) {// 处理新接入的请求消息if (key.isAcceptable()) {// Accept the new connectionServerSocketChannel ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();sc.configureBlocking(false);// 将新连接的通道注册到选择器上,监听读事件sc.register(selector, SelectionKey.OP_READ);}if (key.isReadable()) {// 读取客户端发送的数据SocketChannel sc = (SocketChannel) key.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);int readBytes = sc.read(readBuffer);if (readBytes > 0) {readBuffer.flip();byte[] bytes = new byte[readBuffer.remaining()];readBuffer.get(bytes);String request = new String(bytes, "UTF-8"); // 接收到的输入System.out.println("client said: " + request);String response = request + " 666";doWrite(sc, response);} else if (readBytes < 0) {// 通道读取到-1表示连接已关闭,取消选择键并关闭通道key.cancel();sc.close();}}}}// 向通道写入数据public static void doWrite(SocketChannel channel, String response) throws IOException {if (response != null && response.trim().length() > 0) {byte[] bytes = response.getBytes();ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);writeBuffer.put(bytes);writeBuffer.flip();channel.write(writeBuffer);}}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;public class NioClient {public static void main(String[] args) {String host = "127.0.0.1";int port = 8001;Selector selector = null;SocketChannel socketChannel = null;try {// 创建选择器selector = Selector.open();// 打开SocketChannel并设置为非阻塞模式socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);// 尝试连接服务器if (socketChannel.connect(new InetSocketAddress(host, port))) {// 如果连接成功,注册到多路复用器,发送请求消息,读应答socketChannel.register(selector, SelectionKey.OP_READ);doWrite(socketChannel);} else {// 连接尚未完成,注册为连接就绪状态socketChannel.register(selector, SelectionKey.OP_CONNECT);}} catch (IOException e) {e.printStackTrace();System.exit(1);}while (true) {try {// 选择就绪的通道selector.select(1000);Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> it = selectedKeys.iterator();SelectionKey key = null;while (it.hasNext()) {key = it.next();it.remove();try {// 处理每个通道的事件handleInput(selector, key);} catch (Exception e) {if (key != null) {key.cancel();if (key.channel() != null)key.channel().close();}}}} catch (Exception e) {e.printStackTrace();}}}public static void handleInput(Selector selector, SelectionKey key) throws IOException {if (key.isValid()) {// 连接就绪,进行连接操作if (key.isConnectable()) {SocketChannel sc = (SocketChannel) key.channel();if (sc.finishConnect()) {// 连接成功,注册为读事件sc.register(selector, SelectionKey.OP_READ);doWrite(sc);}}if (key.isReadable()) {SocketChannel sc = (SocketChannel) key.channel();ByteBuffer readBuffer = ByteBuffer.allocate(1024);int readBytes = sc.read(readBuffer);if (readBytes > 0) {readBuffer.flip();byte[] bytes = new byte[readBuffer.remaining()];readBuffer.get(bytes);String body = new String(bytes, "UTF-8");System.out.println("Server said: " + body);} else if (readBytes < 0) {// 对端链路关闭key.cancel();sc.close();}}}}public static void doWrite(SocketChannel sc) throws IOException {// 生成随机消息String str = UUID.randomUUID().toString();byte[] bytes = str.getBytes();ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);writeBuffer.put(bytes);writeBuffer.flip();// 发送消息sc.write(writeBuffer);}
}
六、AIO 编程(异步非阻塞)
6.1相关概念
6.2相关代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.concurrent.TimeUnit;public class AioServer {public static void main(String[] args) throws IOException {// 创建异步服务器端通道并绑定到指定的端口AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();server.bind(new InetSocketAddress("localhost", 8001));System.out.println("服务器在8001端口守候");// 异步地等待客户端连接server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {@Overridepublic void completed(AsynchronousSocketChannel channel, Object attachment) {// 继续等待下一个客户端连接server.accept(null, this);// 准备缓冲区以读取数据ByteBuffer buffer = ByteBuffer.allocate(1024);// 异步地读取客户端发来的数据channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer bytesRead, ByteBuffer attachment) {attachment.flip(); // 将缓冲区反转,以准备从中读取数据CharBuffer charBuffer = CharBuffer.allocate(1024);CharsetDecoder decoder = Charset.defaultCharset().newDecoder();decoder.decode(attachment, charBuffer, false);charBuffer.flip();String data = new String(charBuffer.array(), 0, charBuffer.limit());System.out.println("客户端消息: " + data);// 将处理后的数据返回给客户端channel.write(ByteBuffer.wrap((data + " 666").getBytes()));try {channel.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.out.println("读取错误: " + exc.getMessage());}});}@Overridepublic void failed(Throwable exc, Object attachment) {System.out.println("连接失败: " + exc.getMessage());}});// 保持服务器运行,不断循环等待连接和读取数据try {while (true) {TimeUnit.SECONDS.sleep(5); // 暂停5秒}} catch (InterruptedException e) {e.printStackTrace();}}
}
每一个Comp let ionHandler都可以定义两个方法:comp leted和failed方法。当操作成功完成,将自动回调completed方法;如果操作发生异常,那么将自动回调failed方法。
6.3 3种I/O的区别
七、 Netty编程
7.1Netty库介绍
7.2关键概念

7.3相关配置
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <!-- Use 'netty-all' for 4.0 or above -->
<version>4.1.33.Final</version>
</dependency>
7.4相应代码实例
略
7.5进一步

八、邮件基础
8.1邮件的基础知识
8.1.1相关概念

邮件:一封信,包括发件人/收件人/文本/图片/附件等
邮件客户端
邮件服务端
- 发送邮件服务器
- 接受邮件服务器
8.1.2基础原理

邮件客户端
- Foxmail
- OutLook(Express, Microsoft Outlook)
-Thunderbird (linux平台)
邮件服务端
- Microsoft Exchange Server
- IBM Lotus Notes
- SendMail, Qmail, James
8.1.3主要协议



8.1.4服务器配置

8.2编程
8.2.1配置文件
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
8.2.2相关类
8.2.3收件箱
package org.example;import javax.mail.*;
import java.util.Properties;public class MailClientRecv {private Session session;private Store store;private String username = "xxxxx@qq.com";private String password = "xxxxxxxx";private String popServer = "pop.qq.com";public void init() throws Exception {// 设置属性Properties props = new Properties();props.put("mail.store.protocol", "pop3");// 创建Session对象session = Session.getInstance(props, null);session.setDebug(false); // 设置为true会输出跟踪日志// 创建Store对象并连接到收邮件服务器store = session.getStore("pop3");store.connect(popServer, username, password);}public void receiveMessage() throws Exception {String folderName = "inbox";Folder folder = store.getFolder(folderName);if (folder == null) {throw new Exception(folderName + "邮件夹不存在");}// 打开信箱folder.open(Folder.READ_ONLY);System.out.println("您的收件箱有" + folder.getMessageCount() + "封邮件.");System.out.println("您的收件箱有" + folder.getUnreadMessageCount() + "封未读的邮件.");// 读取邮件Message[] messages = folder.getMessages();// 遍历前3封邮件for (int i = 0; i < Math.min(messages.length, 3); i++) {System.out.println("------第" + (i + 1) + "封邮件-------");// 获取邮件信息Message message = messages[i];// 打印发件人和主题Address[] fromAddresses = message.getFrom();if (fromAddresses.length > 0) {System.out.println("发件人: " + fromAddresses[0]);}System.out.println("主题: " + message.getSubject());System.out.println();}// 关闭邮件夹folder.close(false);}public void close() throws Exception {store.close();}public static void main(String[] args) throws Exception {MailClientRecv client = new MailClientRecv();// 初始化client.init();// 接收邮件client.receiveMessage();// 关闭连接client.close();}
}
8.2.4发件箱
package org.example;import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.util.Properties;public class MailClientSend {private Session session; // 定义会话对象,用于创建邮件会话private Transport transport; // 定义传输对象,用于发送邮件private String username = "xxxxxxx@qq.com"; // 发件人的邮箱账号private String password = "xxxxxxxxxxx"; // 发件人的邮箱密码private String smtpServer = "smtp.qq.com"; // SMTP服务器的地址public void init() throws Exception {// 设置属性Properties props = new Properties();props.put("mail.transport.protocol", "smtp"); // 设置邮件传输协议为smtpprops.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(); // 调用TextMessage类的generate方法生成一个邮件
//Message msg = HtmlMessage.generate();
//Message msg = AttachmentMessage.generate();// 发送邮件transport.connect(); // 连接到SMTP服务器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(); // 创建一个MailClientSend对象// 初始化client.init(); // 调用init方法初始化会话和传输对象// 发送邮件client.sendMessage(); // 调用sendMessage方法发送邮件// 关闭连接client.close(); // 调用close方法关闭连接}
}
文本邮件
package org.example;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;// 这是一个用Java编写的文本邮件生成类
public class TextMessage {public static MimeMessage generate() throws Exception {String from = "xxxxxx@qq.com"; // 定义发件人的邮箱地址String to = "xxxxx@qq.com"; // 定义收件人的邮箱地址String subject = "test"; // 定义邮件的主题String body = "您好,这是来自一封chenliangyu的测试邮件"; // 定义邮件的正文内容// 创建Session实例对象Session session = Session.getDefaultInstance(new Properties()); // 获取默认的会话对象,不需要验证账户// 创建MimeMessage实例对象MimeMessage message = new MimeMessage(session); // 用会话对象创建一个邮件对象// 设置发件人message.setFrom(new InternetAddress(from)); // 用InternetAddress类封装发件人的地址// 设置收件人message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // 用InternetAddress类解析收件人的地址,并设置为收件人类型为TO(主要收件人)// 设置发送日期message.setSentDate(new Date()); // 设置邮件的发送日期为当前日期// 设置邮件主题message.setSubject(subject); // 设置邮件的主题为字符串subject// 设置纯文本内容的邮件正文message.setText(body); // 设置邮件的正文为字符串body,注意这里是纯文本内容,不支持HTML格式// 保存并生成最终的邮件内容message.saveChanges(); // 保存邮件的所有设置,并生成最终的内容// 把MimeMessage对象中的内容写入到文件中//msg.writeTo(new FileOutputStream("e:/test.eml")); // 这一行是注释掉的,如果需要把邮件内容写入到本地文件中,可以取消注释,并指定文件路径和名称return message; // 返回生成好的邮件对象}
}
网页文件
package org.example;import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;public class HtmlMessage {public static MimeMessage generate() throws Exception {String from = "lychen@sei.ecnu.edu.cn"; // 发件人地址String to = "chenliangyu1980@126.com"; // 收件人地址String subject = "HTML邮件";String body = "<a href=\"http://www.ecnu.edu.cn\">" +"<h4>欢迎大家访问我们的网站</h4></a></br>" +"<img src=\"https://news.ecnu.edu.cn/_upload/article/images/2e/e2/6b554d0\">";// 创建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"); // 修正 charset 冒号为等号// 保存并生成最终的邮件内容message.saveChanges();// 把MimeMessage对象中的内容写入到文件中//msg.writeTo(new FileOutputStream("e:/HtmlMessage.eml"));return message;}
}
附件文件
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.activation.DataHandler;
import javax.activation.URLDataSource;
import java.util.Properties;
import java.net.URL;public class AttachmentMessage {public static MimeMessage generate() throws Exception {String from = "lychen@sei.ecnu.edu.cn"; // 发件人地址String to = "chenliangyu1980@126.com"; // 收件人地址String subject = "多附件邮件"; // 邮件主题String body = "<a href=\"http://www.ecnu.edu.cn\">" +"欢迎大家访问我们的网站</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("http://example.com/ecnu4.jpg"); // 创建附件部分1MimeBodyPart attachPart2 = createAttachment("http://example.com/ecnu5.jpg"); // 创建附件部分2// 创建用于组合邮件正文和附件的MimeMultipart对象MimeMultipart allMultipart = new MimeMultipart("mixed"); // 指定Multipart类型为mixed,表示组合正文和附件allMultipart.addBodyPart(contentPart); // 添加邮件正文部分allMultipart.addBodyPart(attachPart1); // 添加附件部分1allMultipart.addBodyPart(attachPart2); // 添加附件部分2// 设置整个邮件内容为最终组合出的MimeMultipart对象message.setContent(allMultipart); // 将组合的Multipart对象设置为邮件内容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"); // 设置邮件正文为HTML格式return htmlBodyPart;}public static MimeBodyPart createAttachment(String filename) throws Exception {// 创建保存附件的MimeBodyPart对象,并加入附件内容和相应信息MimeBodyPart attachPart = new MimeBodyPart();URLDataSource fds = new URLDataSource(new URL(filename)); // 使用URLDataSource读取网络图片attachPart.setDataHandler(new DataHandler(fds)); // 设置附件的数据处理器attachPart.setFileName(fds.getName()); // 设置附件的文件名return attachPart;}
}
8.2.5进一步学习

相关文章:
java入坑之网络编程
一、 网络基础知识 1.1网卡 1.2IP地址 1.3端口 1.4保留IP 1.5网络协议 二、UDP 编程 2.1相关概念 计算机通讯:数据从一个IP的port出发(发送方),运输到另外一个IP的port(接收方) UDP:无连接无…...
A Survey on Large Language Model based Autonomous Agents
本文是LLM系列的文章,针对《A Survey on Large Language Model based Autonomous Agents》的翻译。 基于大模型的自动agents综述 摘要1 引言2 基于LLM的自动代理构建3 基于LLM的自动代理应用4 基于LLM的自动代理评估5 相关综述6 挑战6.1 角色扮演能力6.2 广义与人对…...
Integer、Long 等包装类 == 值判断、地址判断与缓存
先看下以下代码和输出 public static void main(String[] args) throws Exception{Integer a-128;Integer aa-128;System.out.printf("aaa? %s \n",aaa);Integer b127;Integer bb127;System.out.printf("bbb? %s \n",bbb);Integer c128;Integer cc128;Sy…...
numpy学习:reshape和resize
.reshape 与 .resize reshape:有返回值,所谓有返回值,即不对原始多维数组进行修改; resize:无返回值,所谓无返回值,即会对原始多维数组进行修改;...
JPA在不写sql的情况下实现模糊查询
本文已收录于专栏 《Java》 目录 背景介绍概念说明单字段模糊匹配:多字段模糊匹配: 实现过程代码实现1.写一个实体类去实现Specification接口,重写toPredicate方法2.定义一个接口去继承JpaRepository接口,并指定返回的类型和参数类…...
Java设计模式之单例模式
单例模式是一种设计模式,它的目的是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这个模式通常在需要控制资源访问权、限制实例化数量或实现全局共享时使用。 在实现单例模式时,一般会定义一个私有的构造函数,以防…...
Vue3 学习
基础 js:https://www.bilibili.com/video/BV15T411j7pJ/?spm_id_from333.337.search-card.all.click&vd_source9747207be61edfe4ec62226fc79b3589 官方文档: https://cn.vuejs.org/ 版本之间差异在关于---》版本发布 https://cn.vuejs.org/about/release…...
Error obtaining UI hierarchy Error taking device screenshot: EOF/NULL 解决办法
RT:Error obtaining UI hierarchy Error taking device screenshot: EOF/NULL 解决办法 关于monitor开发神器我就不多说了,但是假如我们在开发中遇到如上问题该怎么处理呢?别慌下面会有方法,不过不是对任何机型都有效,…...
Java框架之王:Spring的崛起与进化
在Java世界中,Spring框架无疑已经成为了一个传奇。它为开发者提供了强大的工具和丰富的功能,使得构建高质量、可扩展的Java应用程序变得轻松便捷。本文将带您领略Spring的魅力,以及它在过去几年中的崛起和进化。 一、Spring的崛起 Spring框…...
【位运算】位运算常用技巧总结
目录 前言 一.常见的小问题 1.给定一个数n,确定它的二进制表示中的第x位是0还是1 2.给定一个数n,将它的二进制表示中的第x位修改成1 3.给定一个数n,将它的二进制表示中的第x位修改成0 4.给定一个数n,提取它的二进制表示中最右侧的1&…...
【STM32】IIC使用中DMA传输时 发送数据总少一个的问题
问题描述 在使用STM32 I2C数据发送过程中,发现每轮实际发送出去的数据总比在DMA配置中设定的传输数据个数要少一个。比方说:DMA配置里设定的传输数据个数是10个,结果发现在总线上只能发出9个,经过进一步发现是少了最后一个数据。…...
记录layui数据表格使用文件上传按钮
一、前言 虽然用到这种的情况不多,但是还是记录下 二、相关代码 <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html;charsetutf-8"/><meta name"renderer" content&quo…...
c++之枚举
1、背景 在开发代码的过程中,vector类型数组a的index取了一个枚举值CTR,eg:a[CTR],刚开始以为是map类型,后面看不是,简单的看了下c的enum类型,原来enum按顺序默认为数字。 2、enum简介 2.1、…...
LeetCode 热题 100(七):105. 从前序与中序遍历序列构造二叉树、14. 二叉树展开为链表
题目一: 105. 从前序与中序遍历序列构造二叉树https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 思路:依据前序遍历的根左右和中序遍历的左根右, 且根左长度=左根 代码: …...
机器学习笔记 - 在表格数据上应用高斯混合GMM和网格搜索GridSearchCV提高分类精度的机器学习案例
1、需求及数据集说明 这是一项二分类任务,评估的是分类准确性(正确预测的标签百分比)。训练集有1000个样本,测试集有9000个样本。你的预测应该是一个9000 x 1的向量。您还需要一个Id列(1到9000),并且应该包括一个标题。格式如下所示: Id,Solution 1,0 2,1 3,1 ... 900…...
【UE 材质】模型部分透明
材质节点如下,这里简单解释一下。首先通过“Mask”节点将"Texture Coordinate" 节点中的“G”通道分离出来,然后通过“if”节点进行判断,当值小于0.5时为透明,当颜色不小于5时为不透明。可以通过一个参数来控制模型透明…...
Web3 社交平台如何脱颖而出?我们和 PoPP 聊了聊
能够颠覆 Web2 传统模式的社交产品有着怎样的特征?PoPP 作为专注于 Web3 的私域流量变现平台,为开发者和用户提供了社交产品发展的新路径,让社区用户充分实现互动交流,着力于创作内容的激励与变现。事实上,面对 Web3 社…...
【Android】ARouter新手快速入门
什么是ARouter ARouter是阿里巴巴推出的一款android界面路由框架 ARouter解决的核心问题是什么 在大型的模块化项目中,一个模块,往往无法直接访问到其它模块中的类,必须通过其它方式来完成模块间的调用 ARouter的核心功能在于,…...
基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十一:通用表单组件封装实现
一、本章内容 本章实现通用表单组件,根据实体配置识别实体属性,并自动生成编辑组件,实现对应数据填充、校验及保存等逻辑。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址:...
Oracle Scheduler学习
参考文档: Primary Note: Overview of Oracle Scheduler (Doc ID 1485539.1) Oracle Database Administrators Guide 12c Release 1 (12.1) E17636-21 Chapter(30) Administering Oracle Scheduler Examples of Using the Scheduler http://docs.oracle.com/cd/E166…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...




