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));