首先在pom.xml文件添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
其次编写application.properties文件进行邮箱信息配置,如添加如下内容:
####邮件系统参数设置开始
#邮件服务器地址
spring.mail.host=smtp.exmail.qq.com
#邮件服务器端口
spring.mail.port=465
#邮件服务器登录用户名、密码(此处是企业邮箱)
#登录密码,开通腾讯企业邮箱后,必须修改原密码,否则会报发送异常(501 ÇëµÇ¼exmail.qq.comÐÞ¸ÄÃÜÂë );
#企业邮箱如果未开启安全登录,就不需要授权码了,直接填写登录密码即可。如果开启了安全登录,则这里需要填写客户端专用密码,即授权码
spring.mail.username=occ@hanhoo.com
#如果这不是企业邮箱,是个人邮箱,则此处需要填写授权码而不是密码
#spring.mail.password=5VW9UW5S5eQUBigy
spring.mail.password=123456
spring.mail.protocol=smtp
spring.mail.default-encoding=UTF-8
#开户验证身份 true/false
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.class.fallback=false
#邮件发送地址(此处是企业邮箱)
spring.mail.send.from=occ@hanhoo.com
#邮件接收地址(此处是企业邮箱)
spring.mail.send.to={ dd@hanhoo.com, cc@hanhoo.com }
#邮件抄送地址(此处是企业邮箱)
spring.mail.send.cc=aa@hanhoo.com
####邮件系统参数结束
个人邮箱授权码获取,这里以qq邮箱为例,如图:
打开qq邮箱,点击设置
选择账户:
拉到下面开启smpt服务,需要短信开通:
写一个邮箱配置类:
package com.yonyou.occ.report.config;
import com.sun.mail.util.MailSSLSocketFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import java.security.GeneralSecurityException;
import java.util.Properties;
/**
* @author
* @date 2020-11-23 11:22
*/
@Configuration
public class MailSenderConfig implements WebMvcConfigurer {
//登录用户名
@Value("${spring.mail.username}")
private String username;
//登录密码,开通腾讯企业邮箱后,必须修改原密码,否则会报发送异常(501 ÇëµÇ¼exmail.qq.comÐÞ¸ÄÃÜÂë );
// 企业邮箱如果未开启安全登录,就不需要授权码了,直接填写登录密码即可。如果开启了安全登录,则这里需要填写客户端专用密码,即授权码
@Value("${spring.mail.password}")
private String password;
//发送服务器地址
@Value("${spring.mail.host}")
private String host;
//端口
@Value("${spring.mail.port}")
private Integer port;
//协议
@Value("${spring.mail.protocol}")
private String protocol;
@Bean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setUsername(username);
javaMailSender.setPassword(password);
javaMailSender.setHost(host);
javaMailSender.setPort(port);
javaMailSender.setProtocol(protocol);
javaMailSender.setDefaultEncoding("UTF-8");
Properties props = new Properties();//②
props.setProperty("mail.smtp.host", host);
props.setProperty("mail.smtp.auth", "true");
//使用SSL,企业邮箱必需!
//开启安全协议
MailSSLSocketFactory sf = null;
try {
sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.ssl.socketFactory", sf);
props.put("mail.smtp.ssl.socketFactory.fallback", "false");
Session session = Session.getInstance(props, new MailAuthenricator(username, password));
session.setDebug(Boolean.TRUE);
javaMailSender.setSession(session);//③
return javaMailSender;
}
//用户名密码验证,需要实现抽象类Authenticator的抽象方法PasswordAuthentication
static class MailAuthenricator extends Authenticator {
String u = null;
String p = null;
public MailAuthenricator(String u, String p) {
this.u = u;
this.p = p;
}
@Override
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(u, p);
}
}
}
编写定时任务类:
package com.yonyou.occ.report.task;
import com.yonyou.occ.report.service.EmailSendService;
import com.yonyou.ocm.common.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author
* @date 2020-11-20 10:06
*/
@Slf4j
@Component
//@Async //可加在类或方法,开启异步事件的支持
public class ExportDataSchedulerTask {
@Autowired
private HttpServletResponse response;
@Autowired
private EmailSendService emailSendService;
//cron表达式:0 0 0 1 * ? ,表示每月的1号零点零分零秒执行一次
@Scheduled(cron = "0 0 0 1 * ?")
//cron表达式:0 */1 * * * ?,表示每一分钟执行一次
//@Scheduled(cron = "0 */1 * * * ?")
public void scheduled() {
long startTime = System.currentTimeMillis();
log.info("-------------- 开始 执行导出【客户活动明细报表】数据定时任务 start --------------------" + startTime);
Map<String, Object> searchParams = new HashMap<>();
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
//开始日期减一年
cal.add(Calendar.YEAR, -1);
String startDate = DateUtil.from_Date_to_String(DateUtil.yyMMddHHmmss, cal.getTime());
//结束日期加一年
cal.add(Calendar.YEAR, 1);
String endDate = DateUtil.from_Date_to_String(DateUtil.yyMMddHHmmss, cal.getTime());
searchParams.put("beginDate", startDate);
searchParams.put("endDate", endDate);
emailSendService.sendMail(searchParams, response);
long endTime = System.currentTimeMillis();
log.info("-------------- 结束 执行导出【客户活动明细报表】数据定时任务 end --------------------" + (endTime - startTime) + "ms");
}
}
编写接口:
package com.yonyou.occ.report.service;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* @author
* @date 2020-11-20 19:03
*/
public interface EmailSendService {
/**
* 根据参数发送邮件
* @param searchParams
* @param response
*/
void sendMail(Map<String, Object> searchParams, HttpServletResponse response);
}
编写接口实现类:
package com.yonyou.occ.report.service.impl;
import cn.hutool.poi.excel.ExcelUtil;
import com.yonyou.occ.report.service.EmailSendService;
import com.yonyou.occ.report.utils.BeanConverterUtils;
import com.yonyou.occ.report.vo.CustomerPromActivityDetailVO;
import com.yonyou.ocm.common.utils.DateUtil;
import jxl.Workbook;
import jxl.format.Colour;
import jxl.format.UnderlineStyle;
import jxl.write.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author
* @date 2020-11-23 9:56
*/
@Slf4j
@Service
public class EmailSendServiceImpl implements EmailSendService {
/**
* 将邮件工具放入容器
*/
private JavaMailSenderImpl mailSenderImpl;
@Autowired
public void setMailSenderImpl(JavaMailSenderImpl mailSender) {
this.mailSenderImpl = mailSender;
}
@Autowired
private CustomerPromActivityDetailServiceImpl customerPromActivityDetailServiceImpl;
/**
* 定义模板文件所在的相对路径, File.separator表示文件分隔符,可自动适配Windows和Linux系统
*/
private static String PATH = "." + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + "templates" + File.separator;
//发件人邮箱地址
@Value("${spring.mail.send.from}")
private String mailSendFrom;
//收件人邮箱地址
@Value("${spring.mail.send.to}")
private String mailSendTo;
//抄送人邮箱地址
@Value("${spring.mail.send.cc}")
private String mailSendCc;
/**
* 根据参数发送邮件
*
* @param searchParams
* @param response
*/
@Override
public void sendMail(Map<String, Object> searchParams, HttpServletResponse response) {
try {
String dateStr = DateUtil.from_Date_to_String(DateUtil.yyMMddHHmmss, new Date());
List<CustomerPromActivityDetailVO> customerPromActivityDetailVOS = customerPromActivityDetailServiceImpl.exportExcelData(searchParams, response);
if (!StringUtils.isEmpty(customerPromActivityDetailVOS)) {
List<Map<String, Object>> listMap = BeanConverterUtils.listConvert(customerPromActivityDetailVOS);
StringBuilder fileName = new StringBuilder();
// 表格名字
String name = "客户活动明细报表_" + dateStr;
fileName.append(name).append(".xls");
String filePath = PATH + fileName.toString();
File file = new File(filePath);
// 文件为空则进行创建
if (!file.exists()) {
//先得到文件的上级目录,并创建上级目录,在创建文件
file.getParentFile().mkdir();
try {
//创建文件
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
log.info("-------------- 临时文件创建失败 ----------------" + e.getMessage());
}
}
// 建立excel表格
OutputStream os = new FileOutputStream(filePath);
String[] titleArr = new String[] { "客户编码", "客户名称", "市场区域", "省份", "活动编码", "活动名称", "活动节点名称", "活动审批状态", "活动状态", "活动开始时间", "活动结束时间", "销售合同编码", "合同状态", "活动单位组金额", "收款单认领金额", "收款单认领组数", "授信组数", "授信额度", "活动明细行号", "促销规则编码", "促销规则名称", "规则描述", "活动促销方式", "产品组编码", "产品组名称", "控制类型", "项目类型", "行单位组数量", "行单位组金额", "合计", "零售价", "折扣", "价格", "边界值", "累计参加组数", "活动可提货组数", "活动可提货金额", "明细总金额", "累计行提货金额", "未提货金额", "实际未提货金额", "明细总数量", "累计行提货数量", "未提货数量", "实际未提货数量", "是否计任务", "是否计返点", "是否必选", "冻结值", "冻结金额", "未使用冻结金额", "已使用冻结金额", "是否关闭", "活动关闭回退金额", "货款余额", "零售价余额", "客户活动行备注" };
String[] codeArr = new String[] { "customerCode", "customerName", "marketName", "provinceName", "activityCode", "activityName", "nodeName", "activityApproval", "activityStatusName", "startDate", "endDate", "ctCode", "ctStateName", "activityUnitGroupAmount", "totalClaimAmount", "claimGroup", "creditGroup", "creditLimit", "rowNum", "ruleCode", "ruleName", "ruleDesc", "ruleTypeName", "goodsCode", "goodsName", "controlTypeName", "projectType", "count", "amount", "total", "retailPrice", "rebate", "salePrice", "boundaryValue", "totalClaimGroup", "pickUpGroup", "pickUpAmount", "totalrowCtAmount", "totalrowOrderAmount", "notPickedUpAmount", "actualUndeliveredGoodsAmount", "totalrowCtNum", "totalrowOrderNum", "notPickedUpNum", "actualUndeliveredGoodsNum", "isCalTaskName", "isCalReturnName", "isRequireName", "freezeValue", "freezeAmount", "unuseFreezeAmount", "useFreezeAmount", "isCtClose", "returnAmount", "paymentBalance", "retailBalance", "lineRemark" };
//导出数据到excel
exportExcel(os, listMap, titleArr, codeArr, name);
// 是否需要发邮件,根据配置是否为空来判断
if (!mailSendTo.isEmpty()) {
// 将excel作为附件发送,并删除本地的excel文件
String subject = "客户活动明细报表";
String content = "你好,这是客户活动明细报表的数据,请查收!";
MimeMessage mailMessage = mailSenderImpl.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage, true, "utf-8");
// 发送方邮箱
messageHelper.setFrom(mailSendFrom);
// 接收方邮箱
if(mailSendTo.contains("{") && mailSendTo.contains("}")) {
String sendTo = mailSendTo.replace("{", "").replace("}", "");
String[] mailSendTos = sendTo.split(",");
messageHelper.setTo(mailSendTos);
} else if(mailSendTo.contains("{")) {
String sendTo = mailSendTo.replace("{", "");
String[] mailSendTos = sendTo.split(",");
messageHelper.setTo(mailSendTos);
} else if(mailSendTo.contains("}")){
String sendTo = mailSendTo.replace("}", "");
String[] mailSendTos = sendTo.split(",");
messageHelper.setTo(mailSendTos);
} else {
messageHelper.setTo(mailSendTo);
}
// 抄送方邮箱
messageHelper.setCc(mailSendCc);
// 设置邮件主题
messageHelper.setSubject(subject);
// 设置邮件主题内容
messageHelper.setText(content);
// 读取附件
FileSystemResource fileR = new FileSystemResource(new File(filePath));
// 这里的方法调用和插入图片是不同的。
// 设置附件
messageHelper.addAttachment(fileName + "", fileR);
long startTime = System.currentTimeMillis();
log.info("----------------- 发送邮件开始 -------------- " + startTime);
// 发送邮件
mailSenderImpl.send(mailMessage);
long endTime = System.currentTimeMillis();
log.info("----------------- 发送邮件成功,任务结束 -------------------- 用时" + (endTime - startTime) + "ms");
} else {
log.info("----------------- 发件邮箱或收件邮箱未配置,不发送报表数据邮件 --------------------");
}
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
log.info("------------------ 临时文件删除成功 --------------------");
}
}
} catch (Exception e) {
log.error("【客户活动明细报表】邮件发送异常:", e);
e.printStackTrace();
}
}
public static void exportExcel(OutputStream os, List<Map<String, Object>> list, String[] titleArr, String[] codeArr, String name){
try {
//创建一个工作簿,也就是整个文档
WritableWorkbook wbook = Workbook.createWorkbook(os);
//设置字体
WritableFont wfont = new WritableFont(WritableFont.ARIAL, 10,
WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE,
Colour.BLACK);
//定义单元格格式
WritableCellFormat wcf = new WritableCellFormat(wfont);
double maxSheetSize = 600000.0;
int sheetNum = (int) Math.ceil(list.size() / maxSheetSize);
for(int num = 0; num < sheetNum; num++){
WritableSheet wsheet = wbook.createSheet(name + "("+(num+1)+")", num);
String title=null;
for(int i=0; i<titleArr.length; i++){
title = titleArr[i];
wsheet.addCell(new Label(i, 0, title, wcf));
}
for(int i = num*(int)maxSheetSize ; i < (num+1)*(int)maxSheetSize && i < list.size(); i++){
Map<String, Object> m = list.get(i);
int temp = i - num*(int)maxSheetSize + 1;
for(int j=0; j<codeArr.length; j++){
String value = String.valueOf(m.get(codeArr[j])==null?"":m.get(codeArr[j]));
wsheet.addCell(new Label(j, temp, value));
}
}
}
wbook.write();
wbook.close();
os.close();
}catch(Exception e){
log.info("exception heppended in "+ ExcelUtil.class+" cause: ", e);
}
}
}
至此,邮箱发送功能实现到此结束。欢迎大佬们评论指导!