Java&POI以流的形式的形式生成Excel文件并作为邮件附件发送(不生成实际Excel文件)

近期项目开发设计一个批处理报表数据的展示,原本是将数据以前台模板Thymylef的形式下展示发送邮件的,近期生产报出严重问题数据量太大超过200m无法发送成功邮件,以致添加新的需求,将数据放到附件excel发送。

注意我们的方法不生成文件,再服务器上生成文件再取再存入附件太过麻烦,而且大多数生产服务器是不允许你有这个权限,所以我们用流的方式存储。POI生成流

public static ByteArrayOutputStream createExcel(List<Map<String, Object>> excelDataList) {
        try {
            // 1、创建一个流文件
            ByteArrayOutputStream excel = new ByteArrayOutputStream();
            //创建一个excel
            WritableWorkbook workbook = Workbook.createWorkbook(excel);

            //  2、创建一个Excel的工作表sheet
            WritableSheet sheet = workbook.createSheet("指标群异常数据", 0);

            //  3、样式设置
            WritableFont bold = new WritableFont(WritableFont.createFont("微软雅黑"), 12, WritableFont.BOLD);
            WritableFont noBold = new WritableFont(WritableFont.createFont("微软雅黑"), 12, WritableFont.NO_BOLD);

            WritableCellFormat titleFormate = new WritableCellFormat(bold);
            // 设置单元格中的内容水平方向居中、垂直方向居中设置边框
            titleFormate.setAlignment(jxl.format.Alignment.CENTRE);
            titleFormate.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
            titleFormate.setBorder(Border.ALL, BorderLineStyle.THIN);

            // 设置正文内容样式,单元格样式控制对象
            WritableCellFormat textFormat = new WritableCellFormat(noBold);
            //  单元格中的内容水平方向居中、垂直方向居中、设置边框
            textFormat.setAlignment(jxl.format.Alignment.CENTRE);
            textFormat.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
            textFormat.setBorder(Border.ALL,BorderLineStyle.THIN);

            //  3.4、窗口冻结第一行
            sheet.getSettings().setVerticalFreeze(1);
            //sheet.getSettings().setHorizontalFreeze(2);//冻结 2列两行

            //  3.5、设置行高--第一行标题行
            sheet.setRowView(0,500);

            //  3.6、设置列宽
            sheet.setColumnView(0,15);
            sheet.setColumnView(1,25);
            sheet.setColumnView(2,30);
            sheet.setColumnView(3,15);
            sheet.setColumnView(4,15);
            sheet.setColumnView(5,20);


            //  4、构造表头
            ExcelUtil.setSheetHeader(sheet, titleFormate);

            //  5、填充数据
            ExcelUtil.setSheetData(sheet, textFormat, 1, excelDataList);
            workbook.write();
            workbook.close();
            return excel;
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("创建邮件失败");
        }
    }

因为生成的临时文件我不需要放到本地,所以这里直接用了一个字节流来存储excel信息

private static void setSheetHeader(WritableSheet sheet, WritableCellFormat titleFormate) throws WriteException {
        // 构造表头
        //mergeCells(0, 0, 0, 0) 表示不合并; sheet.mergeCells(1,0,2,0)表示第2列和第3列合并成一列
        //Label label_20 = new Label(2, 0, "描述", cellFormat); 前面的数字表示第几列,第几行
        //4.1、创建表数据
        List<String> titleList = Arrays.asList("测试1", "测试2", "测试3", "测试4", "测试5", "测试6");
        for (int i = 0; i < titleList.size(); i++) {
            Label label_00 = new Label(i,0, titleList.get(i), titleFormate);
            sheet.addCell(label_00);
        }

    }

表头以及信息方便展示,我就是固定死了,也可以用数据库中的数据

private static void setSheetData(WritableSheet sheet, WritableCellFormat textFormat, int startRow, List<Map<String,Object>> excelDataList) throws WriteException {
        for (int i = 0; i < excelDataList.size(); i++, startRow++) {
            Map excelData = excelDataList.get(i);
            Label label_02 = new Label(0, startRow, (String) excelData.get("INDEX_CODE"), textFormat);
            sheet.addCell(label_02);
            Label label_12 = new Label(1, startRow, (String) excelData.get("INDEX_NAME"), textFormat);
            sheet.addCell(label_12);
            Label label_22 = new Label(2, startRow, (String) excelData.get("IND_CONDITION"), textFormat);
            sheet.addCell(label_22);
            Label label_32 = new Label(3, startRow, (String) excelData.get("STATISTICAL_FREQUENCY"), textFormat);
            sheet.addCell(label_32);
            Label label_42 = new Label(4, startRow, (String) excelData.get("exceptionDate"), textFormat);
            sheet.addCell(label_42);
            Label label_52 = new Label(5, startRow, (String) excelData.get("msg"), textFormat);
            sheet.addCell(label_52);
        }
    }

excelDataList就是要插入的行数据了,通过循环将数据插入到这些列中。当然列信息也是可以写成动态的,不过我只需要几列,也是固定死了。

上面代码执行完成之后,就得到了一个ByteArrayOutputStream类的excel流文件

// 将流文件存到字节数组缓冲区 (以上的所有代码可放在一个方法体中 设置格式设置字体添加信息转换字节流 然后将ByteArrayInputStream作为return的对象返回,因为mail附件的格式是要求是InputStream格式的)
        ByteArrayInputStream excelAttachment = new ByteArrayInputStream(excel.toByteArray());
        

然后将流文件放到字节数组缓冲区中,以待使用。接下来就是创建邮件发送类

try {
            // 创建邮件发送类
            JavaMailSenderImpl javaMailSender = setMailSender();

            // 创建邮件信息类
            MimeMessage msg = javaMailSender.createMimeMessage();
            // 创建MimeMessageHelper对象,MimeMessage的辅助类
            MimeMessageHelper message = new MimeMessageHelper(msg, true);

            message.setFrom(javaMailSender.getUsername());
            String[] emailArray = emailList.toArray(new String[emailList.size()]);
//            message.setTo(emailArray);
            // 要发送的账号
            message.setTo("***********@qq.com");

            // 标题
            message.setSubject(INDEX_CODE + "——" + INDEX_NAME + "——" + STATISTICAL_FREQUENCY + "——指标异常");

            // 主体
            message.setText(generateEmailMsg(item));

            ByteArrayDataSource file = new ByteArrayDataSource(excelAttachment, "application/vnd.ms-excel;charset=UTF-8");
            // 附件 关键部分
            message.addAttachment(MimeUtility.encodeWord("指标异常数据信息.xls","utf-8","B"),file);

            javaMailSender.send(msg);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("邮件发送失败!" + e);
        }

至于发送邮件以及类的方法我就不一一展示了,说一下注意的坑点。我之前者应部署后会报一个错误JavaMailSender with Exception writing Multipart。

  • 使用存在方法检查文件是否在FileSystemResource中退出
  • 请发布完整的异常堆栈跟踪。
    我去搜了解决办法是因为它默认判断我的主体是空的,所以我把 message.setText 放在添加附件代码的下面就行了按循序执行就可以正常发送了。很神奇

           
            ByteArrayDataSource file = new ByteArrayDataSource(excelAttachment, "application/vnd.ms-excel;charset=UTF-8");
            // 附件 关键部分
            message.addAttachment(MimeUtility.encodeWord("指标异常数据信息.xls","utf-8","B"),file);
            message.setText(generateEmailMsg(item));
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
可以使用Apache POI生成Excel文件。以下是示例Java代码: ```java import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.mail.MessagingException; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelGenerator { public static MimeMultipart generateExcel() throws IOException, MessagingException { // Create a new workbook Workbook workbook = new XSSFWorkbook(); // Create a sheet in the workbook Sheet sheet = workbook.createSheet("Sheet1"); // Create a header row Row headerRow = sheet.createRow(0); Cell headerCell = headerRow.createCell(0); headerCell.setCellValue("Header"); // Create some data rows Row dataRow = sheet.createRow(1); Cell dataCell = dataRow.createCell(0); dataCell.setCellValue("Data"); // Write the workbook to a byte array output stream ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); workbook.write(outputStream); // Create a MIME body part for the Excel attachment MimeBodyPart attachmentPart = new MimeBodyPart(); attachmentPart.setFileName("example.xlsx"); attachmentPart.setContent(outputStream.toByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // Create a MIME multipart message with the Excel attachment MimeMultipart multipart = new MimeMultipart(); multipart.addBodyPart(attachmentPart); return multipart; } } ``` 该代码使用XSSFWorkbook来创建一个工作簿,并在其中创建一个名为“Sheet1”的工作表。该代码还创建一个标题行和一个数据行,然后将工作簿写入ByteArrayOutputStream。最后,该代码将Excel文件作为附件添加到MIME多部分消息中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值