阿里开源的这个库,让 Excel 导出不再复杂(简简单单的写)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你好,我是看山。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导出是中后台常见的功能,Excel文件是常见的导出格式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Java栈中,常用的是","attrs":{}},{"type":"link","attrs":{"href":"https://sourceforge.net/projects/jexcelapi/","title":"","type":null},"content":[{"type":"text","text":"JXL(目前改名为JExcel)","attrs":{}}]},{"type":"text","text":"和","attrs":{}},{"type":"link","attrs":{"href":"http://poi.apache.org/","title":"","type":null},"content":[{"type":"text","text":"Apache POI","attrs":{}}]},{"type":"text","text":"。其中jxl最后的更新时间是2012,除了老系统中能看到影子,几乎见不到踪迹了。目前基本上是POI一统天下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"今天要说的EasyExcel阿里巴巴开源的Excel导出类库,是对POI的封装,实现了很多高级功能,并且留出扩展口,支持扩展定制化功能。打个比喻,POI相当于乐高积木,一个个的小积木可以自由组装,只能动手能力强,就可以随心所欲的组装。EasyExcel更像是把这些小积木提前组装好,想要搭建房子,就直接找组装好的屋顶、围墙就行。如果仅仅如此,那EasyExcel仅仅就是简单的工具包,其更加吸引人的地方是对于内存的控制,它通过压缩文件、分批读取、抛弃不重要数据、文件缓存等多种方式,降低内存消耗。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"内容比较多,文内只会列出关键代码,想要完整源码,可以关注公号「看山的小屋」回复“easyexcel”获取。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"最简单的写表格","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开始之前,先定义一下基础类,这个类将贯穿全文,所有的功能都是在这个类的简单变形。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\npublic class Item {\n @ExcelProperty(\"字符串标题\")\n private String string;\n @ExcelProperty(\"日期标题\")\n private Date date;\n @ExcelProperty(\"数字标题\")\n private Double doubleData;\n @ExcelIgnore\n private String ignore;\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"根据头对象和列表向一个工作表中写一个表格","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是最简单的一种实现,只需要定义一个对象类,然后读取数据列表即可。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 借助{@link com.alibaba.excel.write.builder.ExcelWriterSheetBuilder}自动创建{@link com.alibaba.excel.ExcelWriter}写入数据。\n *

\n * 提供列表和函数作为数据源\n */\npublic static void writeAutoWriter() {\n final String fileName = defaultFileName(\"writeAutoWriter\");\n EasyExcelFactory.write(fileName)\n .head(Item.class)\n .sheet(\"模板\")\n .doWrite(WriteSample::sampleItems);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"EasyExcel提供了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EasyExcelFactory","attrs":{}}],"attrs":{}},{"type":"text","text":"类,API方法也是fluent方式,可以如丝般顺滑的实现生成Excel文件。如果感觉","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EasyExcelFactory","attrs":{}}],"attrs":{}},{"type":"text","text":"太长,还可以直接写作","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EasyExcel","attrs":{}}],"attrs":{}},{"type":"text","text":",这是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EasyExcelFactory","attrs":{}}],"attrs":{}},{"type":"text","text":"的子类,类似于别名。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不过,这种别名定义方式,在有些规范中属于","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"smell code","attrs":{}}],"attrs":{}},{"type":"text","text":",所以,根据自己或者公司规范选择吧。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.EasyExcelFactory#write(java.lang.String)","attrs":{}}],"attrs":{}},{"type":"text","text":"方法的参数传的是导出文件的文件名,如果并不需要生成文件,只需要创建文件流,也可以传入一个输出流","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"OutputStream","attrs":{}}],"attrs":{}},{"type":"text","text":",这样就可以更加灵活的实现生成逻辑了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.metadata.AbstractParameterBuilder#head()","attrs":{}}],"attrs":{}},{"type":"text","text":"方法是定义表头,只要传入一个类,就会读取这个类的所有字段作为表头。如果字段上","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.annotation.ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"注解,定义了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"value","attrs":{}}],"attrs":{}},{"type":"text","text":",就会取","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"value","attrs":{}}],"attrs":{}},{"type":"text","text":"的值作为表头。此处还有很多操作,比如,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"value","attrs":{}}],"attrs":{}},{"type":"text","text":"是数组,可以定义多个,如果是相邻字段定义了相同的表头,会合并单元格,表体内容会选择第一个单元格的内容。这个注解还可以定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"index","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"order","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"converter","attrs":{}}],"attrs":{}},{"type":"text","text":"等,后面会一一给出例子。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.ExcelWriterBuilder#sheet()","attrs":{}}],"attrs":{}},{"type":"text","text":"方法定义工作表,有多个重载方法,可以定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sheetNo","attrs":{}}],"attrs":{}},{"type":"text","text":"指明是第几个工作表,可以传入","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sheetName","attrs":{}}],"attrs":{}},{"type":"text","text":"指明工作表名称。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.ExcelWriterSheetBuilder#doWrite()","attrs":{}}],"attrs":{}},{"type":"text","text":"方法就是写Excel文件了,传入全部的列表数据,或者使用Java8+的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Supplier","attrs":{}}],"attrs":{}},{"type":"text","text":"函数。还可以实现分页写入,后面会给出例子。这个方法会自动关闭文件流,真是很贴心。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a0/a0de5cb490bf6616084bed5a19ec208c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"根据头对象和列表向多个工作表中写数据","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面是向一个工作表写数据,接下来我们向多个工作表写数据。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个例子会涉及更多的内部对象,比如:ExcelWriter、WriteSheet。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 手动创建{@link com.alibaba.excel.ExcelWriter},指定sheet写入数据。\n *

\n * 提供列表和函数作为数据源\n */\npublic static void writeManualWither() {\n String fileName = defaultFileName(\"writeManualWriter\");\n ExcelWriter excelWriter = null;\n try {\n excelWriter = EasyExcelFactory.write(fileName)\n .head(Item.class)\n .build();\n final WriteSheet writeSheet1 = EasyExcelFactory.writerSheet(\"模板1\").build();\n excelWriter.write(WriteSample::sampleItems, writeSheet1);\n\n final WriteSheet writeSheet2 = EasyExcelFactory.writerSheet(\"模板2\").build();\n excelWriter.write(sampleItems(), writeSheet2);\n } finally {\n // 千万别忘记finish 会帮忙关闭流\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因为是想多个工作表中写数据,我们就不能直接使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"doWrite","attrs":{}}],"attrs":{}},{"type":"text","text":"方法了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.ExcelWriter","attrs":{}}],"attrs":{}},{"type":"text","text":"类是Excel写对象,用来创建Excel工作簿的。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.metadata.WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"类是Sheet写对象,用来创建Sheet工作表的。通过","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.ExcelWriter#write()","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,指定写入数据和写入的目标工作表,就可以实现向多个工作表中写数据的功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此处需要注意,我们在创建","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriter","attrs":{}}],"attrs":{}},{"type":"text","text":"对象时,调用了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"head()","attrs":{}}],"attrs":{}},{"type":"text","text":"方法定义了表头,这是整个Excel的定义,sheet会继承这个定义。这样,整个Excel文件中的所有工作表,表头都是相同的。不要停,后面会给出不同工作表定义不同表头的示例。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8f/8f2c86fea7f678a4456af7727f7feeb6.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"按照定义指定导出列","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在后台系统中,会有行列权限的控制。行权限,通过数据行实现,只导出有权限的行数据即可。列权限,可以通过只导出有权限的列,排除没有权限的列(通常是分等级的敏感数据)。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有时候需要定制化导出,导出所有列表格比较大,用户根据需要指定需要导出的列。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"排除指定列","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeExcludeColumn() {\n String fileName = defaultFileName(\"writeExcludeColumn\");\n Set excludeColumnFiledNames = new HashSet<>();\n excludeColumnFiledNames.add(\"date\");\n\n EasyExcelFactory.write(fileName)\n .head(Item.class)\n .excludeColumnFiledNames(excludeColumnFiledNames)\n .sheet(\"模板\")\n .doWrite(WriteSample::sampleItems);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个需求,需要借助","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.AbstractExcelWriterParameterBuilder#excludeColumnFiledNames","attrs":{}}],"attrs":{}},{"type":"text","text":"方法。这个方法是在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterBuilder","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterSheetBuilder","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterTableBuilder","attrs":{}}],"attrs":{}},{"type":"text","text":"的父类中定义,也就是说,可以是整个Excel工作簿都排除指定字段,也可以是某个sheet工作表排除指定字段,还可以是table表格排除指定字段。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"excludeColumnFiledNames","attrs":{}}],"attrs":{}},{"type":"text","text":"通过字段名排除字段,还可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"excludeColumnIndexes","attrs":{}}],"attrs":{}},{"type":"text","text":"指定字段下标排除列,如果需要控制下标,需要在字段上定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"指明index属性,这样也能够更好的固定字段下标。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4e/4e0cc378e198949d197769add6820e99.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"只导出指定列","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeIncludeColumn() {\n String fileName = defaultFileName(\"writeIncludeColumn\");\n Set includeColumnFiledNames = new HashSet<>();\n includeColumnFiledNames.add(\"date\");\n EasyExcelFactory.write(fileName)\n .head(Item.class)\n .includeColumnFiledNames(includeColumnFiledNames)\n .sheet(\"模板\")\n .doWrite(WriteSample::sampleItems);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个需求,需要借助","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.AbstractExcelWriterParameterBuilder#includeColumnFiledNames","attrs":{}}],"attrs":{}},{"type":"text","text":"方法。与","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"excludeColumnFiledNames","attrs":{}}],"attrs":{}},{"type":"text","text":"是相似,都是可以分级定义,用起来也是一样的,只不过功能相反而已。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同样的,也可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"includeColumnIndexes","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,通过指定字段下标指定列。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4f/4f66653e0bea78329f4d5993b5d1c232.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"表头","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"表头的定义是比较关键的,会直接影响Excel文件的质量。所以,EasyExcel提供了比较丰富的表头定义方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"原始表头","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里定义了一个新的基础类:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EmptyItem","attrs":{}}],"attrs":{}},{"type":"text","text":",与","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Item","attrs":{}}],"attrs":{}},{"type":"text","text":"的区别是移除了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"的定义。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\npublic class EmptyItem {\n private String string;\n private Date date;\n private Double doubleData;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这种情况下,会直接使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"EmptyItem","attrs":{}}],"attrs":{}},{"type":"text","text":"对象的字段作为表头名称。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeNoAnnotation() {\n final String fileName = defaultFileName(\"writeNoAnnotation\");\n EasyExcelFactory.write(fileName)\n .head(EmptyItem.class)\n .sheet(\"模板\")\n .doWrite(WriteSample::sampleItems);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里可以看到,EasyExcel对于表头对象、表体列表对象,没有强制要求必须是相同的对象,只要字段一致,就能够正常组装数据。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fd/fd3de63f420592b02060c43a3911911f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"自定义表头","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用字段作为表头显然不是我们想要的,EasyExcel提供了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"注解,可以定义表头的名称。这个注解还提供了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"index","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"order","attrs":{}}],"attrs":{}},{"type":"text","text":"两个属性,可以定义列的位置和顺序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\npublic class IndexItem {\n @ExcelProperty(value = \"字符串标题\", index = 1)\n private String string;\n @ExcelProperty(value = \"日期标题\", index = 3)\n private Date date;\n @ExcelProperty(value = \"数字标题\", index = 5)\n private Double doubleData;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用起来也很简单:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeWithIndex() {\n final String fileName = defaultFileName(\"writeWithIndex\");\n EasyExcelFactory.write(fileName)\n .head(IndexItem.class)\n .sheet(\"模板\")\n .doWrite(WriteSample::sampleItems);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d9/d9ebdc43639974914ff18dadef3f2a18.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里需要注意一下,在使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"注解时,index表示字段放置第几列,order表示顺序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根据index和order的不同语义,对两者的控制不同。如果index相同,直接会抛出异常,因为程序无法判断这个列放那个字段。如果index值中间有空的数字,就会出现空列。如果order和index同时使用,index优先占据位置,order做排序。index=-1的话,使用java默认排序,order值越小,列越靠前。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ExcelProperty","attrs":{}}],"attrs":{}},{"type":"text","text":"的value属性是字符串数组,相当于一个字段可以定义多个头,这样就可以实现多级表头。同时,如果位置相邻的列定义列明相同,还会合并列。比如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\npublic class ComplexHeadItem {\n @ExcelProperty({\"大标题\", \"字符串标题\"})\n private String string;\n @ExcelProperty(\"日期标题\")\n private Date date;\n @ExcelProperty({\"大标题\", \"数字标题0\"})\n private Double doubleData;\n @ExcelProperty({\"数字标题\"})\n private Double doubleData1;\n @ExcelProperty({\"数字标题\"})\n private Double doubleData2 = 0.0;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5b/5b170b11eaa3f8d7ce8771c35752545c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"动态表头、表体","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面的例子中,表头定义都是传入一个对象,通过解析对象的属性字段,抽取表头定义。有的时候,我们没有办法提前定义表头对象,或者说,表头是根据条件、权限等因素动态变化的,这个时候,就可以使用EasyExcel提供的动态表头功能了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 动态表头,传入的是{@code List>}格式数据。\n *

\n * 可以实现多层表头。\n */\nprivate static void writeDynamicHead() {\n String fileName = defaultFileName(\"writeDynamicHead\");\n EasyExcelFactory.write(fileName)\n .head(dynamicHead())\n .sheet()\n .doWrite(sampleItems());\n}\n\nprivate static List> dynamicHead() {\n List> heads = new ArrayList<>();\n final List head0 = new ArrayList<>(Arrays.asList(\"头0\", \"字符串标题【动态】\"));\n heads.add(head0);\n final List head1 = new ArrayList<>(Arrays.asList(\"头0\", \"日期标题【动态】\"));\n heads.add(head1);\n final List head2 = new ArrayList<>(Collections.singletonList(\"数字标题【动态】\"));\n heads.add(head2);\n return heads;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.metadata.AbstractParameterBuilder#head(java.util.List>)","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,传入","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"List>","attrs":{}}],"attrs":{}},{"type":"text","text":"类型的数据即可。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5e/5ed1e13df09a2fc9feac3f6ec17c0197.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当然,这样做还不是彻底的动态。我们可以使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.ExcelWriterSheetBuilder#doWrite(java.util.Collection>)","attrs":{}}],"attrs":{}},{"type":"text","text":"实现动态表体。代码如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeDynamicData() {\n String fileName = defaultFileName(\"writeDynamicData\");\n EasyExcelFactory.write(fileName)\n .head(dynamicHead())\n .sheet()\n .doWrite(dynamicData());\n}\n\nprivate static List> dynamicData() {\n List> list = new ArrayList<>();\n for (int i = 0; i < 10; i++) {\n List data = new ArrayList<>();\n data.add(\"字符串\" + i);\n data.add(new Date());\n data.add((i + 1) * 0.1);\n list.add(data);\n }\n return list;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f8b454a5977797c53aada91290b1fc7.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"表头国际化","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"互联网无国界,很多时候,我们需要实现国际化。这个时候,我们可以使用动态表头功能,传入不同的表头定义,生成不同的Excel文件。有时候,我们还需要提前定义表体的格式,使用动态表体可以实现。有没有更加简单方法呢?必须有。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先定义格式化表头对象:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\npublic class FormatContentItem {\n @ExcelProperty(value = \"字符串标题\", converter = TitleFormatConverter.class)\n private String string;\n @DateTimeFormat(\"yyyy年MM月dd日HH时mm分ss秒\")\n @ExcelProperty(value = \"日期标题\")\n private Date date;\n @NumberFormat(\"0.000%\")\n @ExcelProperty(\"数字标题\")\n private Double doubleData;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再实现国际化:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 可以同时设置head参数:\n * {@link AbstractParameterBuilder#head(java.util.List)}\n * {@link AbstractParameterBuilder#head(java.lang.Class)}\n *

\n * 对于表头设置,最终起作用的是{@link AbstractParameterBuilder#head(java.util.List)},这样的话,我们可以实现国际化的配置。\n */\nprivate static void writeDynamicMultiHead() {\n String fileName = defaultFileName(\"writeDynamicMultiHead\");\n EasyExcelFactory.write(fileName)\n .head(dynamicHead())\n .head(FormatContentItem.class)\n .sheet()\n .doWrite(sampleItems());\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ee/ee0b14846feb6d78eddb7c7720dee848.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"多次写入","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一般来说,中后台的数据量都不小,有时候需要一次导出几十万行数据,甚至更多,而这种操作并不是常态,如果内存配置比较大,那大多数时间内存都是闲置状态。此时,就可以借助EasyExcel的文件缓存能力,分批写入数据。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"向同一个excel同一个sheet中多次写入","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先是比较常见的场景,向一个sheet工作表中分批写入数据。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeOneSheet() {\n String fileName = defaultFileName(\"writeOneSheet\");\n ExcelWriter excelWriter = null;\n try {\n excelWriter = EasyExcelFactory.write(fileName)\n .head(Item.class)\n .build();\n final WriteSheet writeSheet = EasyExcelFactory.writerSheet(\"模板\").build();\n for (int i = 0; i < 5; i++) {\n excelWriter.write(sampleItems(), writeSheet);\n }\n } finally {\n // 千万别忘记finish 会帮忙关闭流\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriter","attrs":{}}],"attrs":{}},{"type":"text","text":"可以操作整个Excel工作簿,然后定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriter","attrs":{}}],"attrs":{}},{"type":"text","text":"sheet工作表,接下来就是循环调用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.ExcelWriter.write(java.util.Collection>, com.alibaba.excel.write.metadata.WriteSheet)","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,将数据写入到指定的sheet工作表中。这里需要注意的是,最后一定要调用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.ExcelWriter.finish","attrs":{}}],"attrs":{}},{"type":"text","text":"方法,表示停止写入并关闭流。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/75/759cb99bac7dc8d7ed1b997bd5976210.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"向同一个excel不同sheet中多次写入(表头相同)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"还有一种场景是按月导出全年的订单数据,每个月一个sheet工作表,这种导出的方式,表头都是相同的。根据上面的经验,我们需要定义多个","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"工作表对象,然后向该对象中写数据。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里还可能有一种情况,就是我们需要在多个","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"工作表对象之间切换写入,为了不会找错对象,可以指定","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"sheetNo","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代码如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeDiffSheetWithSameHead() {\n String fileName = defaultFileName(\"writeDiffSheetWithSameHead\");\n ExcelWriter excelWriter = null;\n try {\n excelWriter = EasyExcelFactory.write(fileName)\n .head(Item.class)\n .build();\n for (int i = 0; i < 5; i++) {\n final WriteSheet writeSheet = EasyExcelFactory.writerSheet(i, \"模板\" + i)\n .build();\n excelWriter.write(sampleItems(), writeSheet);\n }\n } finally {\n // 千万别忘记finish 会帮忙关闭流\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/30/307c827618e07979b7eac7eddbeae0ca.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3c/3cef53ea7774e84f5893b19a1ad8ab81.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"向同一个excel不同sheet中多次写入(表头不同)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"还有一种场景,导出指定时间范围的订单信息,一个sheet工作表放具体的商品信息,另一个sheet工作表放订单收货地址信息。这种场景就需要不同的表头,根据前面的讲解,我们知道,只需要在定义","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"对象时指定不同的表头对象即可。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代码如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeDiffSheetWithDiffHead() {\n String fileName = defaultFileName(\"writeDiffSheetWithDiffHead\");\n ExcelWriter excelWriter = null;\n try {\n excelWriter = EasyExcelFactory.write(fileName)\n .build();\n\n final WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0, \"模板1\")\n .head(Item.class)\n .build();\n excelWriter.write(sampleItems(), writeSheet0);\n\n final WriteSheet writeSheet1 = EasyExcelFactory.writerSheet(1, \"模板2\")\n .head(ComplexHeadItem.class)\n .build();\n excelWriter.write(sampleItems(), writeSheet1);\n } finally {\n // 千万别忘记finish 会帮忙关闭流\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/91/917d64063f22ed597a5ba00202900754.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/89/897147abe41bb42e6ee33accb1347f2d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"实现多表","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"EasyExcel对于Excel文件定义分成了三层,","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"工作簿,也就是Excel文件","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"工作表,对应是Excel文件中的Sheet","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"表格,对应是Sheet中的有表头、表体的组合","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里所说的功能就是在一个Sheet中创建多个表格。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"同一表单中创建表格","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这个是开胃菜,演示一下怎么单独指定表格。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeTable() {\n String fileName = defaultFileName(\"writeTable\");\n final ExcelWriter excelWriter = EasyExcelFactory.write(fileName)\n .head(Item.class)\n .build();\n try {\n // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了\n WriteSheet writeSheet = EasyExcelFactory.writerSheet()\n .needHead(Boolean.FALSE)\n .build();\n\n // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要\n WriteTable writeTable0 = EasyExcelFactory.writerTable(0)\n .needHead(Boolean.TRUE)\n .build();\n\n excelWriter.write(sampleItems(), writeSheet, writeTable0);\n } finally {\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,除了前面提过的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriter","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":",这里还用到了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteTable","attrs":{}}],"attrs":{}},{"type":"text","text":",这个就是表格的写对象。有了这个对象,我们只要多创建几个,就能够实现在一个Sheet工作表中,创建多个表格的功能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c0/c0865cc830c9043af1976e6011a939f5.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"与前面的例子完全没有差别,条条大路通罗马。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"同一表单中创建不同表格(相同表头)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了上面的铺垫,我们直接上代码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeTables() {\n String fileName = defaultFileName(\"writeTables\");\n final ExcelWriter excelWriter = EasyExcelFactory.write(fileName)\n .build();\n try {\n // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了\n WriteSheet writeSheet = EasyExcelFactory.writerSheet()\n .head(Item.class)\n .needHead(Boolean.FALSE)\n .build();\n\n // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要\n WriteTable writeTable0 = EasyExcelFactory.writerTable(0)\n .needHead(Boolean.TRUE)\n .build();\n\n WriteTable writeTable1 = EasyExcelFactory.writerTable(1)\n .needHead(Boolean.TRUE)\n .build();\n // 第一次写入会创建头\n excelWriter.write(sampleItems(), writeSheet, writeTable0);\n // 第二次写如也会创建头,然后在第一次的后面写入数据\n excelWriter.write(sampleItems(), writeSheet, writeTable1);\n } finally {\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因为使用的是相同的表头,我们可以直接在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"中定义表头对象,通过继承的方式,实现两个表格的表头是相同的。这里需要注意一下,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteSheet","attrs":{}}],"attrs":{}},{"type":"text","text":"构建时,设置","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"needHead(Boolean.FALSE)","attrs":{}}],"attrs":{}},{"type":"text","text":",如果不设置或者设置为true,那第一个表格就会有两个表头。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fb/fb0ec6caa90c9b0575658fb6eb51f0b8.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"同一表单中创建不同表格(不同表头)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"举一反三,对于不同表头,我们只需要为","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"WriteTable","attrs":{}}],"attrs":{}},{"type":"text","text":"对象设置不同表头即可:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeTablesWithDiffHead() {\n String fileName = defaultFileName(\"writeTablesWithDiffHead\");\n final ExcelWriter excelWriter = EasyExcelFactory.write(fileName)\n .build();\n try {\n WriteSheet writeSheet = EasyExcelFactory.writerSheet()\n .build();\n\n WriteTable writeTable0 = EasyExcelFactory.writerTable(0)\n .head(Item.class)\n .build();\n excelWriter.write(sampleItems(), writeSheet, writeTable0);\n\n WriteTable writeTable1 = EasyExcelFactory.writerTable(1)\n .head(ComplexHeadItem.class)\n .build();\n excelWriter.write(sampleItems(), writeSheet, writeTable1);\n } finally {\n if (excelWriter != null) {\n excelWriter.finish();\n }\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"结果为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cf/cf9de2bb33118cb352f1112dc4f3849b.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"写入模板文件(非填充)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有时候,我们需要按照某种模板导出数据,这类模板文件属于固定样式,没有动态数据。比如前面几行是标题、权限声明、责任声明之类的,紧跟着就是列表数据。如果全靠手工拼写数据比较繁琐,EasyExcel提供了写入模板文件的方式。先看代码:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static void writeByTemplate() {\n String fileName = defaultFileName(\"writeByTemplate\");\n String templateFile = getPath() + File.separator + \"template_write_after_fill.xlsx\";\n EasyExcelFactory.write(fileName)\n .withTemplate(templateFile)\n .head(Item.class)\n .sheet()\n .doWrite(sampleItems());\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要使用","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"com.alibaba.excel.write.builder.ExcelWriterBuilder#withTemplate(java.lang.String)","attrs":{}}],"attrs":{}},{"type":"text","text":"指定模板文件路径。withTemplate方法有几个重载实现:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"指定模板文件路径","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterBuilder#withTemplate(java.lang.String)","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"指定模板文件对象","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterBuilder#withTemplate(java.io.File)","attrs":{}}],"attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"指定模板文件输入流","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ExcelWriterBuilder#withTemplate(java.io.InputStream)","attrs":{}}],"attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"指定模板文件和模板文件对象都是操作文件的,需要有文件信息。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"指定模板文件输入流是只要文件流,这个可操作性空间就比较大了。比如,模板文件是可变的,我们可以基于一个带变量的模板文件,使用填充写入的方式初始化模板文件,然后再用模板写入的方式,写入列表。(这个会在技巧篇中详细说明)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代码中的模板文件内容:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bd/bd2c93b8e3fc7db35f6a9a719a3602e4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导出文件的内容:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/35/352a9db70240bc5d321c0430986e6292.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看出,这种方式写入的列表是以追加的方式写入,原有的模板内容不会修改,会从第一行空白行开始写列表信息。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"文末总结","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文从实战角度说了一下 EasyExcel 如果实现写表格,接下来会讲解一下如何更好看的写。","attrs":{}}]},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你好,我是看山。游于码界,戏享人生。如果文章对您有帮助,请点赞、收藏、关注。我还整理了一些精品学习资料,关注公众号「看山的小屋」,回复“资料”即可获得。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9e/9e305acd1cca75053c144cb28adc6061.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章