SpringBoot使用JavaMailSender实现发送邮件+Excel附件
作者:困知勉行1985
需求描述:项目审批完毕后,需要发送邮件通知相关人员,并且要附带数据库表生成的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.代码:
@Override public 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 map PropertyUtilsBean 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 properties for (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 bean DynamicBean dynamicBean = new DynamicBean(dest.getClass(), propertyMap); // add old value for (Map.Entry<String, Class> entry : propertyMap.entrySet()) { try { // filter extra properties if (!addProperties.containsKey(entry.getKey())) { dynamicBean.setValue(entry.getKey(), propertyUtilsBean.getNestedProperty(dest, entry.getKey())); } } catch (Exception e) { logger.error(e.getMessage(), e); } } ; // add extra value for (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生成代码,现在继续写邮件发送代码:
@Autowired private JavaMailSender springMailSender; @Override public 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. 设置系统值:
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表格_java_脚本之家 (jb51.net)
SpringBoot实现excel生成并且通过邮件发送的步骤详解_java_脚本之家 (jb51.net)
以上就是SpringBoot使用JavaMailSender实现发送邮件+Excel附件的详细内容,更多关于SpringBoot JavaMailSender发送邮件的资料请关注脚本之家其它相关文章!