【Java】POI Excel导出 动态行合并
一般情况:
Excel导出一般都是一行一行的记录输出
、
这是Controller代码:
标题行的设置:
标题行会设置获取的结果集的字段名,数据会自动根据设置的名称匹配装填
特殊的需求:
如页面的效果,附加的三个字段存在多个记录,需要合并和之前的主记录拼接处理:
右侧的数据是根据这个接口提供的:
页面有用循环回调来实现
但是导出功能,开发干脆就没写这部分了???
所以BA要我把这个部分给弄出来
合并原理:
关于POI框架和用友提供的封装方法都没有这样关于记录行合并的操作:
现有的方式都是对标题行进行合并设置的
这是一段原框架中的Main方法Demo案例:
public static void main(String[] args) {
NormalExcelExport excel = new NormalExcelExport();
SXSSFWorkbook wb = excel.createExcelWork();
List<List<ExcelCol>> colColList = new LinkedList();
List<ExcelCol> exColList = new LinkedList();
exColList.add(new ExcelCol("TEST1", "测试1", 2, 1));
exColList.add(new ExcelCol("TEST2", "测试2", 2, 1));
exColList.add(new ExcelCol("TEST3", "测试3", 1, 3));
colColList.add(exColList);
List<ExcelCol> exColList1 = new LinkedList();
exColList1.add(new ExcelCol("TEST1", "测试1"));
exColList1.add(new ExcelCol("TEST2", "测试2"));
exColList1.add(new ExcelCol("TEST3", "测试3"));
colColList.add(exColList1);
List<Map> datas = new LinkedList();
Map map1 = new HashMap();
map1.put("TEST1", "1");
map1.put("TEST2", "2");
map1.put("TEST3", "3");
datas.add(map1);
String[] fieldNames = new String[]{"TEST1", "TEST2", "TEST3"};
excel.addSheetMerge(wb, colColList, fieldNames, datas, "第1页"); try {
excel.saveLocal(wb, "F:/", "test1.xlsx");
} catch (Exception var10) {
var10.printStackTrace();
} }
文件效果:
每一次添加之后该方法会将迭代器拨动至下一个基本单元行
colColList.add(exColList);
方法执行之后,迭代器换行至这个位置:
这时就是程序理解的第二行:
添加完第二行记录之后,迭代器切换至第三行:
所以到这里我们就明白合并操作的原理了
这是我写的一个简单的案例:
private static void demo2() {
NormalExcelExport excel = new NormalExcelExport();
SXSSFWorkbook wb = excel.createExcelWork(); // 总表格
List<List<ExcelCol>> colColList = new LinkedList(); // 标题行
List<ExcelCol> exColList = new LinkedList();
exColList.add(new ExcelCol("TEST1", "标题1"));
exColList.add(new ExcelCol("TEST2", "标题2"));
exColList.add(new ExcelCol("TEST3", "标题3"));
// 要合并的行标题
exColList.add(new ExcelCol("TEST4", "标题4"));
exColList.add(new ExcelCol("TEST5", "标题5"));
exColList.add(new ExcelCol("TEST6", "标题6")); colColList.add(exColList); // 单次合并实现
List<ExcelCol> leftSideRow = new LinkedList(); // 左侧单元格 实现行合并
leftSideRow.add(new ExcelCol("TEST1", "AAA", 2, 1));
leftSideRow.add(new ExcelCol("TEST2", "BBB", 2, 1));
leftSideRow.add(new ExcelCol("TEST3", "CCC", 2, 1));
leftSideRow.add(new ExcelCol("TEST4", "41"));
leftSideRow.add(new ExcelCol("TEST5", "42"));
leftSideRow.add(new ExcelCol("TEST6", "43"));
colColList.add(leftSideRow);
leftSideRow = new LinkedList<>();
leftSideRow.add(new ExcelCol("TEST4", "51"));
leftSideRow.add(new ExcelCol("TEST5", "52"));
leftSideRow.add(new ExcelCol("TEST6", "53"));
colColList.add(leftSideRow); List<ExcelCol> smapleRow = new LinkedList();
smapleRow.add(new ExcelCol("TEST1", "AAA3", 3, 1));
smapleRow.add(new ExcelCol("TEST2", "AAA4", 3, 1));
smapleRow.add(new ExcelCol("TEST3", "AAA5", 3, 1));
smapleRow.add(new ExcelCol("TEST4", "AAA6"));
smapleRow.add(new ExcelCol("TEST5", "AAA7"));
smapleRow.add(new ExcelCol("TEST6", "AAA8")); colColList.add(smapleRow); // 换行时注意 前3个合并了3行,下一行会是 AA5开始
smapleRow = new LinkedList<>();
smapleRow.add(new ExcelCol("TEST4", "AAA26"));
smapleRow.add(new ExcelCol("TEST5", "AAA27"));
smapleRow.add(new ExcelCol("TEST6", "AAA28"));
colColList.add(smapleRow);
smapleRow = new LinkedList<>();
smapleRow.add(new ExcelCol("TEST4", "AAA26"));
smapleRow.add(new ExcelCol("TEST5", "AAA27"));
smapleRow.add(new ExcelCol("TEST6", "AAA28"));
colColList.add(smapleRow); excel.addSheetMerge(wb, colColList, null, null, "第1页"); try {
excel.saveLocal(wb, "D:/", "test1.xlsx");
} catch (Exception var10) {
var10.printStackTrace();
}
}
回到业务需求:
/**
*
* @param queryParam
* @return
* @throws Exception
*/
@RequestMapping(value = "/exportData2", method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> SSPInvoiceSumReportExport2(@RequestParam Map<String, String> queryParam)
throws Exception {
ElemBean condition = new ElemBean(queryParam);
List<List<ExcelCol>> colColList = new LinkedList();
// 设置标题行
List<ExcelCol> titleColList = new LinkedList<ExcelCol>();
titleColList.add(new ExcelCol("asc_code","维修站代码"));
titleColList.add(new ExcelCol("SAP_CODE","SAP码"));
titleColList.add(new ExcelCol("asc_name","维修站名称"));
titleColList.add(new ExcelCol("invoice_no","发票号"));
titleColList.add(new ExcelCol("no_tax_amount","不含税金额"));
titleColList.add(new ExcelCol("invoice_amount","含税金额"));
titleColList.add(new ExcelCol("tax_amount","税费"));
titleColList.add(new ExcelCol("audit_status","状态", ExcelDataType.DICT));
titleColList.add(new ExcelCol("invoice_date","发票日期",ExcelDataType.DATEYYYYMMDD));
titleColList.add(new ExcelCol("created_at","提报日期",ExcelDataType.DATEYYYYMMDD));
titleColList.add(new ExcelCol("sap_code1","冲收入代码"));
titleColList.add(new ExcelCol("product_price","合同金额"));
titleColList.add(new ExcelCol("no_tax_income_amount","收入金额(不含税)"));
colColList.add(titleColList); // 需要getInvoiceQuery的查询条件 设置 limit 9999999
// PageInfoDto pageInfoDto = service.getInvoiceQuery(new ElemBean(queryParam)); List<Object> params = new LinkedList<Object>();
String sql = service.getSspInvoiceSumReportExpSql(condition, params);
List<Map> pageInfoDto = DcsDaoUtil.findAll(sql, params); // 左侧的主结果集 Map<String,String> distMap = new LinkedHashMap<>();
distMap.put("59701001","已提交");
distMap.put("59701002","已审核");
distMap.put("59701003","已驳回");
distMap.put("59701004","已核销"); for (int i = 0; i < pageInfoDto.size(); i++) {
// 当前行
Map currentRow = pageInfoDto.get(i); String invoice_no = StringUtils.isNullOrEmpty(currentRow.get("invoice_no")) ? "" : currentRow.get("invoice_no").toString(); // 发票单号为空的情况
List<Map> invoiceDetail = new LinkedList<>();
// 右侧的
if(!"".equals(invoice_no) && invoice_no != null){
invoiceDetail = service.getInvoiceDetail(invoice_no, null); // 右侧结果集
}
titleColList = new LinkedList<>();
titleColList.add(new ExcelCol("asc_code", StringUtils.isNullOrEmpty(currentRow.get("asc_code")) ? "" : currentRow.get("asc_code").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("SAP_CODE", StringUtils.isNullOrEmpty(currentRow.get("SAP_CODE")) ? "" : currentRow.get("SAP_CODE").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("asc_name", StringUtils.isNullOrEmpty(currentRow.get("asc_name")) ? "" : currentRow.get("asc_name").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("invoice_no", StringUtils.isNullOrEmpty(currentRow.get("invoice_no")) ? "" : currentRow.get("invoice_no").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("no_tax_amount", StringUtils.isNullOrEmpty(currentRow.get("no_tax_amount")) ? "" : currentRow.get("no_tax_amount").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("invoice_amount", StringUtils.isNullOrEmpty(currentRow.get("invoice_amount")) ? "" : currentRow.get("invoice_amount").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("tax_amount", StringUtils.isNullOrEmpty(currentRow.get("tax_amount")) ? "" : currentRow.get("tax_amount").toString(),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("audit_status", StringUtils.isNullOrEmpty(currentRow.get("audit_status")) ? "" : distMap.get( currentRow.get("audit_status").toString()),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("invoice_date", StringUtils.isNullOrEmpty(currentRow.get("invoice_date")) ? "" : currentRow.get("invoice_date").toString().substring(0,10),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
titleColList.add(new ExcelCol("created_at", StringUtils.isNullOrEmpty(currentRow.get("created_at")) ? "" : currentRow.get("created_at").toString().substring(0,10),invoiceDetail.size() == 0 ? 1 : invoiceDetail.size() , 1));
for(int j = 0 ; j < invoiceDetail.size() ; j ++){
if(j == 0){ // 第一行的的时候就需要和前面的内容 并列为一行
titleColList.add(new ExcelCol("sap_code1",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("sap_code1")) ? "" : invoiceDetail.get(j).get("sap_code1").toString()));
titleColList.add(new ExcelCol("product_price",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("product_price")) ? "" : invoiceDetail.get(j).get("product_price").toString()));
titleColList.add(new ExcelCol("no_tax_income_amount",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("no_tax_income_amount")) ? "" : invoiceDetail.get(j).get("no_tax_income_amount").toString()));
colColList.add(titleColList);
}else{ // 后面下推的行记录就是新的一行了
titleColList = new LinkedList<>();
titleColList.add(new ExcelCol("sap_code1",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("sap_code1")) ? "" : invoiceDetail.get(j).get("sap_code1").toString()));
titleColList.add(new ExcelCol("product_price",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("product_price")) ? "" : invoiceDetail.get(j).get("product_price").toString()));
titleColList.add(new ExcelCol("no_tax_income_amount",StringUtils.isNullOrEmpty(invoiceDetail.get(j).get("no_tax_income_amount")) ? "" : invoiceDetail.get(j).get("no_tax_income_amount").toString()));
colColList.add(titleColList);
} } if(invoiceDetail.size() == 0){ // 还存在右边结果集查不到结果的情况,这一行也要保留为空记录
titleColList.add(new ExcelCol("sap_code1",""));
titleColList.add(new ExcelCol("product_price",""));
titleColList.add(new ExcelCol("no_tax_income_amount",""));
colColList.add(titleColList);
}
} // for local tested , write by dzz 2021年5月20日18:28:41
// NormalExcelExport excel = new NormalExcelExport();
//
// SXSSFWorkbook wb = excel.createExcelWork();
//
// excel.addSheetMerge(wb, colColList, null, null, "第1页");
// excel.saveLocal(wb, "D:/", "test1.xlsx"); Map<String, Object> maps = jmcExc.addSheetMerge(colColList, null, " select * from (select 1 + 1 ) a where 1 = 2 ", null, "SSP发票汇总报表.xlsx", "SSP发票汇总报表", null);
return maps;
}
最后的调用方法:
Map<String, Object> maps = jmcExc.addSheetMerge(colColList, null, " select * from (select 1 + 1 ) a where 1 = 2 ", null, "SSP发票汇总报表.xlsx", "SSP发票汇总报表", null);
SQL参数时方法中有一个数据装填操作,如果SQL没有记录就不会装数据执行:
无记录的SQL:
" select * from (select 1 + 1 ) a where 1 = 2 "
要求的字段名为空,SQL参数空
最后直接把这个【标题结果集】丢进去,就实现了页面的那种效果
【Java】POI Excel导出 动态行合并的更多相关文章
- java POI excel 导出复合样式(一个单元格两个字体)
前言:java poi 导出 excel 时,需要设置一个单元格有多个字体样式,有点类似于富文本. 想要达到的效果(一个单元格里): 我使用的 poi 版本是 <dependency> & ...
- Java POI导入导出Excel
1.异常java.lang.NoClassDefFoundError: org/apache/poi/UnsupportedFileFormatException 解决方法: 使用的poi的相关jar ...
- Java POI Excel 导入导出
这个东西很容易懂,不是特别难,难就难在一些复杂的计算和Excel格式的调整上. 近期写了一个小列子,放上来便于以后使用. POI.jar下载地址:http://mirror.bit.edu.cn/ap ...
- poi excel超出65536行数限制自动扩展Invalid row number (65536) outside allow
1.xls一个sheet只能装65536行,多余则报错 poi包导出或写入excel超出65536报错: java.lang.IllegalArgumentException: Invalid row ...
- JAVA实现Excel导出数据(以写好的Excel模版导出)
工作中经常会有将后台数据以Excel导出的功能. 简单的方法有将response的contentType设置为application/vnd.ms-excel: 或在JSP页面直接设置成: <% ...
- java中Excel导出
转载:https://www.cnblogs.com/gudongcheng/p/8268909.html,稍加修改了 https://www.cnblogs.com/hanfeihanfei/p/7 ...
- java-excel导出
java excel导出分为两种2003年的格式和2007年的格式. 2003年的xls一个sheet限制65536. 2007年的xlsx限制为1048576. jxl导入2003 gradle j ...
- poi excel导出 xssf 带下拉框
需求:导出之后带有二级级联的下拉框.(类似于省市). 最初的思路是怀疑是不是数组内串太多了,导出之后的excel有36行,调试的误区在于刚开始认为对行数有限制,后自己写了一个测试类,才发现不是行数,而 ...
- java, poi, excel
工作需要用java操作Excel,现在网上搜索了一下,决定选取POI包来操作.pom内容如下: <dependency> <groupId>org.apache.poi< ...
- JAVA POI XSSFWorkbook导出扩展名为xlsx的Excel,附带weblogic 项目导出Excel文件错误的解决方案
现在很多系统都有导出excel的功能,总结一下自己之前写的,希望能帮到其他人,这里我用的是XSSFWorkbook,我们项目在winsang 用的Tomcat,LInux上用的weblogic服务器, ...
随机推荐
- 利用nodejs的require.context来实现不用写impor导入组件
先给你们看下目录结构 stuendt和teacharts还有util是同级 主要是componentRegister.js文件 function changStr(str) { return str. ...
- Kubernetes监控手册06-监控APIServer
写在前面 如果是用的公有云托管的 Kubernetes 集群,控制面的组件都交由云厂商托管的,那作为客户的我们就省事了,基本不用操心 APIServer 的运维.个人也推荐使用云厂商这个服务,毕竟 K ...
- Ton 区块链的官方 类ERC20-Token 智能合约代码-Transfer部分解析
作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 GitHub : https://github.co ...
- MyBatis的逆向工程详细步骤操作
1. MyBatis的逆向工程详细步骤操作 @ 目录 1. MyBatis的逆向工程详细步骤操作 2. 逆向工程配置与生成 2.1 MyBatis3Simple:基础版,只有基本的增删改查 2.1.1 ...
- 异步任务处理注解方法@Async实现异步多线程
异步任务处理注解方法@Async实现异步多线程 1.定义配置类,设置参数2.定义任务执行类3.执行Spring 中的ThreadPoolExecutor是借助JDK并发包中的java.util.con ...
- FreeRTOS简单内核实现6 优先级
0.思考与回答 0.1.思考一 如何实现 RTOS 内核支持多优先级? 因为不支持优先级,所以所有的任务都插入了一个名为 pxReadyTasksLists 的就绪链表中,相当于所有任务的优先级都是一 ...
- python重拾基础第三天
本节内容 函数基本语法及特性 参数与局部变量 返回值 嵌套函数 递归 匿名函数 函数式编程介绍 高阶函数 内置函数 1. 函数基本语法及特性 背景提要 现在老板让你写一个监控程序,监控服务器的系统状况 ...
- Linux Driver : i2c-gpio
# Linux Driver : i2c-gpio https://www.cnblogs.com/haoxing990/p/4718834.html https://blog.csdn.net/ji ...
- python基础-基本语句
1 条件语句 在进行逻辑判断时,我们需要用到条件语句,Python 提供了 if.elif.else 来进行逻辑判断.格式如下所示: 1 if 判断条件1: 2 执行语句1... 3 elif 判断条 ...
- 为什么说这款99元国产ARM工业平台,具有“划时代”意义
随着近年来进口处理器涨价不断,大家会发现市面上已很少见到99元的ARM工业核心板出售. 为满足客户对低成本.高性能的需求,创龙科技推出基于全志T113-i国产ARM工业处理器的"划时代&qu ...