POI之EXCEL导出工具--PoiExportUtil入门优化篇--(三)
本篇章是对转载自https://blog.csdn.net/Jack__Frost/article/details/77510892的入门篇进行了稍加改动,可供大家参考。
**********改动之处主要是:表格要展示的数据内容及字段顺序 取决于 列标题字段。即:导出的数据顺序以headersId为准;**************
文章结构:(1)面向JavaBean的导出工具;(2)面向List-Map结构的导出工具。
大家阅读了前篇就知道Excel报表导出之JSP方式就是这么简单了,查出数据直接对到jsp处理,样式也可以在制作excel模板时自定义,相当简单。但是我们要想当要导出大量数据的时候呢??难道我们也这样实时导出??这样一个正常系统而且在大量人使用的时候,对于系统的负载会非常非常高的,所以前篇我也给出了另一种方式:Excel报表导出之上传文件流方式。在这样的方式下,如何做出一个公用的适应各种情况的设计,这就是往后几篇文章要探讨的。
一、面向JavaBean的导出工具:
(一)设计的关键:
(1)兼容普通JavaBean;
(2)接口方法易用性;
(3)导出数据准确性;
(4)扩展性。
(二)基于POI抽象的关键步骤:
(1)设置表格标题
(2)设置标题栏
(3)设置内容栏(为了精确比对,需要给出标题栏对应的字段—DTO类(普通javabean)的属性)
(4)导出写入到流对象
(三)核心代码与demo:
准备实体:(一个普通的JavaBean)
1 package com.etom.ebihm.module.rm.reportexport; 2 3 /** 4 * Created by zhaof on 2018/9/26. 5 */ 6 public class Student { 7 private int id; 8 private String name; 9 private String sex; 10 private String job; 11 12 public Student(int id, String name, String sex, String job) { 13 this.id = id; 14 this.name = name; 15 this.sex = sex; 16 this.job = job; 17 } 18 19 public String getJob() { 20 return job; 21 } 22 23 public void setJob(String job) { 24 this.job = job; 25 } 26 27 public int getId() { 28 return id; 29 } 30 31 public void setId(int id) { 32 this.id = id; 33 } 34 35 public String getName() { 36 return name; 37 } 38 39 public void setName(String name) { 40 this.name = name; 41 } 42 43 public String getSex() { 44 return sex; 45 } 46 47 public void setSex(String sex) { 48 this.sex = sex; 49 } 50 }
工具代码:
1 package com.etom.ebihm.module.rm.reportexport; 2 3 import org.apache.poi.hssf.usermodel.*; 4 import org.apache.poi.ss.util.CellRangeAddress; 5 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.lang.reflect.Field; 10 import java.lang.reflect.InvocationTargetException; 11 import java.lang.reflect.Method; 12 import java.util.*; 13 14 /** 15 * Created by zhaof on 2018/9/23. 16 */ 17 public class ExportBeanExcel<T> { 18 19 /** 20 * 这是一个通用的方法,利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出 21 * <p> 22 * sheetName 表格sheet名称 23 * headersName 表格属性列名数组 24 * headersId 表格属性列名对应的字段---你需要导出的字段名(为了更灵活控制你想要导出的字段) 25 * dtoList 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象 26 * out 与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中 27 * <p> 28 * dtoRow dtoList集合中每个对象记录所在行序号(从1开始,第0行是列标题栏) 29 * zdCell 列标题字段所在单元格的列序号 30 */ 31 public void exportExcel(String sheetName, List<String> headersName, List<String> headersId, List<T> dtoList) { 32 /* 33 (一)表头--标题栏 34 */ 35 Map<Integer, String> headersNameMap = new HashMap<>(); 36 int key = 0; 37 for (int i = 0; i < headersName.size(); i++) { 38 if (!headersName.get(i).equals(null)) { 39 headersNameMap.put(key, headersName.get(i)); 40 key++; 41 } 42 } 43 /* 44 (二)字段---标题对应的字段 45 */ 46 Map<Integer, String> headersFieldMap = new HashMap<>(); 47 int value = 0; 48 for (int i = 0; i < headersId.size(); i++) { 49 if (!headersId.get(i).equals(null)) { 50 headersFieldMap.put(value, headersId.get(i)); 51 value++; 52 } 53 } 54 /* 55 (三)声明一个工作薄:包括构建工作簿、表格、样式 56 */ 57 HSSFWorkbook wb = new HSSFWorkbook(); 58 HSSFSheet sheet = wb.createSheet(sheetName); 59 sheet.setDefaultColumnWidth(15); 60 // 生成一个样式 61 HSSFCellStyle style = wb.createCellStyle(); 62 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 63 /* 64 合并第一行单元格标题 65 */ 66 HSSFRow row = sheet.createRow(0); 67 HSSFCell cell; 68 cell = row.createCell(0); 69 cell.setCellValue("学生基本信息表"); 70 cell.setCellStyle(style); 71 //CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 72 wb.getSheet(sheetName).addMergedRegion(new CellRangeAddress(0,0,0,headersNameMap.size()-1)); 73 //创建列标题栏所在行 74 row = sheet.createRow(1); 75 76 Collection c = headersNameMap.values();//拿到表格所有列标题的value的集合 77 Iterator<String> it = c.iterator();//表格标题的迭代器 78 /* 79 (四)导出数据:包括导出标题栏以及内容栏 80 */ 81 //根据选择的字段生成表头 82 int size = 0; 83 while (it.hasNext()) { 84 cell = row.createCell(size); 85 cell.setCellValue(it.next().toString()); 86 cell.setCellStyle(style); 87 size++; 88 } 89 //表格列标题一行对应的字段的集合 90 Collection headersFieldCo = headersFieldMap.values(); 91 Iterator<T> labIt = dtoList.iterator();//总记录的迭代器 92 int dtoRow = 2;//内容栏 导出数据dtoList的行序号 93 while (labIt.hasNext()) {//记录的迭代器,遍历总记录 94 row = sheet.createRow(dtoRow); 95 dtoRow++; 96 T l = (T) labIt.next(); 97 // 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 98 Field[] fields = l.getClass().getDeclaredFields();//获得JavaBean全部属性 99 for (short i = 0; i < fields.length; i++) {//遍历属性,比对 100 Field field = fields[i]; 101 String fieldName = field.getName();//属性名 102 Iterator<String> zdIt = headersFieldCo.iterator();//一行列标题字段的集合的迭代器 103 int zdCell = 0; 104 while (zdIt.hasNext()) {//遍历要导出的字段集合 105 if (zdIt.next().equals(fieldName)) {//比对JavaBean的属性名,一致就写入,不一致就丢弃 106 String getMethodName = "get" 107 + fieldName.substring(0, 1).toUpperCase() 108 + fieldName.substring(1);//拿到属性的get方法 109 Class tCls = l.getClass();//拿到JavaBean对象 110 try { 111 Method getMethod = tCls.getMethod(getMethodName, 112 new Class[]{});//通过JavaBean对象拿到该属性的get方法,从而进行操控 113 Object val = getMethod.invoke(l, new Object[]{});//操控该对象属性的get方法,从而拿到属性值 114 String textVal = null; 115 if (val != null) { 116 textVal = String.valueOf(val);//转化成String 117 } else { 118 //字段内容值为null时,进行处理 119 textVal = ""; 120 } 121 row.createCell(zdCell).setCellValue(textVal);//写进excel对象 122 } catch (SecurityException e) { 123 e.printStackTrace(); 124 } catch (IllegalArgumentException e) { 125 e.printStackTrace(); 126 } catch (NoSuchMethodException e) { 127 e.printStackTrace(); 128 } catch (IllegalAccessException e) { 129 e.printStackTrace(); 130 } catch (InvocationTargetException e) { 131 e.printStackTrace(); 132 } 133 }//if 134 zdCell++; 135 }//while 136 }//for 137 } 138 139 //行列分组 140 //wb.getSheet(sheetName).groupColumn(4, 7); 141 try { 142 FileOutputStream exportXls = new FileOutputStream("E://工单信息表.xls"); 143 wb.write(exportXls); 144 exportXls.close(); 145 System.out.println("导出成功!"); 146 } catch (FileNotFoundException e) { 147 System.out.println("导出失败!"); 148 e.printStackTrace(); 149 } catch (IOException e) { 150 System.out.println("导出失败!"); 151 e.printStackTrace(); 152 } 153 } 154 155 156 /*使用例子*/ 157 public static void main(String[] args) { 158 List<String> listName = new ArrayList<>(); 159 listName.add("id"); 160 listName.add("性别"); 161 listName.add("名字"); 162 List<String> listId = new ArrayList<>(); 163 listId.add("id"); 164 listId.add("sex"); 165 listId.add("name"); 166 List<Student> dotList = new ArrayList<>(); 167 dotList.add(new Student(111, "张三asdf", "男", "老师")); 168 dotList.add(new Student(121, null, "男2", "学生")); 169 dotList.add(new Student(131, "王五", "女", "医生")); 170 171 172 ExportBeanExcel<Student> exportBeanExcelUtil = new ExportBeanExcel(); 173 exportBeanExcelUtil.exportExcel("测试POI导出EXCEL文档", listName, listId, dotList); 174 175 } 176 }
导出excel效果图:
(四)工具注意点:
(1)应用泛型,代表任意一个符合javabean风格的类
(2)注意这里为了简单起见,boolean型的属性xxx的get器方式为getXxx(),而不是isXxx()
(3) T这里代表一个不确定是实体类,即参数实体
二、面向List-Map结构的导出工具:
(一)设计的关键:
(1)兼容普通List-Map结构;
(2)接口方法易用性;
(3)导出数据准确性;
(4)扩展性。
(二)基于POI抽象的关键步骤:
(1)设置表格标题
(2)设置标题栏
(3)设置内容栏(为了精确比对,需要给出标题栏对应的字段—dtoList(List-Map结构中的key))
(4)导出写入到流对象
(三)核心代码与demo:
1 package com.etom.ebihm.module.rm.reportexport; 2 3 import org.apache.poi.hssf.usermodel.*; 4 import org.apache.poi.ss.util.CellRangeAddress; 5 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.util.*; 10 11 /** 12 * Created by zhaof on 2018/9/27. 13 */ 14 public class ExportMapExcel { 15 public void exportExcel(String sheetName, List<String> headersName, List<String> headersId, 16 List<Map<String, Object>> dtoList) { 17 /* 18 (一)表头--标题栏 19 */ 20 Map<Integer, String> headersNameMap = new HashMap<>(); 21 int key = 0; 22 for (int i = 0; i < headersName.size(); i++) { 23 if (!headersName.get(i).equals(null)) { 24 headersNameMap.put(key, headersName.get(i)); 25 key++; 26 } 27 } 28 /* 29 (二)字段---标题对应的字段 30 */ 31 Map<Integer, String> titleFieldMap = new HashMap<>(); 32 int value = 0; 33 for (int i = 0; i < headersId.size(); i++) { 34 if (!headersId.get(i).equals(null)) { 35 titleFieldMap.put(value, headersId.get(i)); 36 value++; 37 } 38 } 39 /* 40 (三)声明一个工作薄:包括构建工作簿、表格、样式 41 */ 42 HSSFWorkbook wb = new HSSFWorkbook(); 43 HSSFSheet sheet = wb.createSheet(sheetName); 44 sheet.setDefaultColumnWidth(15); 45 // 生成一个样式 46 HSSFCellStyle style = wb.createCellStyle(); 47 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 48 /* 49 合并第一行单元格标题 50 */ 51 HSSFRow row = sheet.createRow(0); 52 HSSFCell cell; 53 cell = row.createCell(0); 54 cell.setCellValue("学生基本信息表Map"); 55 cell.setCellStyle(style); 56 //CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 57 wb.getSheet(sheetName).addMergedRegion(new CellRangeAddress(0,0,0,headersNameMap.size()-1)); 58 //创建列标题栏所在行 59 row = sheet.createRow(1); 60 Collection c = headersNameMap.values();//拿到表格所有标题的value的集合 61 Iterator<String> headersNameIt = c.iterator();//表格标题的迭代器 62 /* 63 (四)导出数据:包括导出标题栏以及内容栏 64 */ 65 //根据选择的字段生成表头--标题 66 int size = 0; 67 while (headersNameIt.hasNext()) { 68 cell = row.createCell(size); 69 cell.setCellValue(headersNameIt.next().toString()); 70 cell.setCellStyle(style); 71 size++; 72 } 73 //表格一行的字段的集合,以便拿到迭代器 74 Collection headersFieldCo = titleFieldMap.values(); 75 Iterator<Map<String, Object>> dtoMapIt = dtoList.iterator();//总记录的迭代器 76 int zdRow = 2;//内容栏 真正数据记录的行序号 77 while (dtoMapIt.hasNext()) {//记录的迭代器,遍历总记录 78 Map<String, Object> mapTemp = dtoMapIt.next();//拿到一条记录 79 row = sheet.createRow(zdRow); 80 zdRow++; 81 int zdCell = 0; 82 Iterator<String> headersFieldIt = headersFieldCo.iterator();//一条记录的字段的集合的迭代器 83 while (headersFieldIt.hasNext()) { 84 String tempField = headersFieldIt.next();//字段的暂存 85 if (mapTemp.get(tempField) != null) { 86 row.createCell(zdCell).setCellValue(String.valueOf(mapTemp.get(tempField)));//写进excel对象 87 // zdCell++; 88 }else{ 89 //字段内容值为null时,进行处理 90 row.createCell(zdCell).setCellValue("*");//写进excel对象 91 } 92 zdCell++; 93 } 94 } 95 //行列分组 96 //wb.getSheet(sheetName).groupColumn(4, 7); 97 try { 98 FileOutputStream exportXls = new FileOutputStream("E://工单信息表Map.xls"); 99 wb.write(exportXls); 100 exportXls.close(); 101 System.out.println("导出成功!"); 102 } catch (FileNotFoundException e) { 103 System.out.println("导出失败!"); 104 e.printStackTrace(); 105 } catch (IOException e) { 106 System.out.println("导出失败!"); 107 e.printStackTrace(); 108 } 109 } 110 111 public static void main(String[] args) { 112 113 List<String> listName = new ArrayList<>(); 114 listName.add("id"); 115 listName.add("性别"); 116 listName.add("名字"); 117 listName.add("职业"); 118 List<String> listId = new ArrayList<>(); 119 listId.add("id"); 120 listId.add("sex"); 121 listId.add("name"); 122 listId.add("job"); 123 124 List<Map<String, Object>> listB = new ArrayList<>(); 125 for (int t = 0; t < 6; t++) { 126 Map<String, Object> map = new HashMap<>(); 127 map.put("id", t); 128 map.put("name", "abc" + t); 129 map.put("sex", "男" + t); 130 map.put("job", "学生" + t); 131 listB.add(map); 132 } 133 Map<String, Object> map = new HashMap<>(); 134 map.put("id", 77); 135 map.put("name", "蛋蛋超人"); 136 map.put("sex", null); 137 map.put("job", null); 138 listB.add(map); 139 140 Map<String, Object> map2 = new HashMap<>(); 141 map2.put("id", 88); 142 map2.put("name", "笨笨"); 143 map2.put("sex", null); 144 map2.put("job", null); 145 listB.add(map2); 146 147 System.out.println("listB : " + listB.toString()); 148 ExportMapExcel exportExcelUtil = new ExportMapExcel(); 149 exportExcelUtil.exportExcel("测试POI导出EXCEL文档", listName, listId, listB); 150 151 } 152 }
导出excel效果图: