# Apache POI Export **Repository Path**: carbon-studio/apache-poi-export ## Basic Information - **Project Name**: Apache POI Export - **Description**: 基于Apache POI的工具类库,主要解决ERP、WMS、CRM等管理系统的数据以.xlsx文件形式导出。通过精简接口,链式编程以及策略模式等简化电子表格的数据录入,映射规则,样式处理以及合并操作,帮助开发人员注重业务而非调取样式和格式。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-23 - **Last Updated**: 2025-09-27 ## Categories & Tags **Categories**: excel-utils **Tags**: None ## README

Apache POI Export.xlsx📜

Static Badge Static Badge Static Badge
#### 介绍 基于Apache POI的工具类库,主要解决ERP、WMS、CRM等管理系统的数据以.xlsx文件形式导出。通过适配器精简接口,支持链式编程以及采用策略模式和组合模式简化电子表格的数据录入,映射规则,样式处理以及合并操作,帮助开发人员注重业务而非调取样式和格式。详细文档教程参考:[📖 Exporter参考文档](./参考文档.md) ![输入图片说明](resources/demo.jpg) #### 项目结构 - **poi-export-core包**:核心类库,Exporter的源码在此包下。 - **poi-export-demo包**:为测试Exporter工具类的使用而简单搭建的Spring boot项目环境。 #### 快速开始 直接起接口框架,参数记得带上HttpServletResponse对象。 ```java @RestController public class testExporter { @GetMapping("/export") public void export(HttpServletResponse response) throws Exception { XBook book = new XBook(); //创建工作簿 book.setFileName("测试文件"); //给工作簿起名字(实际上是.xlsx的文件名) book.createSheets(new String[]{"Sheet1"}); //创建个工作表,没有工作表的空簿可能打不开 List objects = Service.getData(); //从服务层拿到实体的列表数据 book.putBuildData(objects);//把数据给book对象 Exporter exporter= new Exporter(book); //创建导出器,把工作簿给导出器 exporter.export(response); //导出 } } ``` 数据是录入了,但是布局对应的代码在哪呢?导出的Excel表格长什么样子? 实际上,对于一个工作表,就应当有一个构造策略来告诉构造器这个工作表应该如何布局。如果没录入,则默认使用默认策略(DefaultStrategy)。默认策略是将传入的实体类列表按照基本表格布局:填充内容直接来自字段名,每一行都对应每一个实体类的属性值组成的元组,默认展示所有字段值,表格列宽为自动适配内容,且再无其他样式装饰。 你可以为工作表显式的声明其他的策略或自定义策略: ```java book.putBuildStrategy("Sheet1", new TableStrategy()); ``` `TableStrategy()`是在默认策略(DefaultStrategy)上添加了表头,表头内容通过反射直接拿取对象的私有成员名。 #### 参考文档 ##### 1.设计原理 所有的Excel表格的效果都可由操作:数据录入,样式应用,单元格合并,设置列宽这四步从零开始顺序执行来实现。 ![输入图片说明](resources/ExcelBuild.png) Exporter就建立在这一条基础假设之上来保证表格设计的功能完备性。以下是带泳道的活动图,用于展示这四步操作细化的具体步骤以及承担它们的对象。 输入图片说明 ##### 2.生成.xlsx文件 **2.1创建一个.xlsx文件** ```java XBook book = new XBook("test"); //方案一:构造函数 ``` ```java XBook book = new XBook(); //方案二:set方法 book.setFileName("test"); ``` 一个Excel文件就是一个工作簿,工作簿下可以有一个或多个工作表。单纯创建一个工作簿不会默认初始化一个工作表,所以打开没有工作表的工作簿可能导致Excel文件打开报错。 **2.2为.xlsx文件创建工作表** **创建一个工作表** ```java XBook book = new XBook(); book.setFileName("22级信息表"); book.createSheet("22级电气一班"); //至少创建个工作表,否则没有工作表的空簿可能打不开 ``` **创建多个工作表** ```java book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); ``` ##### 3.导出.xlsx文件 **3.1 创建导出器** ```java XBook book = new XBook("22级信息表"); book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); Exporter exporter= new Exporter(book); //创建导出器,把工作簿对象给导出器 ``` **3.2 从Response响应导出** 在Spring Boot中,导出的接口方法要带上HttpServletResponse参数,把参数传递给导出器以便导出到浏览器。 ```java @RestController public class testExporter { @GetMapping("/export") public void export(HttpServletResponse response) throws Exception { XBook book = new XBook("22级信息表"); //创建工作簿 book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); Exporter exporter= new Exporter(book); //创建导出器,把工作簿给导出器 exporter.export(response); //导出 } } ``` **3.3 选择导出的场景** 某些场景下,需要通过前端传递过来的参数来判断导出哪一种文件。可以预先准备好这些文件,后端通过if-else分支来解决。 ```java @RestController public class testExporter { @GetMapping("/export") public void export(HttpServletResponse response, int parameter) throws Exception { XBook book22 = new XBook("22级信息表"); //创建工作簿 book22.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); XBook book23 = new XBook("23级信息表"); //创建工作簿 book23.createSheets(new String[]{"23级电气一班","23级电气二班","23级电气三班"}); XBook book24 = new XBook("24级信息表"); //创建工作簿 book24.createSheets(new String[]{"24级电气一班","24级电气二班","24级电气三班"}); Exporter exporter= new Exporter(); //创建导出器,把工作簿给导出器 if(parameter==22){ exporter.setBook(book22); }else if(parameter==23){ exporter.setBook(book23); }else if(parameter==24){ exporter.setBook(book24); } exporter.export(response); //导出 } } ``` 不建议让语句`exporter.export(response);`嵌套进if-else分支,当复杂判断结构不良,条件重合使得`exporter.export(response);`执行多次,会向已经提交(committed)的HTTP响应写入数据,产生错误:**java.io.IOException: Response already committed** ##### 4.工作表设计 **4.1 工作表布局的生成** 一个工作簿有多个工作表,在创建多个工作表时,应当指明每个工作表该按照什么策略生成。 一个工作表的构成元素分为两部分:**样式和数据**。因此每个工作表的生成策略都由含有参数样式和数据的策略接口说明。 所有的样式元素对象全部可通过工作表对象获取和修改。因此设计以XSheet负责样式,List\负责数据,策略接口如下: ```java public interface BuildStrategy { public void build(XSheet sheet, List data); } ``` Exporter库中设计了一个默认策略,当用户未编写策略时,默认使用该策略生成。 ```java public class DefaultStrategy implements BuildStrategy{...} ``` 为方便理解,显式的调用情况是这样的: ```java XBook book = new XBook("22级信息表"); //创建工作簿 book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); book.putBuildStrategy("22级电气一班", new DefaultStrategy()); book.putBuildStrategy("22级电气二班", new DefaultStrategy()); book.putBuildStrategy("22级电气三班", new DefaultStrategy()); ``` **4.2 为工作表设计生成策略** 现在的情况是三个班级的表都采用默认策略,代码如上节。现在的需求是为"22级电气一班"工作表设计一种新的生成策略。 如果三个班级的数据全部都封装在了List\中,那么仅需要设置一个全局的数据源即可,这使得全部的工作表都能拿到这一份数据源,从中获取自己数据的那一部分。 ```java List students = Service.getData(); //拿到数据 XBook book = new XBook("22级信息表"); //创建工作簿 book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); book.putBuildStrategy("22级电气一班", new DefaultStrategy()); book.putBuildStrategy("22级电气二班", new DefaultStrategy()); book.putBuildStrategy("22级电气三班", new DefaultStrategy()); book.putBuildData(students); ``` 而如果数据在Service层就划分开来了,那么你可以为每一个工作表都分配一个数据源。 ```java List studentsFromClass1 = Service.getDataFromClass1(); //拿到数据 List studentsFromClass2 = Service.getDataFromClass2(); List studentsFromClass3 = Service.getDataFromClass3(); XBook book = new XBook("22级信息表"); //创建工作簿 book.createSheets(new String[]{"22级电气一班","22级电气二班","22级电气三班"}); book.putBuildStrategy("22级电气一班", new DefaultStrategy()); book.putBuildStrategy("22级电气二班", new DefaultStrategy()); book.putBuildStrategy("22级电气三班", new DefaultStrategy()); book.putBuildData("22级电气一班", studentsFromClass1); book.putBuildData("22级电气二班", studentsFromClass2); book.putBuildData("22级电气三班", studentsFromClass3); ``` 现在需要写自己的设计策略了: ```java public class MyStrategy implements BuildStrategy{ @Override public void build(XSheet sheet, List data) { /*这里data的实际数据就是book.putBuildData方法给设定的数据*/ } } ``` 当策略写完之后,仅需将`book.putBuildStrategy("22级电气一班", new DefaultStrategy());`中的`new DefaultStrategy()`换成`new MyStrategy()`即可。 关于生成策略的详细文档教程参考:[📖 Exporter参考文档](./参考文档.md) #### 如何部署到本地? 可从Intellij IDEA中创建项目,选择Project form Version Control,填写Git仓库地址: https://gitee.com/carbon-studio/apache-poi-export