将数据导出 Excel 并异步发送到指定邮箱:一次性能优化实战 ...

打印 上一主题 下一主题

主题 1985|帖子 1985|积分 5955

使用 Spring Boot 实现 Excel 导出 + 邮件异步发送功能,解决接口阻塞问题
一、背景介绍
最近我在开发一个跑团管理系统的数据导出功能,需求是将用户查询的成员信息、跑量统计等数据导出为 Excel 文件,并通过邮件自动发送至指定邮箱,而非让用户手动下载文件。
虽然功能逻辑看起来不复杂,但在实际开发过程中碰到了一些关键性问题:
导出 Excel 后发送邮件耗时较长,导致接口相应延迟;
QQ 邮箱 SMTP 校验严格,出现 550 The "From" header is missing or invalid 异常;
接口体验差,用户点击后必要等待很久才能收到相应。
于是我对整个流程进行了分析与重构,最终实现了高性能、高可用的数据导出 + 邮件发送功能。
 
 
二、功能实现流程概览
用户发起哀求,选择导出类型(成员列表 / 跑量统计等);
系统调用服务层获取数据;
使用 Apache POI 构建 Excel 文件并写入内存流(ByteArrayOutputStream);
将生成的 Excel 字节数组作为附件,使用 JavaMailSender 发送邮件;
返回接口相应,提示邮件已发送成功(实则后台异步执行);
 
三、碰到的问题与解决方案
✅ 问题一:Excel 导出时报错 sheetName must not be null
原因:
Apache POI 要求每个 Sheet 必须著名称,否则抛出异常。
解决方案:
在创建 ExcelUtil 实例后显式设置 sheetName,例如:
ExcelUtil util = new ExcelUtil(PersonalRunningGroupExportVO.class);
util.setSheetName("跑团数据");
 
✅ 问题二:QQ 邮箱发送失败,报错 550 The "From" header is missing or invalid
原因:
QQ 邮箱对发件人地址校验非常严格,要求 MAIL FROM 地址必须与登录账号同等,否则拒绝发送。
解决方案:
在邮件构建器中显式设置发件人地址:
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom("your-qq@qq.com"); // 必须与 spring.mail.username 同等
同时确保设置文件中使用的是授权码,而非登录密码:

 
spring:
  mail:
    host: smtp.qq.com
    port: 587
    username: your-qq@qq.com
    password: 授权码
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
 
✅ 问题三:发送邮件过程很慢,影响接口相应时间
原因:
邮件发送属于 I/O 操作,受网络、服务器限制,同步执行会阻塞主线程,影响用户体验。
解决方案:
引入 Spring 的异步任务支持 @Async,将邮件发送操作放入子线程处理。
步骤如下:
1.在启动类上添加 @EnableAsync
2.创建邮件服务类 EmailService,并在方法上添加 @Async
3.Controller 中调用异步方法发送邮件,立即返回效果
示例代码:

 
@Async
public void sendExcelEmailAsync(String to, byte[] data, String fileName) {
    try {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom("your-qq@qq.com");
        helper.setTo(to);
        helper.setSubject("导出的跑团数据");
        helper.setText("请查收附件中的跑团数据。");
        helper.addAttachment(fileName + ".xlsx", new ByteArrayResource(data));
        javaMailSender.send(message);
    } catch (Exception e) {
        log.error("邮件发送失败:{}", e.getMessage());
    }
}
四、优化效果
优化前
接口需等待邮件发送完成才返回
用户需等待 3~5 秒乃至超时
多次哀求客易造成线程阻塞
QQ 邮箱频繁报错无法发送
优化后
接口立即返回,邮件后台异步发送
接口相应时间缩短至 300ms 内
支持并发发送,提升吞吐能力
设置 From 后成功发送,兼客性强
 
五、总结
这次开发让我深刻体会到:
邮件发送应尽量避免阻塞主线程,建议统一走异步化处理;
Spring Boot 提供了强大的异步支持,只需简单设置即可使用;
QQ 邮箱对发件人地址校验严格,务必保证 From 和 Username 同等;
使用 ByteArrayOutputStream 替代临时文件,更安全高效;
合理封装 ExcelUtil 工具类,提高复用性和可维护性。
 
六、完整功能点清单(便于读者参考)
功能模块                                                       技能点
数据导出                                                       Apache POl
Excel写入内存            ByteArrayOutputStream
邮件发送              JavaMailSender/Jakarta Mail
异步处理            @Async + ThreadPoolTaskExecutor
邮箱验证              SMTP from 同等性校验
接口优化              非阻塞相应设计
邮箱类型             QQ/Gmail/网易等通用适配


七、结语
假如你也在做类似的数据导出 + 邮件通知功能,盼望这篇文章能帮你少踩坑,快速上线稳定版本。如有疑问接待留言交流,也接待你分享你的优化思路!








免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

石小疯

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表