POI实现导出复杂Excel(动态行,复杂单元格,水印,Excel转换为PDF)。

您所在的位置:网站首页 pdf文档制作目录 POI实现导出复杂Excel(动态行,复杂单元格,水印,Excel转换为PDF)。

POI实现导出复杂Excel(动态行,复杂单元格,水印,Excel转换为PDF)。

2023-02-08 20:21| 来源: 网络整理| 查看: 265

 

一、POI 表格框架

1.POI : POI提供API给Java程序对Microsoft Office格式档案读和写的功能

2.HSSF:Horrible SpreadSheet Format,为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”

3.POI 文档结构类

 HSSFWorkbook 文档对象,HSSFSheet  页,HSSFRow 行,HSSFCell 单元格,HSSFFont 字体, HSSFName 名称,HSSFDataFormat 日期格式

 HSSFHeader 表头,HSSFFooter 表尾,HSSFCellStyle 单元格样式,HSSFDateUtil 日期,HSSFPrintSetup 打印, HSSFErrorConstants 错误信息表

二、POI  文件类型

         类                                      文件                                                                         jar

     HSSF -- 提供读写Microsoft  Excel  XLS格式档案的功能                                 poi   XSSF -- 提供读写Microsoft  Excel  OOXML  XLSX格式档案的功能              poi--ooxml   HWPF -- 提供读写Microsoft  Word  DOC格式档案的功能        poi-scratchpad   HSLF -- 提供读写Microsoft  PowerPoint格式档案的功能         poi-scratchpad   HDGF -- 提供读Microsoft  Visio格式档案的功能            poi-scratchpad   HPBF -- 提供读Microsoft  Publisher格式档案的功能          poi-scratchpad   HSMF -- 提供读Microsoft  Outlook格式档案的功能            poi-scratchpad

 原Excel模板   脱产培训与网络培训两个列表不相同,并且为动态,数据条数未知,所以要动态添加数据与动态合并单元格。

 

需求如此,多以抛弃使用模板填充方式,改为从第一行构建到最后一行,并且将excel添加水印转换成pdf。

POI  Jar包  版本之间差异看官网,尽量用新的

org.apache.poi poi 3.15 org.apache.poi poi-ooxml 3.15 org.apache.poi poi-ooxml-schemas 3.15

PDF转换Jar包 了解工具直接搜索jar包名称就行

com.bc.ext spire.xls.free 5.1.0

业务代码,具体行都有注释。

public File createExcel(HashMap resultMap, List actualList, List netWorkList, HttpServletResponse response){ /** 第一步,创建一个Workbook,对应一个Excel文件 */ XSSFWorkbook wb = new XSSFWorkbook(); /** 第二步,在Workbook中添加一个sheet,对应Excel文件中的sheet */ XSSFSheet sheet = wb.createSheet("sheet1"); //设置每个列有多宽 100为单位好计算 sheet.setColumnWidth(0,100 * 12); sheet.setColumnWidth(1,100 * 19); sheet.setColumnWidth(2,100 * 38); sheet.setColumnWidth(3,100 * 38); sheet.setColumnWidth(4,100 * 38); sheet.setColumnWidth(5,100 * 38); sheet.setColumnWidth(6,100 * 38); /** 第三步,设置样式以及字体样式*/ XSSFCellStyle titleStyle = createTitleCellStyle(wb); XSSFCellStyle headerStyle = createHeadCellStyle(wb); XSSFCellStyle contentStyle = createContentCellStyle(wb); /** 第四步,创建标题 ,合并标题单元格 */ // 行号 int rowNum = 0; // 创建第一页的第一行,索引从0开始 XSSFRow row0 = sheet.createRow(rowNum++); row0.setHeight((short) 800);// 设置行高 String title = "公务员培训情况备案表"; XSSFCell c00 = row0.createCell(0); c00.setCellValue(title); c00.setCellStyle(titleStyle); // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 6));//标题合并单元格操作,6为总列数 // 第二行 XSSFRow row1 = sheet.createRow(rowNum++); row1.setHeight((short) 700); String[] row_first = {"年度","", "", "", "", "", ""}; for (int i = 0; i < row_first.length; i++) { XSSFCell tempCell = row1.createCell(i); tempCell.setCellStyle(headerStyle); if (i == 0) { tempCell.setCellValue(Convert.toStr(resultMap.get("year")) + row_first[i]); }else { tempCell.setCellValue(row_first[i]); } } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 6));//标题合并单元格操作,7为总列数 //第三行 XSSFRow row2 = sheet.createRow(rowNum++); row2.setHeight((short) 700); String[] row_2_str = {"姓名","", Convert.toStr(resultMap.get("name")), "性别", Convert.toStr(resultMap.get("sex")), "政治面貌", Convert.toStr(resultMap.get("politicVal"))}; for (int i = 0; i < row_2_str.length; i++) { XSSFCell tempCell = row2.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_2_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, 1));//标题合并单元格操作,7为总列数 //第四行 XSSFRow row3 = sheet.createRow(rowNum++); row3.setHeight((short) 700); String[] row_3_str = {"学历","",Convert.toStr(resultMap.get("educationVal")), "行政级别",Convert.toStr(resultMap.get("administrationVal")), "",""}; for (int i = 0; i < row_3_str.length; i++) { XSSFCell tempCell = row3.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_3_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(3, 3, 0, 1));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(3, 3, 4, 6));//标题合并单元格操作,7为总列数 //第五行 XSSFRow row4 = sheet.createRow(rowNum++); row4.setHeight((short) 700); String[] row_4_str = {"单位名称","",Convert.toStr(resultMap.get("companyName")), "内设机构",Convert.toStr(resultMap.get("mechanism")), "职务",Convert.toStr(resultMap.get("studentDuties"))}; for (int i = 0; i < row_4_str.length; i++) { XSSFCell tempCell = row4.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_4_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(4, 4, 0, 1));//标题合并单元格操作,7为总列数 //第六行 XSSFRow row5 = sheet.createRow(rowNum++); row5.setHeight((short) 700); String[] row_5_str = {"脱产培训","培训班名称","", "培训时间","", "主办单位","学分"}; for (int i = 0; i < row_5_str.length; i++) { XSSFCell tempCell = row5.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_5_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(5, 5, 1, 2));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(5, 5, 3, 4));//标题合并单元格操作,7为总列数 //第六行带的数据 循环插入 for (Map actuaLData : actualList) { XSSFRow tempRow = sheet.createRow(rowNum++); tempRow.setHeight((short) 700); // 循环单元格填入数据 for (int j = 0; j < 7; j++) { XSSFCell tempCell = tempRow.createCell(j); tempCell.setCellStyle(contentStyle); String tempValue; if (j == 0) { tempValue = ""; } else if (j == 1) { tempValue = Convert.toStr(actuaLData.get("actualName")); } else if (j == 2) { tempValue = ""; } else if (j == 3) { tempValue = Convert.toStr(actuaLData.get("actualTime")); } else if (j == 4) { tempValue = ""; } else if (j == 5) { tempValue = Convert.toStr(actuaLData.get("actualOrgan")); } else { tempValue = Convert.toStr(actuaLData.get("actualPoint")); } tempCell.setCellValue(tempValue); } sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 1, 2));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 3, 4));//标题合并单元格操作,7为总列数 } //培训班小计行 XSSFRow rowxj = sheet.createRow(rowNum++); rowxj.setHeight((short) 700); String[] row_xj_str = {"","小计","", "","", "",Convert.toStr(resultMap.get("totalActualPoint"))}; for (int i = 0; i < row_5_str.length; i++) { XSSFCell tempCell = rowxj.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_xj_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 1, 5));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(5, rowNum - 1, 0, 0));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //网络培训标题行 XSSFRow rowNetworkTitle = sheet.createRow(rowNum++); rowNetworkTitle.setHeight((short) 700); String[] row_networkTitle_str = {"网络培训","所学课程类别","", "","", "课程数","学分"}; for (int i = 0; i < row_networkTitle_str.length; i++) { XSSFCell tempCell = rowNetworkTitle.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_networkTitle_str[i]); } try { // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 1, 4));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //做标记,动态计算坐标合并 int startIndex = rowNum - 1; //网络培训list数据填充 for (Map networkData : netWorkList) { XSSFRow tempRow = sheet.createRow(rowNum++); tempRow.setHeight((short) 700); // 循环单元格填入数据 for (int j = 0; j < 7; j++) { XSSFCell tempCell = tempRow.createCell(j); tempCell.setCellStyle(contentStyle); String tempValue; if (j == 0) { tempValue = ""; } else if (j == 1) { tempValue = Convert.toStr(networkData.get("name")); } else if (j == 2) { tempValue = ""; } else if (j == 3) { tempValue = ""; } else if (j == 4) { tempValue = ""; } else if (j == 5) { tempValue = Convert.toStr(networkData.get("networkCount")); } else { tempValue = Convert.toStr(networkData.get("point")); } tempCell.setCellValue(tempValue); } sheet.addMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 1, 4));//标题合并单元格操作,7为总列数 } //网络培训专题班行 XSSFRow rowNetworkZtb = sheet.createRow(rowNum++); rowNetworkZtb.setHeight((short) 700); String[] row_NetworkZtb_str = {"","专题班","", "","", Convert.toStr(resultMap.get("lessonCount")),Convert.toStr(resultMap.get("pointSum"))}; for (int i = 0; i < row_NetworkZtb_str.length; i++) { XSSFCell tempCell = rowNetworkZtb.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_NetworkZtb_str[i]); } //合并 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 1, 4));//标题合并单元格操作,7为总列数 } catch (Exception e){ } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 //网络培训小计行 XSSFRow rowNetworkXj = sheet.createRow(rowNum++); rowNetworkXj.setHeight((short) 700); String[] row_NetworkXj_str = {"","小计","", "","", Convert.toStr(resultMap.get("networkCount")),Convert.toStr(resultMap.get("networkPoint"))}; for (int i = 0; i < row_NetworkXj_str.length; i++) { XSSFCell tempCell = rowNetworkXj.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_NetworkXj_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 1, 4));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(startIndex, rowNum - 1, 0, 0));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //年度完成专题班行 XSSFRow rowYearNetwork = sheet.createRow(rowNum++); rowYearNetwork.setHeight((short) 700); String yearNetwork = Convert.toStr(resultMap.get("yearNetwork")); String[] row_YearNetwork_str; if (yearNetwork == null){ row_YearNetwork_str = new String[]{"年度完成专题班", "", "", "", "", "个", ""}; }else { row_YearNetwork_str = new String[]{"年度完成专题班", "", "", "", "", Convert.toStr(resultMap.get("yearNetworkCount")) + "个", ""}; } for (int i = 0; i < row_YearNetwork_str.length; i++) { XSSFCell tempCell = rowYearNetwork.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_YearNetwork_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 0, 4));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 5, 6));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //学分合计行 XSSFRow rowPointCount = sheet.createRow(rowNum++); rowPointCount.setHeight((short) 700); String[] row_PointCount_str = new String[]{"学分合计", "", "", "", "", Convert.toStr(resultMap.get("yearPoint")), ""}; for (int i = 0; i < row_PointCount_str.length; i++) { XSSFCell tempCell = rowPointCount.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_PointCount_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 0, 4));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 5, 6));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //excel底部两行 XSSFRow rowUnder2 = sheet.createRow(rowNum++); rowUnder2.setHeight((short) 900); String[] row_Under2_str = new String[]{"主管部门意见", "", "", Convert.toStr(resultMap.get("is")), "", "", ""}; for (int i = 0; i < row_Under2_str.length; i++) { XSSFCell tempCell = rowUnder2.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_Under2_str[i]); } try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 3, 6));//标题合并单元格操作,7为总列数 } catch (Exception e){ } XSSFRow rowUnder1 = sheet.createRow(rowNum++); rowUnder1.setHeight((short) 800); String[] row_Under1_str = new String[]{"", "", "", "", "", Convert.toStr(resultMap.get("pdfTime")), ""}; for (int i = 0; i < row_Under1_str.length; i++) { XSSFCell tempCell = rowUnder1.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_Under1_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 3, 4));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 5, 6));//标题合并单元格操作,7为总列数 sheet.addMergedRegion(new CellRangeAddress(rowNum-2, rowNum - 1, 0, 2));//标题合并单元格操作,7为总列数 } catch (Exception e){ } //备注行 XSSFRow rowremarks = sheet.createRow(rowNum++); rowremarks.setHeight((short) 1300); String[] row_remarks_str = new String[]{"注:根据《干部教育培训工作条例》,干部参加教育培训,每年累计不少于12天或者90学时,因故未按规定参加教育培训或者未达到教育培训要求的,应当及时补训。干部教育培训考核不合格的,年度考核不得确定为优秀等次。", "", "", "", "","", ""}; for (int i = 0; i < row_remarks_str.length; i++) { XSSFCell tempCell = rowremarks.createCell(i); tempCell.setCellStyle(headerStyle); tempCell.setCellValue(row_remarks_str[i]); } // 合并单元格,参数依次为起始行,结束行,起始列,结束列 (索引0开始) //此处没有任何问题,程序不让运行,就给捕获了,不用操作别的,之后的代码也是一样 try { sheet.addMergedRegion(new CellRangeAddress(rowNum-1, rowNum - 1, 0, 6));//标题合并单元格操作,7为总列数 } catch (Exception e){ } try { //添加图片水印 FileOutputStream fileOut = null; BufferedImage bufferImg = null; ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); //加载图片 bufferImg = ImageIO.read(new File("src/main/resources/static/template/peqk.png")); ImageIO.write(bufferImg, "png", byteArrayOut); XSSFDrawing patriarch = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0,5, rowNum-3, 7,rowNum-1 ); //插入图片 1 patriarch.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG)); // // 输出文件 // wb.write(fileOut); } catch (Exception e){ e.printStackTrace(); } File fileExcel = xssfWorkbookToFile(wb, "src/main/resources/static/template/peqk.xlsx"); ExcelToPdf excelToPdf = new ExcelToPdf(); excelToPdf.sheetToPdf("src/main/resources/static/template/peqk.xlsx", "src/main/resources/static/template/peqk.pdf"); File filePdf = new File("src/main/resources/static/template/peqk.pdf"); ServletOutputStream out = null; try{ out = response.getOutputStream(); /** 导出pdf文件流 */ response.setCharacterEncoding("UTF-8"); response.setContentType("application/pdf"); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline; filename="+ URLEncoder.encode("公务员培训情况备案表.pdf","UTF-8")); FileInputStream inputStream = new FileInputStream(filePdf); // 读取文件流 int len = 0; byte[] buffer = new byte[1024 * 10]; while ((len = inputStream.read(buffer)) != -1) { out.write(buffer, 0, len); } out.close(); }catch (Exception e){ e.printStackTrace(); }finally { fileExcel.delete(); filePdf.delete(); } return null; }

 下面是工具方法,样式为自定义,如果想添加表格背景颜色,字体,都是可以定义的,具体查询poi的api

/** * 讲ex对象转换成文件 * @param wb * @param name * @return */ public static File xssfWorkbookToFile(XSSFWorkbook wb, String name) { File toFile = new File(name); try { OutputStream os = new FileOutputStream(toFile); wb.write(os); os.close(); } catch (Exception e) { e.printStackTrace(); } return toFile; } /** * 创建标题样式 * @param wb * @return */ private static XSSFCellStyle createTitleCellStyle(XSSFWorkbook wb) { XSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER);//水平居中 cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直对齐 cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // cellStyle.setBorderBottom(BorderStyle.THIN); //下边框 // cellStyle.setBorderLeft(BorderStyle.THIN); //左边框 // cellStyle.setBorderRight(BorderStyle.THIN); //右边框 // cellStyle.setBorderTop(BorderStyle.THIN); //上边框 // cellStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());//背景颜色 XSSFFont headerFont1 = (XSSFFont) wb.createFont(); // 创建字体样式 // headerFont1.setBold(true); //字体加粗 headerFont1.setFontName("宋体"); // 设置字体类型 headerFont1.setFontHeightInPoints((short) 17); // 设置字体大小 cellStyle.setFont(headerFont1); // 为标题样式设置字体样式 return cellStyle; } /** * 创建表头样式 * @param wb * @return */ private static XSSFCellStyle createHeadCellStyle(XSSFWorkbook wb) { XSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setWrapText(true);// 设置自动换行 // cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景颜色 cellStyle.setAlignment(HorizontalAlignment.CENTER); //水平居中 cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //垂直对齐 cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setBottomBorderColor(IndexedColors.BLACK.index); cellStyle.setBorderBottom(BorderStyle.THIN); //下边框 cellStyle.setBorderLeft(BorderStyle.THIN); //左边框 cellStyle.setBorderRight(BorderStyle.THIN); //右边框 cellStyle.setBorderTop(BorderStyle.THIN); //上边框 XSSFFont headerFont = (XSSFFont) wb.createFont(); // 创建字体样式 // headerFont.setBold(true); //字体加粗 headerFont.setFontName("宋体"); // 设置字体类型 headerFont.setFontHeightInPoints((short) 16); // 设置字体大小 // cellStyle.setFont(headerFont); // 为标题样式设置字体样式 return cellStyle; } /** * 创建内容样式 * @param wb * @return */ private static XSSFCellStyle createContentCellStyle(XSSFWorkbook wb) { XSSFCellStyle cellStyle = wb.createCellStyle(); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中 cellStyle.setAlignment(HorizontalAlignment.CENTER);// 水平居中 cellStyle.setWrapText(true);// 设置自动换行 cellStyle.setBorderBottom(BorderStyle.THIN); //下边框 cellStyle.setBorderLeft(BorderStyle.THIN); //左边框 cellStyle.setBorderRight(BorderStyle.THIN); //右边框 cellStyle.setBorderTop(BorderStyle.THIN); //上边框 // 生成12号字体 XSSFFont font = wb.createFont(); font.setColor((short)8); font.setFontHeightInPoints((short) 12); cellStyle.setFont(font); return cellStyle; }

 最终结果为 pdf 向导出excel把转换pdf的语句删掉就可以了

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3