🥼JavaWeb~(柒)文件/邮件传输.
笔记代码
文件传输
利用到了 Commons-io,通过 http 和 servlet 传输流文件.
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
/**
* Servlet implementation class FileServlet
*/
public class FileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 判断上传的文件普通表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(request)) {
return;//终止方法运行,说明这是一个普通的表单,直接返回
}
// 创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tempFile = new File(tmpPath);
if (!tempFile.exists()) {
tempFile.mkdir();//创建临时目录
}
//创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访间上传的文件;
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {
uploadFile.mkdir(); //创建这个月录
}
/*
处理上传的文件,一般都需要通过流来获取,我们可以使用 request.getInputStream(),原生态的文件上传流获取,十分麻烦
建议使用 Apache的文件上传组件来实现, common-fileUpload,它需要 commons-io组件
*/
try {
// 获取ServletFileUpload
ServletFileUpload fileUpload = getServletFileUpload(tempFile);
// 处理上传文件
// 把前端请求解析,封装成FileItem对象,需要从ServletFileUpload对象中获取
boolean flag = uploadParseRequest(fileUpload, request, uploadPath);
// Servlet请求转发消息
if (flag) {
// Servlet请求转发消息
request.setAttribute("flag", true);
} else {
request.setAttribute("flag", false);
}
request.getRequestDispatcher("info.jsp").forward(request, response);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public static ServletFileUpload getServletFileUpload(File tempFile) {
// 创建DiskFileItemFactory对象,处理文件路径或者大小限制
DiskFileItemFactory factory = new DiskFileItemFactory();
// 通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
factory.setSizeThreshold((int) 2e20);// 缓冲区大小为1M
factory.setRepository(tempFile);// 临时目录的保存目录,需要一个file
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
// 处理乱码问题
servletFileUpload.setHeaderEncoding("UTF-8");
// 设置总共能够上传文件的大小 10M
servletFileUpload.setFileSizeMax((long) 2e21);
/*
监听长传进度
pBytesRead:已读取到的文件大小
pContextLength:文件大小
*/
servletFileUpload.setProgressListener((long pBytesRead, long pContentLength, int pItems) -> System.out.println("已上传:" + pBytesRead + "\n总大小:" + pContentLength));
return servletFileUpload;
}
public static boolean uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath)
throws FileUploadException, IOException {
boolean flag = false; // 是否成功
// 把前端请求解析,封装成FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
// 判断上传的文件是普通的表单还是带文件的表单
if (fileItem.isFormField()) {
// getFieldName指的是前端表单控件的name;
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8"); // 处理乱码
System.out.println(name + ": " + value);
} else {
// ============处理文件==============
// 拿到文件名
String uploadFileName = fileItem.getName();
/*
.trim() 删除前后空格
下面的写法会导致"uploadFileName == null" 一直判定为false :
uploadFileName.trim().equals("") || uploadFileName == null
反过来就好了,原因是字符串对象引用改变了
*/
if (uploadFileName == null || uploadFileName.trim().equals("")) {
continue;
}
// 获得上传的文件名
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
// 获得文件的后缀名,如果文件后缀名fileExtName不是我们所需要的 就直按return.不处理,告诉用户文件类型不对。
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
System.out.println("文件名: " + fileName + "\n后缀名" + fileExtName);
// ================处理文件完毕==============
/*
UUID.randomUUID(),随机生一个唯一识别的通用码,保证文件夹名唯一
文件真实存在的路径 realPath
*/
String realPath = uploadPath + "/" + UUID.randomUUID();
// 给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if (!realPathFile.exists()) {
realPathFile.mkdir();
}
// ==============存放地址完毕==============
// 获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
// 创建一个文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(realPath + "/" + fileName);
// 创建一个缓冲区
byte[] buffer = new byte[(int) 2e20]; // 1M
int len;
while ((len = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, len);
}
// 关闭流
fileOutputStream.close();
inputStream.close();
flag = true;
// 上传成功,清除临时文件
fileItem.delete();
//=============文件传输完成=============
}
}
return flag;
}
}项目地址
包含用到的 JSP 页面和 xml 配置文件
问题: 如果 Tomcat 是 10 版本的,运行时会出现 500
邮件发送
原理图:
依赖
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
简单邮件
代码:
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;
public class MailDemo1 {
private static final String fromEmailAddress = "utsuko27@qq.com";
private static final String toEmailAddress = "utsuko27@163.com";
private static final String password = "这里填授权码";
public static void main(String[] args) throws Exception {
//0. 设置连接配置
Properties properties = getProperties();
//1.创建定义整个应用程序所需要的环境信息的session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(fromEmailAddress, password);
}
});
//开启session的debug模式,这样可以查看到程序发送Email的运行状态
session.setDebug(true);
//2.通过session得到transport对象
Transport transport = session.getTransport();
//3.使用邮箱的用户名和授权码连上邮件服务器
transport.connect("smtp.qq.com", fromEmailAddress, password);
//4.创建邮件:写文件
MimeMessage message = getMimeMessage(session);
//5.发送邮件
transport.sendMessage(message, message.getAllRecipients());
//6.关闭连接
transport.close();
}
private static Properties getProperties() throws GeneralSecurityException {
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com");///设置QQ邮件服务器
properties.setProperty("mail.transport.protocol", "smtp");///邮件发送协议
properties.setProperty("mail.smtp.auth", "true");//需要验证用户密码
//设置SSL加密(QQ邮箱需要)
MailSSLSocketFactory mailSSLSocketFactory = new MailSSLSocketFactory();
mailSSLSocketFactory.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", mailSSLSocketFactory);
return properties;
}
private static MimeMessage getMimeMessage(Session session) throws MessagingException {
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress(fromEmailAddress));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(toEmailAddress));
//邮件标题
message.setSubject("发送的标题");
//邮件的文本内容
message.setContent("内容", "text/html;charset=UTF-8");
return message;
}
}-> 开启 Debug 后的信息 <-
DEBUG: setDebug: JavaMail version 1.4.7
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.qq.com", port 465, isSSL true
220 newxmesmtplogicsvrsza8.qq.com XMail Esmtp QQ Mail Server.
DEBUG SMTP: connected to host "smtp.qq.com", port: 465
EHLO DESKTOP-CTDDD3K
250-newxmesmtplogicsvrsza8.qq.com
250-PIPELINING
250-SIZE 73400320
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "SIZE", arg "73400320"
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH XOAUTH2"
DEBUG SMTP: Found extension "AUTH=LOGIN", arg ""
DEBUG SMTP: Found extension "MAILCOMPRESS", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<utsuko27@qq.com>
250 OK.
RCPT TO:<utsuko27@163.com>
250 OK
DEBUG SMTP: Verified Addresses
DEBUG SMTP: utsuko27@163.com
DATA
354 End data with <CR><LF>.<CR><LF>.
From: utsuko27@qq.com
To: utsuko27@163.com
Message-ID: <825249556.0.1619921529857.JavaMail.29845@smtp.qq.com>
Subject: =?UTF-8?B?5Y+R6YCB55qE5qCH6aKY?=
MIME-Version: 1.0
Content-Type: text/html;charset=UTF-8
Content-Transfer-Encoding: base64
5YaF5a65
.
250 OK: queued as.
QUIT
221 Bye.
复杂邮件
比如涉及到附件或者插入图片的邮件,这种邮件就需要进行特殊包装
代码 (只需要修改 getMimeMessage()方法)
/**
* 含带附件的邮件
*
* @param session
* @return
* @throws MessagingException
*/
private static MimeMessage getMimeMessage(Session session) throws MessagingException {
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress(fromEmailAddress));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(toEmailAddress));
//邮件标题
message.setSubject("发送的标题");
//邮件的文本内容
//=================================准备图片数据
MimeBodyPart image = new MimeBodyPart();
//图片需要经过数据化的处理
DataHandler dataHandler = new DataHandler(new FileDataSource("D:/Game/Weidows/JavaWeb/Last/src/main/java/MailDemo.java"));
//在part中放入这个处理过图片的数据
image.setDataHandler(dataHandler);
//给这个part设置一个ID名字
image.setContentID("嵌入.png");
//=================================准备正文数据
MimeBodyPart text = new MimeBodyPart();
text.setContent("这是一张正文<img src='嵌入.jpg'>", "text/html;charset=UTF-8");
//=================================准备附件数据
MimeBodyPart body = new MimeBodyPart();
body.setDataHandler(new DataHandler(new FileDataSource("D:/Game/Weidows/JavaWeb/Last/src/main/java/MailDemo.java")));
body.setFileName("附件.png");
//描述数据关系
MimeMultipart mimeMultipart = new MimeMultipart();
mimeMultipart.addBodyPart(image);
mimeMultipart.addBodyPart(text);
mimeMultipart.addBodyPart(body);
mimeMultipart.setSubType("mixed");
//设置到消息中,保存修改
message.setContent(mimeMultipart);
message.saveChanges();
return message;
}测试过邮件发送没有问题,但是很有可能因为包装问题导致图片或者文件出现编码解析错误问题
Lombok
通过注解快速生成代码
需要
安装插件
和导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>效果如图:
注册-发送邮件 demo
其他资源可以去这里找: 代码
通过 JSP 获取表单中用户名,密码和 email,然后用 Servlet 获取,并开启邮件发送线程通知用户.
发送邮件的类
package demo;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.security.GeneralSecurityException;
import java.util.Properties;
public class SendMail extends Thread {
private static final String fromEmailAddress = "utsuko27@qq.com";
private static final String toEmailAddress = "utsuko27@163.com";
private static final String password = "授权码";
private final User user;
public SendMail(User user) {
this.user = user;
}
public void run() {
try {
Session session = Session.getDefaultInstance(getProperties(), new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(fromEmailAddress, password);
}
});
session.setDebug(true);
MimeMessage message = getMimeMessage(session);
send(session, message);
} catch (Exception e) {
System.out.println(e);
}
}
private Properties getProperties() throws GeneralSecurityException {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com");///设置QQ邮件服务器
prop.setProperty("mail.transport.protocol", "smtp");///邮件发送协议
prop.setProperty("mail.smtp.auth", "true");//需要验证用户密码
//QQ邮箱需要设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
return prop;
}
private MimeMessage getMimeMessage(Session session) throws MessagingException {
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress(fromEmailAddress));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress(toEmailAddress));
//邮件标题
message.setSubject("注册通知");
//邮件的文本内容
message.setContent(("恭喜你(" + user.getUserName() + ")成功注册!" + "密码:" + user.getPassword())
, "text/html;charset=UTF-8");
return message;
}
private void send(Session session, MimeMessage message) throws MessagingException {
Transport transport = session.getTransport();
transport.connect("smtp.qq.com", fromEmailAddress, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
}Servlet 类
package demo;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("pwd");
String email = req.getParameter("email");
User user = new User(username, password, email);
new SendMail(user).start(); // 开启线程
resp.getWriter().write("正在发送邮件....");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ⭐️齐下无贰⭐️!
评论