Apache POI是Apache软件基金会的开放源码函式库。
提供API给Java应用程序对Microsoft Office格式档案读和写的功能。
老外起名字总是很谦虚,POI为(Poor Obfuscation Implementation)的首字母缩写,意为“可怜的模糊实现”。
如果你查看过 Apache 开源库中的任意项目的源码,你会发现恰到好处的设计模式、模块之间的高内聚低耦合、接口抽象相当到位、实现方式也非常优雅,这样的一些特定。
o(︶︿︶)o 唉 需要多严谨的思维、多大的代码实现量,多少项目的设计积累,才能达到那样的高度?
POI 中主要提供的读写 Microsoft Office 功能点如下:
本文借一次使用POI 实现读写 Excel 的过程,记述其中具体POI运用的方式。
由搜索引擎点进来的同学,上面这一句话就是本文的主旨句。若能解决你问题,请往下细看。
项目中使用的是最新的 poi-3.14-20160307.jar,百度云地址:http://pan.baidu.com/s/1bnWFWg3 密码: kame
因项目比较大,下面为单独新建工程后的例子。
上图左侧用例图为 POI 写 Excel
a.getExcelData: 获取需要输出到Excel数据,这里的数据获取可以是从持久层,页面展示层......
(例子中的数据为Mysql自有数据库中表help_categroy 表记录),其中的 JavaBean建立 与 数据库获取的过程这里就不说了。
获取数据的数据类型是这样的 List<HelpCategory>
b.POI Write Workbook:这里才是关键的地方,使用POI 将数据实例化为 HSSFWorkbook。核心代码如下:
public HSSFWorkbook expExcel(List<HelpCategory> helpCategories) { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); createSheetStyle(workbook, sheet); HSSFRow row = sheet.createRow(0); HSSFCell cell; HelpCategory category = new HelpCategory(); Field[] fields = category.getClass().getDeclaredFields(); for (int j = 0; j < fields.length; j++) { cell = row.createCell(j); cell.setCellValue(fields[j].getName()); cell.setCellStyle(this.textAlignCenter); } for (int i = 0; i < helpCategories.size(); i++) { category = helpCategories.get(i); row = sheet.createRow(i + 1); for (int k = 0; k < fields.length; k++) { Field field = fields[k]; Object o = invokeGet(category, field.getName()); cell = row.createCell(k); cell.setCellValue(o != null ? o.toString() : ""); cell.setCellStyle((k == 0 || k == 1) ? this.textAlignCenter : this.textAlignLeft); } } return workbook; }
获取JavaBean字段值作为表头,并设置表头的样式:
HSSFRow row = sheet.createRow(0); HSSFCell cell; HelpCategory category = new HelpCategory(); Field[] fields = category.getClass().getDeclaredFields(); for (int j = 0; j < fields.length; j++) { cell = row.createCell(j); cell.setCellValue(fields[j].getName()); cell.setCellStyle(this.textAlignCenter); }
获取JavaBean HelpCategory 中字段的值填充到对应的表格中,并设置样式:
for (int i = 0; i < helpCategories.size(); i++) { category = helpCategories.get(i); row = sheet.createRow(i + 1); for (int k = 0; k < fields.length; k++) { Field field = fields[k]; Object o = invokeGet(category, field.getName()); cell = row.createCell(k); cell.setCellValue(o != null ? o.toString() : ""); cell.setCellStyle((k == 0 || k == 1) ? this.textAlignCenter : this.textAlignLeft); } }
这里面用的了一点反射的东西,来获取javaBean属性的值。
如果你觉得反射的效率有点差劲,可以自己构造一个Map数据集合,同样能达到这样的效果。
private Object invokeGet(Object o, String fieldName) { Method method = getGetMethod(o.getClass(), fieldName); try { return method.invoke(o, new Object[0]); } catch (Exception e) { e.printStackTrace(); } return null; } private Method getGetMethod(Class objectClass, String fieldName) { StringBuilder sb = new StringBuilder(); sb.append("get"); sb.append(fieldName.substring(0, 1).toUpperCase()); sb.append(fieldName.substring(1)); try { return objectClass.getMethod(sb.toString()); } catch (Exception e) { e.printStackTrace(); } return null; }
同样你可以设置表格样式、边框样式:
private void createSheetStyle(HSSFWorkbook _workbook, HSSFSheet _sheet) { // 设置表字体 HSSFFont font10 = _workbook.createFont(); font10.setFontHeightInPoints((short) 12); font10.setFontName("黑体"); // 设置表样 this.textAlignCenter = getCellStyle(_workbook, font10, HSSFCellStyle.ALIGN_CENTER); this.textAlignLeft = getCellStyle(_workbook, font10, HSSFCellStyle.ALIGN_LEFT); // 设置列宽 _sheet.setColumnWidth(0, 4000); _sheet.setColumnWidth(1, 4000); _sheet.setColumnWidth(2, 10000); _sheet.setColumnWidth(3, 10000); }
上面的样式设置,如果还满足不了你的功能需求,更多的设置请参考博客:http://langhua9527.iteye.com/blog/388005
上图左侧用例图为 POI 写 Excel
a.getExcleFile:获取要读取的Excel文件...这里就不说了。(注意:判断获取的文件后缀名)
String fileName = excel.getName(); int iIndex = fileName.lastIndexOf("."); String ext = (iIndex < 0) ? "" : fileName.substring(iIndex + 1).toLowerCase(); if (!"xls,xlsx".contains(ext) || "".contains(ext)) { System.out.println("文件类型不是EXCEL!"); }
b.POI Read Workbook:这里就是重点啦,使用POI读取Excel文件,解析并进行保存到你自己数据类型当中。
ArrayList<HelpCategory> categories = new ArrayList<>(); try { POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new FileInputStream(excel)); HSSFWorkbook workbook = new HSSFWorkbook(poifsFileSystem); HSSFSheet sheet = workbook.getSheetAt(0); HelpCategory category = new HelpCategory(); Field[] declaredField = category.getClass().getDeclaredFields(); for (int k = 1; k <= sheet.getLastRowNum(); k++) { HSSFRow row = sheet.getRow(k); category = new HelpCategory(); for (int j = 0; j < declaredField.length; j++) { HSSFCell cell = row.getCell(j); invokeSet(category, declaredField[j].getName(), cell.getStringCellValue()); } categories.add(category); } } catch (Exception e) { e.printStackTrace(); }
上面也同样用到了一些反射的东西,这里获取JavaBean 的set方法,来设置具体的属性。
public void invokeSet(Object o, String fieldName, Object value) { Method method = getSetMethod(o.getClass(), fieldName); try { method.invoke(o, new Object[]{value}); } catch (Exception e) { e.printStackTrace(); } } public Method getSetMethod(Class objectClass, String fieldName) { try { Class[] parameterTypes = new Class[1]; Field field = objectClass.getDeclaredField(fieldName); parameterTypes[0] = field.getType(); StringBuffer sb = new StringBuffer(); sb.append("set"); sb.append(fieldName.substring(0, 1).toUpperCase()); sb.append(fieldName.substring(1)); Method method = objectClass.getMethod(sb.toString(), parameterTypes); return method; } catch (Exception e) { e.printStackTrace(); } return null; }
上述例子仅当作抛砖引玉之用,项目中的具体需求随时都有其他的变化。
如获取数据的途径可能是多表联合查询或者是展现层、结果需要进行其他运算、写Excel表格样式的变化........
但熟悉具体核心读写实现,已不变应万变,可为上将。