【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參數空

最后直接把這個【標題結果集】丟進去,就實現了頁面的那種效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM