由于最近项目原因需要使用Java将数据导出成excel文件并发送给某邮箱,借鉴了各位前辈大佬们的经验写了个简单的demo方法。现将代码记录如下:
详细介绍可参考:https://www.cnblogs.com/huajiezh/p/5467821.html
poi 表格背景色:https://www.cnblogs.com/toumh/p/npoi-color-value.html
总体的思路就是:1、使用poi工具的HSSFWorkbook类创建一张表
2、创建行(row),自定义相关行的样式或内容来生成标题、表头或表数
据
3、行内创建单元格(cell),每个cell对应行内一个列元素,所以填充的数
组或集合必须是有序的
一、首先是使用到的依赖jar包
<!-- poi excel生成依赖jar--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency>
<!--发送邮件依赖jar包--> <!-- https://mvnrepository.com/artifact/javax.mail/javax.mail-api --> <dependency> <groupId>javax.mail</groupId> <artifactId>javax.mail-api</artifactId> <version>1.6.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.1</version> </dependency>
二、cell单元格工具类
这个类是自己编写用于筛除一些表数据BUG的,实际上可以不使用
package com.demo.po; import org.apache.poi.hssf.usermodel.HSSFCell; import java.math.BigDecimal; import java.sql.Date; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.regex.Pattern; public class CellUtil { public static String returnCellValue(HSSFCell cell){ String cellvalue = ""; if (null != cell) { switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_NUMERIC: // 数字 return String.valueOf(cell.getNumericCellValue()).trim(); case HSSFCell.CELL_TYPE_STRING: // 字符串 return String.valueOf(cell.getStringCellValue()).trim(); case HSSFCell.CELL_TYPE_BOOLEAN: // Boolean return String.valueOf(cell.getBooleanCellValue()).trim(); case HSSFCell.CELL_TYPE_FORMULA: // 公式 return String.valueOf(cell.getCellFormula()).trim(); case HSSFCell.CELL_TYPE_BLANK: // 空值 return ""; case HSSFCell.CELL_TYPE_ERROR: // 故障 return ""; default: return ""; } } else { } return cellvalue; } //避免cell.setCellValue(checkOrderQmSave.getSellOrderNo())中参数为空就会报错 public static void setCellValue(HSSFCell cell, Object object){ if(object == null){ cell.setCellValue(""); }else{ if (object instanceof String) { cell.setCellValue(String.valueOf(object)); }else if(object instanceof Long){ Long temp = (Long)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Double){ Double temp = (Double)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Float){ Float temp = (Float)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Integer){ Integer temp = (Integer)object; cell.setCellValue(temp.intValue()); }else if(object instanceof BigDecimal){ BigDecimal temp = (BigDecimal)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else{ cell.setCellValue(""); } } } public static void setCellValue(HSSFCell cell, Object object, String model){ if(object == null){ cell.setCellValue(""); }else{ if (object instanceof String) { cell.setCellValue(String.valueOf(object)); }else if(object instanceof Long){ Long temp = (Long)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Double){ Double temp = (Double)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Float){ Float temp = (Float)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Integer){ Integer temp = (Integer)object; cell.setCellValue(temp.intValue()); }else if(object instanceof BigDecimal){ BigDecimal temp = (BigDecimal)object; String cellvalue = new DecimalFormat("#0.00").format(temp.doubleValue()); cell.setCellValue(cellvalue); }else if(object instanceof Date){ cell.setCellValue(new SimpleDateFormat(model).format(object)); }else if(object instanceof java.util.Date){ cell.setCellValue(new SimpleDateFormat(model).format(object)); }else{ cell.setCellValue(""); } } } public static void setCellValue(HSSFCell cell, String object){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(object); } } public static void setCellValue(HSSFCell cell, Long object){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(object.doubleValue()); } } public static void setCellValue(HSSFCell cell, Double object){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(object.doubleValue()); } } public static void setCellValue(HSSFCell cell, double object){ cell.setCellValue(object); } public static void setCellValue(HSSFCell cell, Date object, String model){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(new SimpleDateFormat(model).format(object)); } } public static void setCellValue(HSSFCell cell, java.util.Date object, String model){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(new SimpleDateFormat(model).format(object)); } } public static void setCellValue(HSSFCell cell, BigDecimal object){ if(object == null){ cell.setCellValue(""); }else{ cell.setCellValue(object.toString()); } } //判断EXCEL表格高度用 row.setHeight((short) CellUtil.getExcelCellAutoHeight(TAR_VAL_ALL_STRING, 280, 30)); public static float getExcelCellAutoHeight(String str, float defaultRowHeight, int fontCountInline) { int defaultCount = 0; for (int i = 0; i < str.length(); i++) { int ff = getregex(str.substring(i, i + 1)); defaultCount = defaultCount + ff; } if (defaultCount > fontCountInline){ return ((int) (defaultCount / fontCountInline) + 1) * defaultRowHeight;//计算 } else { return defaultRowHeight; } } public static int getregex(String charStr) { if("".equals(charStr) || charStr == null){ return 1; } // 判断是否为字母或字符 if (Pattern.compile("^[A-Za-z0-9]+$").matcher(charStr).matches()) { return 1; } // 判断是否为全角 if (Pattern.compile("[\u4e00-\u9fa5]+$").matcher(charStr).matches()) { return 2; } //全角符号 及中文 if (Pattern.compile("[^x00-xff]").matcher(charStr).matches()) { return 2; } return 1; } }
三、表格创建并发送邮件
这一段是重点!这一段是重点!这一段是重点!
package com.demo; import com.bnwisdom.dao.BnVoteDao; import com.bnwisdom.dao.BnVoteOptionDao; import com.bnwisdom.dao.BnVoteOptionGroupDao; import com.bnwisdom.dao.BnVoteRecordsDao; import com.bnwisdom.po.ApiResult; import com.bnwisdom.po.CellUtil; import com.bnwisdom.po.ConfigUtils; import com.bnwisdom.service.ExportSendMailService; import com.bnwisdom.vo.BnVoteOptionGroupVo; import com.bnwisdom.vo.BnVoteOptionVo; import com.bnwisdom.vo.BnVoteVo; import org.apache.log4j.Logger; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.mail.*; import javax.mail.internet.*; import javax.mail.util.ByteArrayDataSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Author 一只菜鸡 * @CreateTime 2019/4/1 14:32 * @Version 1.0 * @Descr **/ public class ExportSendMail{ //日志打印 Logger log=Logger.getLogger(ExportSendMailServiceImpl.class); public String exportSendEmail(String userEmail) throws Exception { //表的标题名称 String sheetName="教师满意度调查(投票统计表)"; //表头集合 List<String> tableHead=new ArrayList<String>(); tableHead.add("投票对象") tableHead.add("很满意") tableHead.add("满意") . . . . //表格内数据内容,此处为一个双层集合数组,外层数组代表的是总的表格内容,数组长度为行数(不包括标题和表头), //第二层数组类似于行,数组内每个元素对应一个单元格,因此二层数组长度应与表头数组长度一致,不然会出现单元格缺失 List<List<Object>> tableBody=new ArrayList<>(); List<Object> tableRow1=new ArrayList<>(); tableRow1.add("张三"); tableRow1.add(2); tableRow1.add(1); . . . . List<Object> tableRow2=new ArrayList<>(); tableRow2.add("李四"); tableRow2.add(1); tableRow2.add(2); . . . . tableBody.add(tableRow1); tableBody.add(tableRow2); boolean boo = false; try { InputStream is = exportXls(sheetName,tableHead,tableBody); if(is == null){ return "创建表格失败"; }else{ boo = sendMail(is, sheetName, userEmail); is.close(); } } catch (Exception e) { e.printStackTrace(); } if (boo) { return "导出成功"; } else { return "导出数据失败"; } } /** * 生成表格并返回结果流 * @param sheetName 表名 * @param tableHead 表头 * @param tableBody 表格数据(双层集合数组) * @return 生成的表格以流的形式返回 * @throws Exception */ public InputStream exportXls( String sheetName,List<String> tableHead,List<List<Object>> tableBody) throws Exception { HSSFWorkbook workbook = new HSSFWorkbook(); // 创建一张excel表 HSSFSheet sheet = workbook.createSheet(sheetName); // ---------------- 表标题样式 ------------------- HSSFFont headfont = workbook.createFont(); headfont.setFontName("宋体"); // 设置字体大小 headfont.setFontHeightInPoints((short) 18); //粗体显示 headfont.setBold(true); //设置单元格样式 HSSFCellStyle headstyle = workbook.createCellStyle(); //设置文字样式 headstyle.setFont(headfont); // 单元格内容左右居中 // 设置单元格上下居中 headstyle.setAlignment(HorizontalAlignment.CENTER); headstyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置标题固定 headstyle.setLocked(true); // --------------- 表头样式 ----------------- HSSFFont font = workbook.createFont(); font.setFontName("宋体"); font.setFontHeightInPoints((short) 12); HSSFCellStyle style = workbook.createCellStyle(); //设置表头背景色 style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index); style.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); //单元格边框属性设置 style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); style.setFont(font); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setLocked(true); // -------------- 普通单元格样式(中文) --------------- HSSFFont font2 = workbook.createFont(); font2.setFontName("宋体"); font2.setFontHeightInPoints((short) 12); font2.setBold(true); HSSFCellStyle style2 = workbook.createCellStyle(); style2.setBorderBottom(BorderStyle.THIN); style2.setBorderLeft(BorderStyle.THIN); style2.setBorderRight(BorderStyle.THIN); style2.setBorderTop(BorderStyle.THIN); style2.setFont(font2); // 设置单元格内容自动换行 style2.setWrapText(true); style2.setAlignment(HorizontalAlignment.CENTER); style2.setVerticalAlignment(VerticalAlignment.CENTER); //设置默认行高 sheet.setDefaultRowHeight((short)360); // 第一行,添加表的标题 sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, tableHead.size()-1)); HSSFRow row = sheet.createRow(0); row.setHeight((short) 0x349); HSSFCell cell = row.createCell(0); cell.setCellStyle(headstyle); CellUtil.setCellValue(cell, sheetName); //第二行,添加表头 row = sheet.createRow(1); row.setHeight((short)0x180); for (int j = 0; j < tableHead.size(); j++) { //设置每列的宽度 (自定义列宽) 4200为每列最小宽度 int dataLength=tableHead.get(j).getBytes().length*2*232; sheet.setColumnWidth((short)j,dataLength<4200?4200:dataLength); //在行内创建一个单元格 cell = row.createCell(j); //单元格设置自定样式 style(上边有定义) cell.setCellStyle(style); cell.setCellType(HSSFCell.CELL_TYPE_STRING); //将数据填充进表格内 cell:创建的单元格 tableHead.get(j):数据 CellUtil.setCellValue(cell, tableHead.get(j)); } // 设置列值-每行数据的内容 for (int i = 0; i < tableBody.size(); i++) { //标题、表头字段共占了2行,所以在填充数据的时候要加2,也就是数据要从第3行开始填充 row = sheet.createRow(i + 2); for (int j = 0; j < tableBody.get(i).size(); j++) { cell = row.createCell(j); cell.setCellStyle(style2); cell.setCellType(HSSFCell.CELL_TYPE_STRING); CellUtil.setCellValue(cell, tableBody.get(i).get(j)); } } //以下代码需要修改为下载到某个路径 ByteArrayOutputStream bos = new ByteArrayOutputStream(); workbook.write(bos); return new ByteArrayInputStream(bos.toByteArray()); } /** * 发送邮件 * @param is 表格输出流 * @param fileName 发送的文件名称 (例:xxxx统计表) * @param reUserMail 收件人邮箱(例:[email protected]) */ public boolean sendMail(InputStream is, String fileName, String reUserMail){ log.info("[ 开始发送邮件... ]"); Transport transport = null; try{ System.setProperty("mail.mime.splitlongparameters","false"); Properties props = new Properties(); // 设置发送邮件的邮件服务器的属性(这里使用网易的smtp服务器) props.put("mail.smtp.host","smtp.exmail.qq.com"); // 需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条) props.put("mail.smtp.auth", "true"); // 用刚刚设置好的props对象构建一个session Session session = Session.getDefaultInstance(props); // 有了这句便可以在发送邮件的过程中在console处显示过程信息,供调试使 // 用(你可以在控制台(console)上看到发送邮件的过程) session.setDebug(false); // 用session为参数定义消息对象 MimeMessage message = new MimeMessage(session); // 加载发件人地址 message.setFrom(new InternetAddress("[email protected]"/*删除此段-发件邮箱*/)); // 加载收件人地址 message.addRecipient(Message.RecipientType.TO, new InternetAddress(reUserMail)); // 加载标题 message.setSubject(fileName); // 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件 Multipart multipart = new MimeMultipart(); // 设置邮件的文本内容 BodyPart contentPart = new MimeBodyPart(); contentPart.setText("请查看附件"); multipart.addBodyPart(contentPart); // 添加附件 BodyPart messageBodyPart = new MimeBodyPart(); DataSource source = new ByteArrayDataSource(is, "application/msexcel"); // 添加附件的内容 messageBodyPart.setDataHandler(new DataHandler(source)); // 添加附件的标题 // 这里很重要,通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码 messageBodyPart.setFileName(MimeUtility.encodeText(fileName+".xls")); multipart.addBodyPart(messageBodyPart); // 将multipart对象放到message中 message.setContent(multipart); // 保存邮件 message.saveChanges(); // 发送邮件 transport = session.getTransport("smtp"); // 连接服务器的邮箱 transport.connect("smtp.exmail.qq.com", "aaaa"/*删除此段-发件人名称*/, "123456"/*删除此段-发件人邮箱密码*/); // 把邮件发送出去 transport.sendMessage(message, message.getAllRecipients()); return true; }catch (Exception e){ e.printStackTrace(); return false; }finally { try { transport.close(); }catch (Exception e){ e.printStackTrace(); } } } }
附上一张效果截图