使用poi生成復雜多行表頭


  最近公司的項目需要添加導出報表的功能,報表都是多行表頭,最初是使用事先創建模板然后導出的方式,但是隨着報表數量的增加和模板表頭的變動,這種導出方案就不合適了。因此嘗試使用了poi動態生成復雜多行表頭的方式導出。說明一下,表頭格式來源是根據頁面表格屬性生成的,其中頁面表格是使用了jqgrid框架。以下是代碼實現過程:

  一、js獲取表格屬性的共用方法:

  1、獲取表格的行和列屬性;

  2、獲取數據行的屬性和數據格式,方便動態添加數據行;

  3、獲取導出文件名,把菜單名作為導出的excel文件名。

  

/**
 * 下載報表,使用poi,並根據頁面報表動態創建表頭,不需要事先創建模板
 * @param gridId 頁面表格ID
 * @param formId 
 */
function downloadReport(gridId, formId) {
    var downloadReportUrl = "downloadReport";
    var exportHeader = $("#gview_" + gridId).find('div.ui-jqgrid-hdiv').find('table').eq(0).find('tr');
    //獲取表頭行列屬性(為了生成多行表頭)
    var mergedRegions = "";
    for(var i = 0;i<exportHeader.length;i++){
        var mergedRegion = "";
        exportHeader.eq(i).find('th:visible').each(function(){
            if($(this).text() != null && $(this).text() != ''){
                var rowspan = $(this).attr('rowspan');
                var colspan = $(this).attr('colspan');
                if(rowspan == null || rowspan == undefined){
                    rowspan = 0;
                }
                if(colspan == null || colspan == undefined){
                    colspan = 0;
                }
                mergedRegion += $(this).text() + "," +rowspan + "," + colspan + ":"
            }
        });
        if(mergedRegion != ""){
            mergedRegion = mergedRegion.substring(0, mergedRegion.length-1);
            mergedRegions += mergedRegion + ";";
        }
    }
    if(mergedRegions != ""){
        mergedRegions = mergedRegions.substring(0, mergedRegions.length-1);
    }
    //獲取數據行
    var exportBody = $("#gview_" + gridId).find('div.ui-jqgrid-bdiv').find('table').eq(0).find('tr');
    if(exportBody.length <= 1){
        showAlert("不能導出空報表,請點擊查詢后再導出!", "信 息");
        return;
    }
    //獲取首行數據行(獲取name和value,為了導出excel的數據和格式的填充)
    var columnNames = "";
    exportBody.eq(1).find('td:visible').each(function(){
        var key = $(this).attr('aria-describedby');
        var value = $(this).text();
        if(key){
            if(key == ""){
                showAlert("報表下載出錯,請聯系系統管理員!", "信 息");
                return;
            }
            key = key.replace(gridId + '_','');
            columnNames += key + "=" + value +"^_^";
        }
    });
    if(columnNames != ""){
        columnNames = columnNames.substring(0, columnNames.length-3);
    }

    //獲取表格所在頁面的菜單名,為了生成導出報表的文件名
    var fileName = "";
    var labelledby = $("#gview_" + gridId).parents('div.ui-tabs-panel').attr('aria-labelledby');
    if(labelledby){
        fileName = $('#'+labelledby).text();
    }
    if(fileName == ""){
        fileName = "報表";
    }
    try {
        $('#loading-msk').show().find('span').html('正在下載...');
        getDownLoadStatu();
        
        //表頭信息
        if($("#" + formId).find('input[name="excel_mergedRegions"]').length == 0){
            $("#" + formId).append('<input name="excel_mergedRegions" type="hidden"/>');
        }
        $("#" + formId).find("input[name='excel_mergedRegions']").val(mergedRegions);

        //數據信息
        if($("#" + formId).find('input[name="excel_columnNames"]').length == 0){
            $("#" + formId).append('<input name="excel_columnNames" type="hidden"/>');
        }
        $("#" + formId).find("input[name='excel_columnNames']").val(columnNames);
        
        //報表信息
        if($("#" + formId).find('input[name="excel_fileName"]').length == 0){
            $("#" + formId).append('<input name="excel_fileName" type="hidden"/>');
        }
        $("#" + formId).find("input[name='excel_fileName']").val(fileName);

        
        if($("#" + formId).find('input[name="gridParam"]').length == 0){
            $("#" + formId).append('<input name="gridParam" type="hidden"/>');
        }
        
        var $grid    = $('#' + gridId + '');
        var postData = $grid.jqGrid("getGridParam", "postData");

        $.extend(postData, {rpt_parameters:$('#' + formId).serializeJson()});

        $("#" + formId).find("input[name='gridParam']").val(JSON.stringify(postData));
        $("#" + formId).attr("action", downloadReportUrl).submit();
    } catch(e) {
        $('#loading-msk').hide();
        showAlert("報表下載出錯,請聯系系統管理員!", "信 息");
    } finally {
    //    $("#" + formId).attr("action", "#");
        $("#" + formId).find("input[name='gridParam']").val("");
    }
}


2、后台處理:

 獲取表格屬性參數

//獲取前端傳遞的表格屬性參數
String mergedRegion = p.getParameters().get("excel_mergedRegions");
String columnNames = p.getParameters().get("excel_columnNames");
String fileName = p.getParameters().get("excel_fileName");


動態生成多行表頭

/**
     * 根據poi導出excel,並根據頁面自動創建表頭信息 
     * @param mergedRegion 表頭格式信息
     * @param columnNames 字段信息
     * @param fileName 報表名
     * @return
     */
    public static XSSFWorkbook createWorkBook(String mergedRegion, String columnNames, String fileName) {
        // 創建新的Excel 工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 設置字體
        XSSFFont font = workbook.createFont();
        font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
        font.setFontHeightInPoints((short) 14);

        // 設置樣式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setFont(font);
        cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);
        cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);

        XSSFCellStyle cellLeftStyle = workbook.createCellStyle();
        cellLeftStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        cellLeftStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);

        XSSFCellStyle cellRightStyle = workbook.createCellStyle();
        cellRightStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        cellRightStyle.setAlignment(XSSFCellStyle.ALIGN_RIGHT);

        XSSFCellStyle cs = workbook.createCellStyle();
        XSSFFont f = workbook.createFont();
        f.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
        f.setFontHeightInPoints((short) 10);
        cs.setFont(f);
        cs.setAlignment(CellStyle.ALIGN_CENTER);
        cs.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        cs.setWrapText(true);

        //獲取數據行的列數
        int length = columnNames.split("\\^\\_\\^").length;

        // 第一行
        // 在索引0的位置創建行(最頂端的行)
        XSSFSheet sheet = workbook.createSheet(fileName);
        XSSFRow row = sheet.createRow(0);
        CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, length - 1);
        sheet.addMergedRegion(cellRangeAddress);
        // 在索引0的位置創建單元格(左上端)
        XSSFCell cell = row.createCell(0);
        // 定義單元格為字符串類型
        cell.setCellType(XSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(cellStyle);
        // 在單元格中輸入一些內容
        cell.setCellValue(fileName + "報表");

        // 第二行
        row = sheet.createRow(1);
        cellRangeAddress = new CellRangeAddress(1, 1, 0, length - 1);
        sheet.addMergedRegion(cellRangeAddress);
        cell = row.createCell(0);
        cell.setCellStyle(cellRightStyle);
        cell.setCellValue("制表時間:"+ new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date()));

        // 處理表頭,第三行開始
        String[] mergedRegions = mergedRegion.split(";");
        //創建一個虛擬表頭,並使用false標識這個單元格沒有被占用
        List<Map<Integer, Boolean>> headerLists = new ArrayList<Map<Integer, Boolean>>();
        for (int i = 0; i <= mergedRegions.length + 1; i++) {
            Map<Integer, Boolean> headerMap = new HashMap<Integer, Boolean>();
            for (int j = 0; j < length; j++) {
                headerMap.put(j, false);
                if (i == 0) {
                    sheet.setColumnWidth(j, (short) (16 * 256));
                }
            }
            headerLists.add(headerMap);
        }
        for (int i = 0; i < mergedRegions.length; i++) {
            String mergedRegionss = mergedRegions[i];
            int x = 2 + i;
            int y = 2 + i;
            int m = 0;
            int n = 0;
            row = sheet.createRow(2 + i);
            row.setHeight((short) (2 * 256));
            String[] _mergedRegionss = mergedRegionss.split(":");
            for (int j = 0; j < _mergedRegionss.length; j++) {
                String mergedRegionsss = _mergedRegionss[j];
                String[] _mergedRegionsss = mergedRegionsss.split(",");
                //獲取最小行中未被占用的單元格
                List<Integer> cellNum = new ArrayList<Integer>();
                for (int mm = 0; mm < headerLists.size(); mm++) {
                    Map<Integer, Boolean> headerMap = headerLists.get(mm);
                    for (Integer key : headerLists.get(mm).keySet()) {
                        if (!headerMap.get(key)) {
                            cellNum.add(key);
                        }
                    }
                    if (cellNum.size() > 0) {
                        break;
                    }
                }
                Collections.sort(cellNum);
                m = cellNum.get(0);

                int _y = y + (Integer.parseInt(_mergedRegionsss[1])) - 1;
                if (Integer.parseInt(_mergedRegionsss[1]) == 0) {
                    _y = y;
                }

                n = n + (Integer.parseInt(_mergedRegionsss[2]));
                if (Integer.parseInt(_mergedRegionsss[2]) == 0) {
                    n = m;
                }

                // String cra = x + ", " + _y + ", " + m + ", " + n;
                for (int t = x - 2; t <= _y - 2; t++) {
                    for (int k = m; k <= n; k++) {
                        headerLists.get(t).put(k, true);
                    }
                }
                cellRangeAddress = new CellRangeAddress(x, _y, m, n);
                sheet.addMergedRegion(cellRangeAddress);
                cell = row.createCell(m);
                cell.setCellStyle(cs);
                cell.setCellValue(_mergedRegionsss[0]);
                m = n + 1;
            }
        }
        
        return workbook;
    }


最后就是數據和行格式的填充、導出流的處理。

 

  


免責聲明!

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



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