Springboot 使用JavaMailSender发送邮件 + Excel附件

目录

1.生成Excel表格

1.依赖设置

2.代码:

2.邮件发送

1.邮件发送功能实现-带附件

 2.踩过的坑

1.附件名中文乱码问题

3.参考文章:


需求描述:项目审批完毕后,需要发送邮件通知相关人员,并且要附带数据库表生成的Excel表格,这就要求不光是邮件发送功能,还要临时生成Excel表格做为附件

1.生成Excel表格

使用huTool工具包的Excel表格生成功能

1.依赖设置

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.2</version>
</dependency>

Hutool-all中包含了Hutool的所有工具类,由于需要生成Excel文件需要依赖poi

2.代码:

    @Overridepublic void publish(xxxxxxPublishVo publishVo) {..................................................../*** 生成Excel表格*///在内存操作,写到输出流中ExcelWriter writer = ExcelUtil.getWriter(true);//自定义标题别名writer.addHeaderAlias("projectCode", "xx编号");writer.addHeaderAlias("projectName", "xx名称");writer.addHeaderAlias("targetType", "xx类型");writer.addHeaderAlias("targetName", "xx名称");writer.addHeaderAlias("targetForMp", "xxxx目标");writer.addHeaderAlias("symbols", "xx限制符");//获取数据QpmxxxxTargetMg query = new QpmxxxxTargetMg();query.setProjectCode(publishVo.getProjectCode());List<xxxxxxListDTO> data =  selectxxxxxxByCondition(query);//整理数据,以便于生成Excel表格List<Object> dataNew = new ArrayList<>();Set<String> stageCollectSet = new HashSet<>();for (xxxxxxListDTO target: data){List<xxxxxxTargetMgStage> stageList = target.getxxxxxxStageList();Map<String, Object> addProperties = new HashMap<>();for (xxxxxxMgStage stage: stageList){if (!stageCollectSet.contains(stage)){stageCollectSet.add(stage.getStage());//给Excel增加列writer.addHeaderAlias(stage.getStage(), stage.getStage() + "目标");}//为对象动态增加属性addProperties.put(stage.getStage(), stage.getStageTarget());}//生成新的包含了新增字段的对象Object targetNew = ReflectUtil.getTarget(target, addProperties);dataNew.add(targetNew);}//只保留别名的数据writer.setOnlyAlias(true);writer.write(dataNew,true);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();// excel写入到输出流writer.flush(outputStream,true);...........................................................................

上述代码中,调用了工具类ReflectUtil给对象动态增加属性。由于数据中有子类,需要获取到子类中的某个字段并生成Excel表格,所以Excel表格构造就需要对数据对象进行改造,简单来说就是需要给对象动态增加新的属性(成员对象的属性),如下所示示例:

把studentList里面的关键属性数据,新增给Test类

示例不是很合适,凑合着用吧

class Test {

    private String class;

    .............................................

    private List<Student> studentList;

}

工具类ReflectUtil,用于给对象动态增加新的属性:

import com.google.common.collect.Maps;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;/*** 为实体类动态增加属性,用于生成Excel表格时的特殊情况,例如表格中的列需要动态增加*/
public class ReflectUtil {static Logger logger = LoggerFactory.getLogger(ReflectUtil.class);public static Object getTarget(Object dest, Map<String, Object> addProperties) {// get property mapPropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);Map<String, Class> propertyMap = Maps.newHashMap();for (PropertyDescriptor d : descriptors) {if (!"class".equalsIgnoreCase(d.getName())) {propertyMap.put(d.getName(), d.getPropertyType());}}// add extra propertiesfor (Map.Entry<String, Object> entry : addProperties.entrySet()) {propertyMap.put(entry.getKey(), entry.getValue().getClass());}
//        addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));// new dynamic beanDynamicBean dynamicBean = new DynamicBean(dest.getClass(), propertyMap);// add old valuefor (Map.Entry<String, Class> entry : propertyMap.entrySet()) {try {// filter extra propertiesif (!addProperties.containsKey(entry.getKey())) {dynamicBean.setValue(entry.getKey(), propertyUtilsBean.getNestedProperty(dest, entry.getKey()));}} catch (Exception e) {logger.error(e.getMessage(), e);}};// add extra valuefor (Map.Entry<String, Object> entry : addProperties.entrySet()) {try {dynamicBean.setValue(entry.getKey(), entry.getValue());} catch (Exception e) {logger.error(e.getMessage(), e);}};Object target = dynamicBean.beanMap;return target;}public static class DynamicBean {/*** 目标对象*/private Object target;/*** 属性集合*/private BeanMap beanMap;public DynamicBean(Class superclass, Map<String, Class> propertyMap) {this.target = generateBean(superclass, propertyMap);this.beanMap = BeanMap.create(this.target);}/*** bean 添加属性和值** @param property* @param value*/public void setValue(String property, Object value) {beanMap.put(property, value);}/*** 获取属性值** @param property* @return*/public Object getValue(String property) {return beanMap.get(property);}/*** 获取对象** @return*/public Object getTarget() {return this.target;}/*** 根据属性生成对象** @param superclass* @param propertyMap* @return*/private Object generateBean(Class superclass, Map<String, Class> propertyMap) {BeanGenerator generator = new BeanGenerator();if (null != superclass) {generator.setSuperclass(superclass);}BeanGenerator.addProperties(generator, propertyMap);return generator.create();}}
}

至此,我们就生成了Excel表格,并且把数据写入到了输出流中。

下面我们需要从输出流中拿到Excel表格数据,并做为邮件的附件发送出去。

2.邮件发送

1.邮件发送功能实现-带附件

Spring Email 抽象的核心是 JavaMailSender接口,通过实现JavaMailSender接口把 Email 发送给邮件服务器,由邮件服务器实现邮件发送的功能。

Spring 自带了一个 JavaMailSender的实现 JavaMailSenderImpl。SpringBoot 应用在发送 Email 之前,我们需要在配置文件中对JavaMailSender进行属性配置,这样就可以利用Springboot的自动装配机制,将 JavaMailSenderImpl 装配为 Spring容器的一个 bean。

spring.mail.host: xxxxxxx.com
# 设置端口
spring.mail.port: 25
# 设置用户名
spring.mail.username: xxxxxxxxxx
# 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码
spring.mail.password: xxxxxxxxx
# 设置是否需要认证,如果为true,那么用户名和密码就必须的,
# 如果设置false,可以不设置用户名和密码,当然也得看你的对接的平台是否支持无密码进行访问的。
spring.mail.properties.mail.smtp.auth: false
# STARTTLS[1]  是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL),而不是另外使用一个端口作加密通信。
spring.mail.properties.mail.smtp.starttls.enable: true
spring.mail.properties.mail.smtp.starttls.required: fasle
spring.mail.properties.mail.imap.starttls.socketFactory.fallback: false
spring.mail.properties.mail.smtp.starttls.socketFactory.class: com.ey.model.MailCommand

继上面完整的Excel生成代码,现在继续写邮件发送代码:

    @Autowiredprivate JavaMailSender springMailSender;    @Overridepublic void publish(xxxxxxPublishVo publishVo) {//........这里不再复制上面的代码,只从Excel表格写入输出流开始.........// excel写入输出流writer.flush(outputStream,true);//邮件附件名称String fileName = String.format("制定xx目标-%s.xlsx",UUID.randomUUID());//这个地方无需再配置,springboot自动装配,配置信息在nacos配置中心
//        springMailSender.setDefaultEncoding("UTF-8");
//        springMailSender.setHost("mx.goertek.com");
//        springMailSender.setPort(25);
//        springMailSender.setProtocol(JavaMailSenderImpl.DEFAULT_PROTOCOL);
//        springMailSender.setUsername("tims.sys@goertek.com");
//        springMailSender.setPassword("Khkd0804");
//        Properties p = new Properties();
//        p.setProperty("mail.smtp.timeout", "25000");
//        p.setProperty("mail.smtp.auth", "true");
//        p.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//        springMailSender.setJavaMailProperties(p);MimeMessage mimeMessage = springMailSender.createMimeMessage();System.getProperties().setProperty("mail.mime.splitlongparameters", "false");MimeMessageHelper messageHelper = null;try {messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");} catch (MessagingException e) {throw new RuntimeException(e);}try {LoginUser userInfo = UserUtil.getCurrentUser();
//            String currentUserEmail = userInfo.getEmaila();
//            messageHelper.setFrom(currentUserEmail);messageHelper.setFrom(mailUserName);//设置收件人String[] emailArr = publishVo.getEmails().replaceAll("\\s+", "").split(",");messageHelper.setTo(emailArr);//设置抄送人if (!StringUtils.isBlank(publishVo.getCcEmails())){String[] ccEmailArr = publishVo.getCcEmails().replaceAll("\\s+", "").split(",");messageHelper.setCc(ccEmailArr);}messageHelper.setSubject("项目-" + publishVo.getProjectName().concat(": 制定品质目标完毕"));messageHelper.setText("项目-" + publishVo.getProjectName().concat(": 制定品质目标完毕"));try {//messageHelper.addInline("doge.gif", new File("xx/xx/doge.gif"));messageHelper.addAttachment(MimeUtility.encodeWord(fileName,"utf-8","B"), new ByteArrayResource(outputStream.toByteArray()));} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}springMailSender.send(mimeMessage);} catch (MessagingException e) {throw new RuntimeException(e);}

 2.踩过的坑

上述邮件发送功能实现过程中踩过的坑:

1.附件名中文乱码问题

附件的名字是中文,发送成功后,在邮件中的附件名字中文乱码,怎样解决这个问题?

1. 设置系统值:

System.setProperty("mail.mime.splitlongparameters", "false");

2. 这里,在创建对象的时候定义编码格式(utf-8):

MimeMessageHelper messageHelper = new MimeMessageHelper(mes, true, "utf-8");

3. 其次,在添加附件的时候,附件名是需要定义编码:

messageHelper.addAttachment(MimeUtility.encodeWord(附件名,"utf-8","B"), 附件输入流));

3.参考文章:

使用hutool工具进行导入导出excel表格_hutool excel-CSDN博客

springboot:实现excel生成并且通过邮件发送 - 哔哩哔哩 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/172294.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

京东平台数据分析:2023年9月京东空气净化器行业品牌销售排行榜

鲸参谋监测的京东平台9月份空气净化器市场销售数据已出炉&#xff01; 9月份&#xff0c;空气净化器的销售同比上年增长。根据鲸参谋平台的数据显示&#xff0c;今年9月&#xff0c;京东平台空气净化器的销量将近15万&#xff0c;同比增长约1%&#xff1b;销售额将近2亿元&…

C++多态(超级详细版)

目录 一、什么是多态 二、多态的定义及实现 1.多态构成条件 2.虚函数的重写和协变 虚函数重写的两个例外&#xff1a; 2.1协变 2.2析构函数的重写 &#xff08;析构函数名统一处理成destructor&#xff09; 3.重载、覆盖(重写)、隐藏(重定义)的对比 4.final 和 overr…

【计算机网络笔记】DNS报文格式

DNS 提供域名到主机IP地址的映射  域名服务的三大要素&#xff1a;  域&#xff08;Domain&#xff09;和域名(Domain name)&#xff1a; 域指由地 理位置或业务类型而联系在一起的一组计算机构 成。  主机&#xff1a;由域名来标识。域名是由字符和&#xff08;或&a…

如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载

如何在linux服务器上安装Anaconda与pytorch&#xff0c;以及pytorch卸载 1&#xff0c;安装anaconda1.1 下载anaconda安装包1.2 安装anaconda1.3 设计环境变量1.4 安装完成验证 2 Anaconda安装pytorch2.1 创建虚拟环境2.2 查看现存环境2.3 激活环境2.4 选择合适的pytorch版本下…

Python:实现日历到excel文档

背景 日历是一种常见的工具,用于记录事件和显示日期。在编程中,可以使用Python编码来制作日历。 Python提供了一些内置的模块和函数,使得制作日历变得更加简单。 在本文,我们将探讨如何使用Python制作日历,并将日历输出到excel文档中。 效果展示 实现 在代码中会用到cale…

FFmpeg5.1.3编译动态库踩坑之旅(基于Linux虚拟机)

准备工作 环境准备 1.Windows安装Oracle VM VirtualBox 7.0.10&#xff0c;安装ubuntu-22.04.3。 坑一&#xff1a;无法往虚拟机里拖放复制文件&#xff0c;解决办法&#xff1a;登录Ubuntu虚拟机时切换到xorg方式登录&#xff0c;参考地址&#xff1a;Ubuntu Desktop 22.04…

软考系统架构之案例篇(架构设计相关概念)

案例篇-架构设计相关概念 1. 架构风格的概念2. 五大架构风格有哪些3. MVC架构含义4. 云计算架构5. 云原生架构设计原则6. ESB的主要功能包括7. 质量属性的含义及其设计策略8. EJB中的 Bean 分三种类型9. 风险点、敏感点、权衡点的含义10. REST 的5个原则 其它相关推荐&#xff…

Generative AI 新世界 | Falcon 40B 开源大模型的部署方式分析

在上期文章&#xff0c;我们探讨了如何在自定义数据集上来微调&#xff08;fine-tuned&#xff09;模型。本期文章&#xff0c;我们将重新回到文本生成的大模型部署场景&#xff0c;探讨如何在 Amazon SageMaker 上部署具有 400 亿参数的 Falcon 40B 开源大模型。 亚马逊云科技…

ICLR 2023丨3DSQA:3D 场景中的情景问答

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/pdf/2210.07474.pdf 主页链接&#xff1a;http://sqa3d.github.io 图 1&#xff1a;3D 场景中情景问答 (SQA3D) 的任务图示。给定场景上下文 S&#xff08;例如&#…

并发编程 - 并发可见性,原子性,有序性 与 JMM内存模型

1. 并发三大特性 并发编程Bug的源头&#xff1a; 原子性 、 可见性 和 有序性 问题 1.1 原子性 一个或多个操作&#xff0c;要么全部执行且在执行过程中不被任何因素打断&#xff0c;要么全部不执行。 在 Java 中&#xff0c;对基本数据类型的变量的读取和赋值操作是原子性操…

常用字符串函数拓展

文章目录 字符串拓展函数strncpystrncatstrncmpstrstrstrtokstrerrormemcpymemmovememcmpmemset 库函数模拟实现memmoveqsort 我们在学习C语言时已经学习了一些常见的字符串函数&#xff0c;但这还不能满足我们的需求&#xff0c;为此我们拓展了几个常用的字符串函数。 字符串拓…

Maven项目转为SpringBoot项目

Maven项目转为SpringBoot项目 前言创建一个maven项目前的软件的一些通用设置Maven仓库的设置其他的设置字符编码编译器注解支持 创建的Maven项目修改为Spring Boot项目修改pom.xml文件修改启动类-Main新建WAR包所需的类 添加核心配置文件 测试的控制器最后整个项目的目录结构![…

ce从初阶到大牛(两台主机免密登录)

一、配置ssh远程连接 实现两台linux主机之间通过公钥验证能够互相实现免密登陆 1.确认服务程序是否安装 rpm -qa | grep ssh 2.是否启动 ps -aux | grep ssh 3.生成非对称公钥 ssh-keygen -t rsa 4.公钥发送到客户端 cd /root/.ssh/ ssh-copy-id root192.168.170.134 因为…

OpenCV学习(五)——图像基本操作(访问图像像素值、图像属性、感兴趣区域ROI和图像边框)

图像基本操作 5. 图像基本操作5.1 访问像素值并修改5.2 访问图像属性5.2 图像感兴趣区域ROI5.3 拆分和合并图像通道5.4 为图像设置边框&#xff08;填充&#xff09; 5. 图像基本操作 访问像素值并修改访问图像属性设置感兴趣区域&#xff08;ROI&#xff09;分割和合并图像 …

本来打算做功能测试的,但是发现playwright太好玩了,玩了一天,功能测试进度为空

本文是作者的自言自语&#xff1a;//todo 未完待续 https://blog.csdn.net/lineuman 微软果然有大牛啊&#xff01;有能人的公司总是令人敬佩。 playwright这种级别的工具简直就是核弹级别的。 当我开始使用playwright的时候&#xff0c;嘭的一下&#xff0c;我的世界炸了&…

javaEE -10(11000字详解5层重要协议)

一&#xff1a;应用层重点协议 1.1&#xff1a; DNS DNS&#xff0c;即Domain Name System&#xff0c;域名系统。DNS是一整套从域名映射到IP的系统。 TCP/IP中使用IP地址来确定网络上的一台主机&#xff0c;但是IP地址不方便记忆&#xff0c;且不能表达地址组织信息&#x…

2023年正版win10/win11系统安装教学(纯净版)

第一步&#xff1a;准备一个8G容量以上的U盘。 注意&#xff0c;在制作系统盘时会格式化U盘&#xff0c;所以最好准备个空U盘&#xff0c;防止资料丢失。 第二步&#xff1a;制作系统盘。 安装win10 进入windows官网 官网win10下载地址&#xff1a;https://www.microsoft.c…

Oracle数据库设置归档模式(超级简单)

1、打开监听 查看监听的状态&#xff0c;如果没打开监听需要打开监听&#xff0c;如果打开直接下一步 lsnrctl status 打开监听 lsnrctl start 2、启动数据库 首先进入数据库 sqlplus /nolog 然后连接管理员 conn / as sysdba 3、查看当前模式 archive log list 可以…

图像特征Vol.1:计算机视觉特征度量|第一弹:【纹理区域特征】

目录 一、前言二、纹理区域度量2.1&#xff1a;边缘特征度量2.2&#xff1a;互相关和自相关特征2.3&#xff1a;频谱方法—傅里叶谱2.4&#xff1a;灰度共生矩阵(GLCM)2.5&#xff1a;Laws纹理特征2.6&#xff1a;局部二值模式&#xff08;LBP&#xff09; 一、前言 &#x1f…