最近公司的项目需要添加导出报表的功能,报表都是多行表头,最初是使用事先创建模板然后导出的方式,但是随着报表数量的增加和模板表头的变动,这种导出方案就不合适了。因此尝试使用了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 HSSFWorkbook createWorkBook(String mergedRegion, String columnNames, String fileName) { // 创建新的Excel 工作簿 HSSFWorkbook workbook = new HSSFWorkbook(); // 设置字体 HSSFFont font = workbook.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); font.setFontHeightInPoints((short) 14); // 设置样式 HSSFCellStyle cellStyle = workbook.createCellStyle(); cellStyle.setFont(font); cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); HSSFCellStyle cellLeftStyle = workbook.createCellStyle(); cellLeftStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellLeftStyle.setAlignment(HSSFCellStyle.ALIGN_LEFT); HSSFCellStyle cellRightStyle = workbook.createCellStyle(); cellRightStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); cellRightStyle.setAlignment(HSSFCellStyle.ALIGN_RIGHT); HSSFCellStyle cs = workbook.createCellStyle(); HSSFFont f = workbook.createFont(); f.setBoldweight(HSSFFont.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的位置创建行(最顶端的行) HSSFSheet sheet = workbook.createSheet(fileName); HSSFRow row = sheet.createRow(0); CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, length - 1); sheet.addMergedRegion(cellRangeAddress); // 在索引0的位置创建单元格(左上端) HSSFCell cell = row.createCell(0); // 定义单元格为字符串类型 cell.setCellType(HSSFCell.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; }
最后就是数据和行格式的填充、导出流的处理。
时间: 2024-11-10 15:15:06