• 【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参数空

    最后直接把这个【标题结果集】丢进去,就实现了页面的那种效果

  • 相关阅读:
    JVM简单入门
    10 张图聊聊线程的生命周期和常用 APIs
    Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期
    ueditor 插入视频代码解析
    CentOS下添加新硬盘并分区格式化的详细步骤
    Java 8 stream
    crontab命令详解
    计算机网络自顶向下学习杂记
    nginx安装
    js识别PC和H5
  • 原文地址:https://www.cnblogs.com/mindzone/p/14792825.html
Copyright © 2020-2023  润新知