mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-06 08:58:38 +08:00
add 添加邮件附件压缩方法,支持 本地文件/目录+oss网络路径 一键打包
This commit is contained in:
parent
6ffe9473f7
commit
e2142aaa23
@ -37,6 +37,18 @@ public interface MailClient {
|
||||
*/
|
||||
void sendEmail(String mailAddress, String title, String body,Map<String,String> files);
|
||||
|
||||
/**
|
||||
* sendEmail
|
||||
* <p>发送带有附件的文本邮件
|
||||
* @param mailAddress 收件人地址 多个收件人地址请按英文','字符隔开
|
||||
* @param title 邮件标题
|
||||
* @param body 邮件正文
|
||||
* @param zipName 压缩包名称 比如 附件.zip
|
||||
* @param files 附件,可添加多个
|
||||
* @author :Wind
|
||||
*/
|
||||
void sendEmail(String mailAddress, String title, String body, String zipName, Map<String,String> files);
|
||||
|
||||
/**
|
||||
* sendEmail
|
||||
* <p>群体发送带有附件的文本邮件
|
||||
@ -220,6 +232,21 @@ public interface MailClient {
|
||||
*/
|
||||
void sendHtml(String mailAddress, String title ,String body, String htmlName, Map<String,String> parameter,Map<String,String> files);
|
||||
|
||||
/**
|
||||
* sendHtml
|
||||
* <p> 读取模板发送html邮件,并携带正文和附件
|
||||
* <p> 将默认读取resources/template下的html文件,第四个参数为html的名称,需携带尾缀
|
||||
* @param mailAddress 收件人地址 多个收件人地址请按英文','字符隔开
|
||||
* @param title 邮件标题
|
||||
* @param body 邮件文本正文 可为空
|
||||
* @param htmlName 邮件正文
|
||||
* @param parameter key为模板的变量名称 无需携带大括号 value为模板变量所对应的值
|
||||
* @param zipName 压缩包名称 比如 附件.zip
|
||||
* @param files 附件,可添加多个 key 为文件名,value为文件的路径
|
||||
* @author :Wind
|
||||
*/
|
||||
void sendHtml(String mailAddress, String title, String body, String htmlName, Map<String,String> parameter, String zipName, Map<String,String> files);
|
||||
|
||||
/**
|
||||
* sendHtml
|
||||
* <p> 读取模板发送html邮件,并携带正文和附件
|
||||
|
||||
@ -22,6 +22,11 @@
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,107 @@
|
||||
package org.dromara.email.comm.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.ZipUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 压缩包处理类
|
||||
*
|
||||
* @author Bleachtred
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ZipUtils extends ZipUtil {
|
||||
private final static Integer TEMP_SIZE = 2048;
|
||||
|
||||
/**
|
||||
* 压缩方法(支持 本地文件/目录 + oss网络路径 混合)
|
||||
* @param files 文件列表
|
||||
* @author Bleachtred
|
||||
*/
|
||||
public static void zipFilePip(Map<String, String> files, OutputStream outputStream) {
|
||||
try(WritableByteChannel out = Channels.newChannel(outputStream)) {
|
||||
Pipe pipe = Pipe.open();
|
||||
//异步任务
|
||||
CompletableFuture.runAsync(() -> runTask(pipe, files));
|
||||
//获取读通道
|
||||
try (ReadableByteChannel readableByteChannel = pipe.source()) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(TEMP_SIZE);
|
||||
while (readableByteChannel.read(buffer) >= 0) {
|
||||
buffer.flip();
|
||||
out.write(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTask(Pipe pipe, Map<String, String> files) {
|
||||
try(ZipOutputStream zos = new ZipOutputStream(Channels.newOutputStream(pipe.sink()));
|
||||
WritableByteChannel out = Channels.newChannel(zos)) {
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
taskFunction(zos, out, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包文件
|
||||
* @param zos 压缩包输出
|
||||
* @param out 缓冲区通道
|
||||
* @param fileName 文件名称
|
||||
* @param file 文件
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
private static void taskFunction(ZipOutputStream zos, WritableByteChannel out, String fileName, File file) throws IOException {
|
||||
// 是否为目录
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
fileName = StrUtil.isEmpty(fileName) ? file.getName() + "/" : fileName + "/";
|
||||
if (files == null || files.length == 0){
|
||||
return;
|
||||
}
|
||||
for (File child : files) {
|
||||
taskFunction(zos, out, fileName + child.getName(), child);
|
||||
}
|
||||
} else {
|
||||
fileName = StrUtil.isEmpty(fileName) ? file.getName() : fileName;
|
||||
zos.putNextEntry(new ZipEntry(fileName));
|
||||
try(FileInputStream fis = new FileInputStream(file.getAbsolutePath())){
|
||||
FileChannel fileChannel = fis.getChannel();
|
||||
fileChannel.transferTo(0, fileChannel.size(), out);
|
||||
fileChannel.close();
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void taskFunction(ZipOutputStream zos, WritableByteChannel out, String fileName, String file) throws IOException {
|
||||
// 网络文件
|
||||
if (file.startsWith("http")) {
|
||||
zos.putNextEntry(new ZipEntry(fileName));
|
||||
byte[] bytes = HttpUtil.downloadBytes(file);
|
||||
out.write(ByteBuffer.wrap(bytes));
|
||||
}else {
|
||||
taskFunction(zos, out, fileName, new File(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,15 @@
|
||||
package org.dromara.email.core.service;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.dromara.email.api.MailClient;
|
||||
import org.dromara.email.api.Parameter;
|
||||
import org.dromara.email.comm.errors.MailException;
|
||||
import org.dromara.email.comm.utils.HtmlUtil;
|
||||
import org.dromara.email.comm.utils.ZipUtils;
|
||||
import org.dromara.email.core.ReflectUtil;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
@ -15,6 +21,10 @@ import javax.mail.Multipart;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -22,7 +32,7 @@ import java.util.Objects;
|
||||
|
||||
public class MailService implements MailClient {
|
||||
|
||||
private MailBuild mailBuild;
|
||||
private final MailBuild mailBuild;
|
||||
|
||||
private MailService(MailBuild mailBuild) {
|
||||
this.mailBuild = mailBuild;
|
||||
@ -47,13 +57,33 @@ public class MailService implements MailClient {
|
||||
sendEmail(Collections.singletonList(mailAddress), title, body, files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmail(String mailAddress, String title, String body, String zipName, Map<String, String> files) {
|
||||
try {
|
||||
Message message = mailBuild.getMessage();
|
||||
message.setRecipients(Message.RecipientType.TO, mailBuild.eliminate(Convert.toList(String.class, mailAddress)));
|
||||
message.setSubject(title);
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
message.setText(body);
|
||||
}
|
||||
if (files != null && files.size() != 0) {
|
||||
Multipart multipart = new MimeMultipart();
|
||||
zipFiles(multipart, zipName, files);
|
||||
message.setContent(multipart);
|
||||
}
|
||||
Transport.send(message);
|
||||
} catch (MessagingException | IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmail(List<String> mailAddress, String title, String body, Map<String,String> files) {
|
||||
try {
|
||||
Message message = mailBuild.getMessage();
|
||||
message.setRecipients(Message.RecipientType.TO, mailBuild.eliminate(mailAddress));
|
||||
message.setSubject(title);
|
||||
if (Objects.isNull(body) || body.isEmpty()) {
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
message.setText(body);
|
||||
}
|
||||
if (files != null && files.size() != 0) {
|
||||
@ -132,6 +162,38 @@ public class MailService implements MailClient {
|
||||
sendHtml(Collections.singletonList(mailAddress), title, body, htmlName, parameter, files);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHtml(String mailAddress, String title, String body, String htmlName, Map<String, String> parameter, String zipName, Map<String, String> files) {
|
||||
try {
|
||||
Message message = mailBuild.getMessage();
|
||||
message.setRecipients(Message.RecipientType.TO, mailBuild.eliminate(Convert.toList(String.class, mailAddress)));
|
||||
message.setSubject(title);
|
||||
|
||||
Multipart multipart = new MimeMultipart("alternative");
|
||||
//读取模板并进行变量替换
|
||||
List<String> strings = HtmlUtil.replacePlaceholder(HtmlUtil.readHtml(htmlName), parameter);
|
||||
//拼合HTML数据
|
||||
String htmlData = HtmlUtil.pieceHtml(strings);
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
// 创建文本正文部分
|
||||
MimeBodyPart textPart = new MimeBodyPart();
|
||||
textPart.setText(body);
|
||||
multipart.addBodyPart(textPart);
|
||||
}
|
||||
//添加附件
|
||||
if (MapUtil.isNotEmpty(files)) {
|
||||
zipFiles(multipart, zipName, files);
|
||||
}
|
||||
MimeBodyPart htmlPart = new MimeBodyPart();
|
||||
htmlPart.setContent(htmlData, "text/html;charset=UTF-8");
|
||||
multipart.addBodyPart(htmlPart);
|
||||
message.setContent(multipart);
|
||||
Transport.send(message);
|
||||
} catch (MessagingException | IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendHtml(List<String> mailAddress, String title, String body, String htmlName, Map<String, String> parameter, Map<String, String> files) {
|
||||
try {
|
||||
@ -186,4 +248,16 @@ public class MailService implements MailClient {
|
||||
multipart.addBodyPart(messageBodyPart);
|
||||
}
|
||||
}
|
||||
|
||||
private void zipFiles(Multipart multipart, String zipName, Map<String, String> files) throws MessagingException, IOException {
|
||||
// 设置附件消息部分
|
||||
MimeBodyPart messageBodyPart = new MimeBodyPart();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
ZipUtils.zipFilePip(files, os);
|
||||
ByteArrayInputStream stream = IoUtil.toStream(os);
|
||||
DataSource source = new ByteArrayDataSource(stream, "application/octet-stream");
|
||||
messageBodyPart.setDataHandler(new DataHandler(source));
|
||||
messageBodyPart.setFileName(StrUtil.isNotBlank(zipName) ? zipName: UUID.fastUUID() + ".zip");
|
||||
multipart.addBodyPart(messageBodyPart);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user