邮件发送在实际业务中的使用

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

前言

在前面的文章里有介绍过hutool工具的邮件发送,但是在实际的业务中并不是调用其sendMail方法就能实现业务的,有时候我们得对其进行改造或者自己写方法实现,那今天来看看我是如何实现发送邮件及多个附件功能的。

一.实现思路

先实现动态Excel实现再实现邮件发送多人及多附件,动态生成Excel的是因为业务需要的Excel表格数据可能会根据后期的需要增加或减少字段,所以不能固定,可以通过SQL查询出来然后根据字段创建动态表头和对应的数据列,其次是发送邮件时需要发送多个附件,如果是先生成到本地再从本地取到再作为附件发送有点不太好,可以用数据流的方式发送生成的Excel文件,这个点也是行得通的,那下面来看看具体的实现吧。

二.具体实现

1.生成动态Excel

1)动态表头生成

/***
 * 动态创建表头 
 * @param map 
 * @return
 */
public static String[] createTitle(Map<String, Object> map) {
    int count = 0;
    String strings[] = new String[map.size()];
    for( Map.Entry<String, Object> entry : map.entrySet() ) {
        strings[count] = entry.getKey();
        count++;
    }
    return strings;
}
复制代码

2)绘制Excel,包括表头以及数量类型的一些简单处理

  /**
     * 创建Excel
     * @param sheetName sheet名称
     * @param title     标题
     * @param values    内容
     * @param wb        HSSFWorkbook对象
     * @return
     */
    public static HSSFWorkbook createHSSFWorkbook(String sheetName, String[] title, String[][] values, HSSFWorkbook wb) {
        // 第一步,创建一个HSSFWorkbook,对应一个Excel文件
        if (wb == null) {
            wb = new HSSFWorkbook();
        }
        // 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步,创建单元格,并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER); // 创建一个居中格式
        //声明列对象
        HSSFCell cell = null;
        //创建标题
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }
        HSSFCellStyle contextstyle =wb.createCellStyle();
        //创建内容
        for (int i = 0; i < values.length; i++) {
            row = sheet.createRow(i + 1);
            for (int j = 0; j < values[i].length; j++) {
                Boolean isNum = false;
                Boolean isInteger=false;//data是否为整数
                HSSFCell contentCell = row.createCell(j);
              //将内容按顺序赋给对应的列对象
                if (null!=values[i][j] || "".equals(values[i][j])) {
                    //判断data是否为数值型
                    isNum = values[i][j].toString().matches("^(-?\d+)(\.\d+)?$");
                    //判断data是否为整数(小数部分是否为0)
                    isInteger=values[i][j].toString().matches("^[-\+]?[\d]*$");
                }
                // 此处设置数据格式
                if (isNum) {
                    HSSFDataFormat df = wb.createDataFormat(); 
                    if (isInteger) {
                    //数据格式只显示整数
                     contextstyle.setDataFormat(df.getBuiltinFormat("#,#0"));
                    }else{
                    /保留一位小数点
                     contextstyle.setDataFormat(df.getBuiltinFormat("#,##0.0"));/
                    }
                    // 设置单元格格式
                    contentCell.setCellStyle(contextstyle);
                    // 设置单元格内容为double类型
                    contentCell.setCellValue(Double.parseDouble(values[i][j]));
                } else {
                    contentCell.setCellStyle(contextstyle);
                    // 设置单元格内容为字符型
                    contentCell.setCellValue(values[i][j]);
                }
            }
            //设置自动列宽
            sheet.autoSizeColumn(i);
            sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 10);
        }
        return wb;
    }
复制代码

3)组装数据,将MySQL里查询的数据,组整到一个List<LinkedHashMap<String, Object>>里,为什么是LinkedHashMap而不是Map,这里有一个小细节,MySQL查询出来不一定按照数据库看到的顺序,所以得使用LinkedHashMap去接收,即将其变成有顺的

image.png

2.发送邮件

1)发送多人及多个附件

/**
 * @param subject 邮件标题
 * @param mapList 附件信息 可多附件
 * @param content 邮件内容
 * @param receiveList 收件人集合
 */
public static void sendEmail(String subject, List<Map<String,Object>> mapList, String content, List<String> receiveList, String smtpHost, String userName, String password) {
    logger.info("send report start>>>>>>>>>>>>");
    Session session = EmailUtils.getSession(smtpHost, userName, password);
    MimeMessage message = new MimeMessage(session);
    InternetAddress[] toArray = new InternetAddress[receiveList.size()];
    try {
        //接收列表
        for (int i = 0; i < toArray.length; i++) {
            toArray[i] = new InternetAddress(receiveList.get(i));
        }
        message.setSubject(subject);
        message.setSentDate(new Date());
        message.setFrom(new InternetAddress(userName));
        message.addRecipients(MimeMessage.RecipientType.TO, toArray);
        // 创建消息部分
        BodyPart messageBodyPart = new MimeBodyPart();
        // 消息
        messageBodyPart.setContent(content, "text/html;charset=utf-8");
        // 创建多重消息及可以发送多个附件
        Multipart multipart = new MimeMultipart();
        // 设置文本消息部分
        multipart.addBodyPart(messageBodyPart);
        //添加附件 这里以流形式直接发送
        for (Map<String, Object> map : mapList) {
            messageBodyPart = new MimeBodyPart();
            DataSource source = new ByteArrayDataSource((byte[])map.get("os"), "application/excel");
            messageBodyPart.setDataHandler(new DataHandler(source));
            //避免中文乱码的处理
            messageBodyPart.setFileName(MimeUtility.encodeText(map.get("title") + ".xlsx"));
            multipart.addBodyPart(messageBodyPart);
        }
        // 发送完整消息
        message.setContent(multipart);
        // 发送消息
        Transport.send(message);
        logger.info("send email successful>>>>>>>>>>>>");
    } catch (Exception e) {
        e.printStackTrace();
        logger.error("send email error",e.getMessage());
    }
}
复制代码

2)发送结果及数据,@1为目标邮件收到邮件的截图,@2为测试数据,@2中箭头标注的就是SQL里的字段,直接查询出中文然后通过createTitle创建表头,并根据其长度生成对应的列

@1image.png

@2image.png 2)关于收件人配置

这里收件人可以配置到数据库或者Redis,需要添加或者删除改了立即生效,因为也不是常用的,没有必要放到配置文件里。

三.常见报错及解决

1.明明已开启SMTP但是过段时间后报了@1的错误,解决办法。重新生成授权码@2并替换之前设置的密码,此处是新浪邮箱为示例。

@1image.png

@2Snipaste_2022-02-21_23-17-32.png

小结

很多人估计在拿到需求的时候就开始写代码,其实这样写出来的代码质量并不高,拿到需求应该先打个草稿或者画个图应该怎么处理,再怎么处理,代码虽然都是改出来的,后者的效率肯定要高很多,还有就是开发的时候能写灵活方法就写灵活的,别只顾着当前业务实现就行了。另外因为篇幅的限制,部分代码只能是截图的方式展示。

Guess you like

Origin juejin.im/post/7068270757335285768