看到标题已然知道,即将介绍的这款用于导出数据的工具又是Apache开源项目之一,不得不说,Apache对IT领域的贡献,程序猿皆知。
Apache POI(以下简称POI)是一款用Java语言编写的开源的跨平台Java API,全称是Poor Obfuscation Implementation(可怜的模糊实现)。该API提供方法完成对Microsoft Office(Excel、WORD、PowerPoint、Visio等)格式档案读和写的功能。
类名(包名) | 用途 |
---|---|
HSSF | 提供读写Microsoft Excel XLS格式档案的功能(Excel97-2003)(也即我们用的.xls格式的Excel文件) |
XSSF | 提供读写Microsoft Excel OOXML XLSX格式档案的功能(Excel2007以后)(也即我们用的.xlsx格式的Excel文件) |
XWPF | 提供读写Microsoft Word DOC2003格式档案的功能 |
这里我们使用到了HSSF
来处理Excel数据的导出,我们先介绍HSSF
。
(1) 简介
HSSF
全称是Horrible SpreadSheet Format
,可以通过该方法用纯Java代码处理Excel文件。上面说到HSSF
是POI
提供的处理Excel文件的一种方法,更准确的说其实一类方法的总称,这些类位于org.apache.poi.hssf
包中。打开该包可以发现,又存在多个子包,我们这里使用到的是usermodel
包中的类,至于其他包中的内容,后面在研究其用途。(2) 使用HSSF创建并导出一个简单的Excel文件
要使用POI提供的这个工具,首先我们需要导入jar
包,当用Maven创建的项目时可以直接在其中加入需要的依赖即可,具体如下。
导入jar
包的方式
在所在项目的lib目录中导入下图所示的jar
包即可。
Maven引入依赖的方式
在所在Maven项目的pom.xml
文件中,引入下图所示的依赖即可。
在导入依赖的插件之后,我们就可以开始使用其提供的类和方法了。这里我们首先创建并导出一个简单的Excel文件,具体代码如下,代码中有详细注释。
/** * 导入的包结构 */ import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; // 创建Excel工作簿 HSSFWorkbook wk = new HSSFWorkbook(); // 创建一张工作表 HSSFSheet sheet = wk.createSheet("我的工作表"); // 设置第一列的列宽 sheet.setColumnWidth(0, 256*15+184); // 这样设置列宽,第二个参数即是Excel中实际显示的列宽 // 创建第一行 HSSFRow row = sheet.createRow(0); // 创建第一行中的第一个单元格 HSSFCell column = row.createCell(0); // 向单元格中写值 column.setCellValue("测试"); // 将工作簿保存到本地目录 try { wk.write(new FileOutputStream(new File("d:\\poitest.xls"))); } catch (Exception e) { e.printStackTrace(); }finally { try { // 关闭资源 wk.close(); } catch (IOException e) { e.printStackTrace(); } }
上面的代码就是创建并向本地磁盘输出了一个最基本的Excel表,结果如下图所示。
我们再来分析一下上面的代码到底完成了哪些工作?
可以发现,hssf
包中提供的类对应于Excel的每一个对象,每使用包中的一个类,就创建了一个Excel部件对象。我们可以抽象出一个Excel表该有的内容,如下面的树形所示。想必看到类似这样的树形图大家也不陌生,DOM对象就是这种树形结构。
在两张图中,第一章是整个Excel文件(不管是什么格式的Excel文件)的部件抽象,从最基本的一个工作簿开始到其中的多个工作表,最后到行以及行中的元素(这里抽象层次中行与列的关系有点类似我们学过的二维数组的存储方案:行优先,与此对应的还有列优先算法)。
第二张图中展示的是HSSF
处理xls
格式的Excel文件使用的类结构图,与第一张图的类相比,在基本部件的前面加上了具体的包信息HSSF
。
(3)在Web系统中使用HSSF
导出表格数据至Excel文件
有了上面简单的使用实例,我们就可以在真正的Web系统中使用该文件导出表格数据至Excel文件中了。在笔者目前接触到的系统中,导入导出数据操作是很频繁且通用的需求。因为我们知道,网站中的数据大多数是以网格的形式展示和组织的,如果你所开发的系统要操作大量数据,单凭手工导入或导出是不行的,这样我们就需要借助工具来实现数据的导入导出。与展示形式类似,在导出数据的媒介中,我们也选择数据表格,Excel就是不错的输出地。输出到Excel的数据,因为其格式的特殊性,在现在做数据处理时也是比较方面的,无论是纯Excel函数处理还是机器学习算法。
在笔者的认识里,要将系统中的数据写入Excel文件,首先要做的就是写入表头的信息,也即表格首行的栏目项,但一般我们可能将表头信息在前端页面中配置(现在想明白了我们所接触的项目中为什么将表头信息也存储在数据库中,即这样可以避免前端页面中大量重复冗余的代码;同时配置时也比较方便,改变数据库中的内容即可;如有加载表头信息的需求,可以直接读取数据库即可),这样需要在后端代码中定义数组或列表来保存全部的字段值。
以我们的例子为例,我们的需求是要导出供应商的信息,前端中的展示如下图所示。
可以看出,我们需要导出的字段并不多。在表格中我们也需要表头信息,故我们在服务端代码中加入需要的表头信息。代码如下:
// 定义好每一列的标题 String[] headerNames = {"名称", "地址", "联系人", "电话", "Email"};
定义好了表头,我们需要在写入数据时,严格按照表头内容对应的字段写入。这李我们需要首先将表头信息写入表格中,代码如下:
// 创建工作簿 HSSFWorkbook wk = new HSSFWorkbook(); // 创建工作表sheet HSSFSheet sheet = null; // 写入表头信息 HSSFRow row = sheet.createRow(0); // 定义好每一列的标题 String[] headerNames = {"名称", "地址", "联系人", "电话", "Email"}; // 指定每一列的宽度 int[] columnsWidths = {256*15+184, 256*40+184, 256*15+184, 256*15+184, 256*30+184}; // 创建每一行的元素(列) HSSFCell cell = null; // 写入表头内容 for (int i = 0; i < headerNames.length; i++) { cell = row.createCell(i); cell.setCellValue(headerNames[i]); sheet.setColumnWidth(i, columnsWidths[i]); }
我们可以将上面的内容抽象为一个方法,这样每次只需要传入具体的表头信息,实现代码的重复使用。
在写好上面的表头信息后,我们就可以遍历数据并将其写入到数据行中了。注意,为了内容不出错,一定严格按照表头信息字段写入数据。我们例子中的代码如下:
// 写入数据 int i = 1; for (Supplier supplier : supplierList) { row = sheet.createRow(i); // 按照表头顺序写入数据 row.createCell(0).setCellValue(supplier.getName()); // 名称 row.createCell(1).setCellValue(supplier.getAddress()); // 地址 row.createCell(2).setCellValue(supplier.getContact()); // 联系人 row.createCell(3).setCellValue(supplier.getTele()); // 电话 row.createCell(4).setCellValue(supplier.getEmail()); // Email i++; }
(4)在Web系统中使用Excel模板写入数据
在笔者接触到的系统中,将表头信息直接写在Excel模板中,这样可以不用在后端代码中再写入。这样一来,我们只需要将模板表存入指定路径中,之后通过文件输入流的方式创建HSSF
的HSSFWorkbook
对象,代码如下:
FileInputStream fis = new FileInputStream(new File(SupplierAction.class.getClassLoader().getResource("template.xls").getPath())); HSSFWorkbook wk = new HSSFWorkbook(fis);
通过这种方式写入时,若想改变模板表的Sheet
名称,可以直接通过索引修改,代码如下:
wk.setSheetName(0, "供应商列表");
之后严格按照模板表的表头信息写入数据即可。