900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Java使用阿里邮箱生成excle邮件附件发送

Java使用阿里邮箱生成excle邮件附件发送

时间:2020-05-12 10:16:04

相关推荐

Java使用阿里邮箱生成excle邮件附件发送

需求背景

日常工作中,对于一个码农来说,熟练使用框架之外,还需要灵活使用各类工具类,类似于导入导出,上传下载,邮件短信,语音视频等常用功能也是非常常见的需求,网上搜索的相关资料也是非常的多,今天就描述一个需求的场景,难度不是太难,只是需要注意的小细节还是挺多的,故借此契机,二狗在此将我个人实现的过程全程记录下来,希望有类似需求的朋友可以参考,但是话说到底,编程这个东西可以看,可以摘录,可以背诵,但是只有自己手敲出来的才是自己的,希望二狗的文章可以帮助更多的朋友把时间花在研究技术原理以及各类底层实现的设计艺术上,而对于业务类的需求,永远千变万化,只需要理解清楚,想顺畅了,就可以动手开干~以上一些个人理解,如有

实现功能:

每周二上午10点,以当天时间为参照时间节点,到当天之前的一周内的这个时间段,把后台的律师信息表中的律师信息,进行汇总,然后通过excel附件的形式,使用阿里邮箱发送到市场运营人员的邮箱;

需求分析:

每周二上午10点–定时任务解决(需要注意线上多台服务器跑批,执行定时任务需要添加分布锁,避免重复跑批)时间段为:(当天-当天前一周]通过Excel 附件形式,考虑使用POI生成Excel模板文件,后端读取数据进行填充使用阿里邮箱,需要准备好连接邮箱的Host,端口,协议等参数,数据上准备好收件人邮箱账号+发件人邮箱账号,密码

项目技术架构选型描述

本项目使用的是Springboot框架,一些固定参数,比如邮箱的Host,端口,协议等参数,数据上准备好收件人邮箱账号发件人邮箱账号,密码等均参数化的配置在boot框架的yml配置文件中定时任务使用注解@Scheduled(cron="")方式进行跑批,当然启动类Application类需要添加@EnableScheduling 注解以便于执行定是脚本,在此不再赘述,因为不是本文探讨的重点;本本文描述的代码基于Idea+ jdk1.8+ 数据库mysql+ Mybatis+ Gradle导包+ Redis缓存

代码过程展示

1、build.gradle 文件 的dependencies { }中先导包,如果你使用的是Maven原理也是一样,可以去 Maven中央仓库搜索你想要的包的版本的Maven写法,在此就不再赘述

//poiimplementation('org.apache.poi:poi:3.16')implementation('org.apache.poi:poi-ooxml:3.14')implementation('org.apache.poi:poi-scratchpad:3.15')//emailimplementation('org.springframework:spring-context-support')implementation('javax.mail:javax.mail-api:1.5.1')implementation('com.sun.mail:javax.mail:1.5.4')

2、yml文件内配置邮箱相关参数

email:host: port: 80senderMail: autoAdmin@senderPassword: WahahasendTo: autoMarketOne@,autoMarketSecond@

3、律师信息实体类–使用的Lombok插件通过@Data生成setter 和getter

@Datapublic class LawyerAuthenticate {/*** 主键* */private Long id;/*** 律师姓名* */private String lawName;/*** 所属律所* */private String lawFirm;/*** 律师手机号* */private String phone;/*** 律师常用邮箱* */private String mail;/*** 律师执业证号* */private String licenseNumber;/*** 律师执业证照片名字* */private String licenseName;/*** 律师执业证照片url* */private String licenseUrl;/*** 身份证照片名字* */private String idcardName;/*** 身份证照片url* */private String idcardUrl;/*** 创建日期* */private Date createDate;/*** 起始时间--不存库* */private Date startTime;/*** 截止时间--不存库* */private Date endTime;}

4、日期工具类–在本功能内仅仅用到了:nextDay(int num) 这个方法,其他日期常用方法,为了篇幅的简洁,故在此就不一一列举了

/*** 日期相关工具*/public class DateUtils {/*** 获取当前日期指定天数之后的日期.* @param num 相隔天数* @return Date 日期* @since 1.0*/public static Date nextDay(int num) {Calendar curr = Calendar.getInstance();curr.set(Calendar.DAY_OF_MONTH, curr.get(Calendar.DAY_OF_MONTH) + num);return curr.getTime();}}

4、定时任务脚本代码

*注意该接口类下的方法,为本次需求的核心方法:sendMailLawyerAuthService.sendMail();

@Slf4j@Componentpublic class SendMailOfLawyerAuthJob {@Autowiredprivate SendMailLawyerAuthService sendMailLawyerAuthService;@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Scheduled(cron = "0 0 10 ? * TUE")protected synchronized void executeInternal() throws InterruptedException {Thread.sleep((int) (Math.random() * 8000));Object judgementCount = this.getJudgementCount();if (null == judgementCount) {// 分布式锁redisTemplate.execute(new RedisCallback<Object>() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {byte[] key = redisTemplate.getStringSerializer().serialize("SendMailOfLawyerAuthJob");byte[] value = SerializationHelper.serialize("SendMailOfLawyerAuthJob");connection.setEx(key, 120, value);return null;}});Date now = new Date();//新版律师信息汇总定期发送邮件成功!try {sendMailLawyerAuthService.sendMail();} catch (Exception e){log.error("ErrorMessage: "+ e.getMessage());}//Test测试打印log.info("新版律师信息汇总定期发送邮件任务:SendMailOfLawyerAuthJob 执行完毕!");}}//分布式锁public Object getJudgementCount() {return redisTemplate.execute(new RedisCallback<Object>() {@Overridepublic Object doInRedis(RedisConnection connection) throws DataAccessException {byte[] key = redisTemplate.getStringSerializer().serialize("SendMailOfLawyerAuthJob");byte[] value = connection.get(key);return SerializationHelper.unSerialize(value);}});}}

5、核心方法sendMail() 代码示例

/**发送邮件核心方法*/public interface SendMailLawyerAuthService {void sendMail() throws IOException;}

实现类方法—此处非常重要,此处非常重要,此处非常重要(重要的是说三遍!)

/*** Created by 陈二狗 on -09-18.* Desc: 新版律师信息汇总定期发送邮件*/@Servicepublic class SendMailLawyerAuthServiceImpl implements SendMailLawyerAuthService {@Autowiredprivate LawyerAuthenticateMapper lawyerAuthenticateMapper;private static final Logger log = LoggerFactory.getLogger(SendMailLawyerAuthServiceImpl.class);@Value("${email.host}")private String emailHost;@Value("${email.port}")private int emailPort;@Value("${email.senderMail}")private String senderMail;@Value("${email.senderPassword}")private String senderPassword;@Value("${email.sendTo}")private List<String> sendTo;/**发送邮件的附件标题后缀*/private static final String FILENAME_END_PREFIX = "新版律师信息汇总.xls";/*** 发送带Excel附件的阿里企业邮件* @throws IOException*/@Overridepublic void sendMail() throws IOException {//获取当前日期的前一周日期Date startTime = DateUtils.nextDay(-7);Date endTime = new Date();//首先查库获取周期范围内的数据信息List<LawyerAuthenticate> lists = lawyerAuthenticateMapper.sendMailOfLawyerAuth(startTime, endTime);if (CollectionUtils.isEmpty(lists)) {log.info("没有需要发送的认证律师相关的邮件!");return ;}//1、调用创建邮件对象辅助方法Map<String, Object> resultMap = createSendMailHelper();Properties props = (Properties)resultMap.get("props");Authenticator authenticator = (Authenticator)resultMap.get("authenticator");Session session = Session.getInstance(props,authenticator);MimeMessage message = new MimeMessage(session);try {/*** 2、设置发件人* 其中 InternetAddress 的三个参数分别为: 邮箱, 显示的昵称(只用于显示, 没有特别的要求), 昵称的字符集编码*/message.setFrom(new InternetAddress(senderMail, "wusong", "UTF-8"));/*** 3、设置收件人--支持多个,基于收件人肯定存在的情况下哈,因为发邮件如果一个收件人都没有,我·····* To收件人 CC 抄送 BCC密送*/if (sendTo.size() > 0) {InternetAddress[] sendToInfo = new InternetAddress[sendTo.size()];for (int i = 0; i < sendTo.size(); i++) {sendToInfo[i] = new InternetAddress(sendTo.get(i), "", "UTF-8");}message.addRecipients(MimeMessage.RecipientType.TO, sendToInfo);}/*** 4、设置标题*/log.info("导出到Excel");message.setSubject("新版律师认证信息汇总表","UTF-8");HSSFWorkbook workbook = new HSSFWorkbook();CreationHelper helper = workbook.getCreationHelper();HSSFSheet sheet = workbook.createSheet("新版律师认证信息汇总表");//调用设置文件以及填充对象数据方法,具象模板文件setFileFromLawyerInfolHelper(sheet, lists);/****workBook写入输出流******/log.info("workBook写入输出流");ByteArrayOutputStream baos = new ByteArrayOutputStream();workbook.write(baos);baos.flush();baos.close();DataSource fds = new ByteArrayDataSource(baos.toByteArray(), "application/vnd.ms-excel");MimeBodyPart mbp1 = new MimeBodyPart();//此处设置的是邮件内容的body部分,可以对比效果图查看mbp1.setText("你好:\n 律师信息邮件汇总,请注意查收!");MimeBodyPart mbp2 = new MimeBodyPart();mbp2.setDataHandler(new DataHandler(fds));//5、调用格式化日期方法,生成附件标题String fileNameStr = formatDateHelper();//Javamail源码中MimeBodyPart在setFileName 时候会对文件名进行强制转码,So,针对此进行强制设置编码,避免出现乱码现象mbp2.setFileName(new String(fileNameStr.getBytes(), "ISO8859-1"));Multipart mp = new MimeMultipart();mp.addBodyPart(mbp1);mp.addBodyPart(mbp2);message.setContent(mp);/*** 6、保存邮件并发送*/log.info("保存邮件并发送");message.saveChanges();Transport transport = session.getTransport("smtp");transport.connect(emailHost, senderMail, senderPassword);transport.sendMessage(message,message.getAllRecipients());transport.close();} catch (MessagingException e) {log.error("异常信息为:"+e.getMessage());} catch (UnsupportedEncodingException e) {log.error("异常信息为:"+e.getMessage());}}/**** 创建邮件相关对象辅助方法-001* */private Map<String, Object> createSendMailHelper(){Properties props = new Properties();/**表示SMTP发送邮件,需要进行身份验证*/props.put("mail.smtp.auth", "true");/**是否启用调试*/props.put("mail.debug", "false");/**设置链接超时*/props.put("mail.smtp.timeout", "50000");/**设置端口*/props.put("mail.smtp.port", Integer.toString(emailPort));/**设置ssl端口*/props.put("mail.smtp.socketFactory.port", Integer.toString(emailPort));props.put("mail.smtp.socketFactory.fallback", "false");props.put("mail.smtp.socketFactory.class", ".ssl.SSLSocketFactory");// 发件人的账号props.put("mail.user", senderMail);// 访问SMTP服务时需要提供的密码(邮箱密码)props.put("mail.password", senderPassword);// 构建授权信息,用于进行SMTP进行身份验证Authenticator authenticator = new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {// 用户名、密码String userName = props.getProperty("mail.user");String password = props.getProperty("mail.password");return new PasswordAuthentication(userName, password);}};//封装返回对象参数数据Map<String, Object> mailMap = new HashMap<>();mailMap.put("props",props);mailMap.put("authenticator",authenticator);return mailMap;}/*** 设置文件以及填充数据辅助方法-002* */private void setFileFromLawyerInfolHelper(HSSFSheet sheet, List<LawyerAuthenticate> lists){//设置列宽度sheet.setColumnWidth(0, 20 * 256);sheet.setColumnWidth(1, 20 * 256);sheet.setColumnWidth(2, 20 * 256);sheet.setColumnWidth(3, 20 * 256);sheet.setColumnWidth(4, 20 * 256);sheet.setColumnWidth(5, 20 * 256);sheet.setColumnWidth(6, 80 * 256);sheet.setColumnWidth(7, 80 * 256);//新增数据行,并且设置单元格数据int rowNum = 1;String[] headers = { "序号","律师姓名","手机号","所属律所","邮箱","执业证号","律师执照照片","手持身份证照片"};//headers表示excel表中第一行的表头HSSFRow row = sheet.createRow(0);//在excel表中添加表头for(int i=0;i<headers.length;i++){HSSFCell cell = row.createCell(i);HSSFRichTextString text = new HSSFRichTextString(headers[i]);cell.setCellValue(text);}//在表中存放查询到的数据放入对应的列for (LawyerAuthenticate lawyerAuthInfo : lists) {HSSFRow row1 = sheet.createRow(rowNum);row1.createCell(0).setCellValue(rowNum);row1.createCell(1).setCellValue(lawyerAuthInfo.getLawName());row1.createCell(2).setCellValue(lawyerAuthInfo.getPhone());row1.createCell(3).setCellValue(lawyerAuthInfo.getLawFirm());row1.createCell(4).setCellValue(lawyerAuthInfo.getMail());row1.createCell(5).setCellValue(lawyerAuthInfo.getLicenseNumber());//由于字段的选填性,手动设置过滤字段为空if (StringUtils.isEmpty(lawyerAuthInfo.getLicenseUrl())){row1.createCell(6).setCellValue("");}else {row1.createCell(6).setCellValue(lawyerAuthInfo.getLicenseUrl());}if (StringUtils.isEmpty(lawyerAuthInfo.getIdcardUrl())){row1.createCell(7).setCellValue("");}else {row1.createCell(7).setCellValue(lawyerAuthInfo.getIdcardUrl());}rowNum++;}}/**** 创建邮件相关对象辅助方法-003* */private String formatDateHelper(){//格式化日期Date startTimeStr = DateUtils.nextDay(-7);Date endTimeStr = new Date();DateFormat sdf = new SimpleDateFormat("yyyyMMdd");String tempfileName = sdf.format(startTimeStr) + "-" + sdf.format(endTimeStr) + FILENAME_END_PREFIX ;return tempfileName;}}

邮件发送代码说明:

1)附件主题乱码,通过读取源码的setFilename()方法可以看到,源码底层对字符串进行了转码,所以我们在代码中,进行了处理,需要注意的是,不同的邮箱可能处理的方式不尽相同,此处我这里使用的是阿里企业邮箱,以下为我的处理方式:

String fileNameStr = formatDateHelper();//Javamail源码中MimeBodyPart在setFileName 时候会对文件名进行强制转码,So,针对此进行强制设置编码,避免出现乱码现象mbp2.setFileName(new String(fileNameStr.getBytes(), "ISO8859-1"));

网上很多资料说的方式是在发送邮件之前,添加修改编码代码,如果大家感兴趣可以自行百度,此处不再过多赘述;

2)附件的excel 内各列的宽度可以自定义设置调整,各位看官根据实际需要变更即可

附上效果图:红色1:发件人;红色2:多个收件人

附件详情效果图:

综上所述,整体的功能实现到此基本全部完毕,代码虽然进行了一定的抽离但是届于自身能力以及工作技术架构选型的的局限,解决方案不一定是最优解,但是可以作为有类似需求的看官浏览使用,不足之处,欢迎各位看官提出宝贵的意见,我也会积极响应,长路漫漫,其修远兮,共勉!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。