目录
需求背景:
之前的导出都是单行表头+数据,所以使用easyexcel框架自带的方法两行代码就搞定了,需求变动之后要导出复杂的表格,更贴合实际运用点,针对客户需求,我们需要重新写导出方法
预期效果:
分析需求,提取思路:
针对复杂的表格还是选取最原始的方法,使用poi创建表格,
java
// 创建一个新的 Excel 工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建一个工作表
XSSFSheet sheet = workbook.createSheet("sheet1");
需要导出的excel分为以下几部分:
1、表头
①附件行(附件1)
创建行使用:
java
XSSFRow fileRow = sheet.createRow(0);
在该行创建单元格(列):
java
XSSFCell fileCell = fileRow.createCell(0);
②标题行(xx市稻谷生产者补贴分户登记清册)
③表格样式行
④盖章行
⑤数据表头行(序号、姓名、身份证、银行账户等)
2、数据
这块数据直接从数据库中查出来填充就好了
3、合计行
4、表尾
重难点(需要考虑到的知识点):
1、跨列合并
java
// 合并单元格
// 合并第一行的前八列
// 起始行、截至行、起始列、截至列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(1, 1, 0, 8));
2、字体样式
上面讲了创建行、在行上创建单元格(列),样式是设置在单元格上的:
java
// 创建大标题单元格样式
XSSFCellStyle cellStyle = workbook.createCellStyle();
XSSFFont font = workbook.createFont();
font.setBold(true); // 加粗字体
font.setFontName("仿宋_GB2312");
font.setFontHeightInPoints((short) 18); // 设置字体大小为三号(16pt)
cellStyle.setFont(font);
// 设置为单元格样式
cell.setCellStyle(cellStyle);
3、行列宽高
设置行高:
java
XSSFRow blankRow = sheet.createRow(3);
blankRow.setHeightInPoints(25.5f);
设置列宽:
java
sheet.setColumnWidth(0, 6 * 256); // 第1列宽度
4、单元格水平居中、垂直居中
居中是在cellstyle上设置的:
java
// 设置单元格居中对齐
cellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
5、表格中格子的边框
java
// 设置边框
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
6、文字自动换行
java
cellStyle.setWrapText(true);
7、表尾的行数是表头行数加数据体行数加合计行行数
完整代码:
java
@Override
public void export(HttpServletResponse response, ApplyQueryVO query) {
// 创建一个新的 Excel 工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
// 创建一个工作表
XSSFSheet sheet = workbook.createSheet("sheet1");
// 设置列宽
sheet.setColumnWidth(0, 6 * 256); // 第1列宽度
sheet.setColumnWidth(1, 20 * 256); // 第1列宽度
sheet.setColumnWidth(2, 20 * 256); // 第1列宽度
sheet.setColumnWidth(3, 22 * 256); // 第1列宽度
sheet.setColumnWidth(4, 10 * 256); // 第1列宽度
sheet.setColumnWidth(5, 10 * 256); // 第1列宽度
sheet.setColumnWidth(6, 12 * 256); // 第1列宽度
sheet.setColumnWidth(7, 13 * 256); // 第1列宽度
sheet.setColumnWidth(8, 14 * 256); // 第1列宽度
// 附件1
// 创建字体
Font font = workbook.createFont();
font.setFontName("黑体"); // 设置字体为黑体
font.setFontHeightInPoints((short) 12); // 设置字体大小
// 创建单元格样式并设置字体
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(font);
XSSFRow fileRow = sheet.createRow(0);
XSSFCell fileCell = fileRow.createCell(0);
fileCell.setCellValue("附件1");
fileCell.setCellStyle(cellStyle);
// 设置大表头标题
XSSFRow bigTitleRow = sheet.createRow(1);
bigTitleRow.setHeightInPoints(33.75f); // 增加行高以便容纳大标题
// 创建大标题单元格样式
XSSFCellStyle bigTitleCellStyle = workbook.createCellStyle();
XSSFFont bigTitleFont = workbook.createFont();
bigTitleFont.setBold(true); // 加粗字体
bigTitleFont.setFontName("仿宋_GB2312");
bigTitleFont.setFontHeightInPoints((short) 18); // 设置字体大小为三号(16pt)
bigTitleCellStyle.setFont(bigTitleFont);
// 设置单元格居中对齐
bigTitleCellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
bigTitleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(1, 1, 0, 8)); // 合并第一行的前三列
// 大标题单元格内容
XSSFCell bigTitleCell = bigTitleRow.createCell(0);
bigTitleCell.setCellValue("xxx市稻谷生产者补贴分户登记清册");
if (Func.isNotBlank(query.getYear())) {
bigTitleCell.setCellValue("xxx市稻谷生产者补贴分户登记清册" + "(" + query.getYear() + "年)");
}
bigTitleCell.setCellStyle(bigTitleCellStyle);
// 样表格式
XSSFRow styleRow = sheet.createRow(2);
XSSFCell styleCell = styleRow.createCell(0);
styleCell.setCellValue("(样表格式)");
XSSFCellStyle styleCellStyle = workbook.createCellStyle();
styleCellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
styleCell.setCellStyle(styleCellStyle);
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(2, 2, 0, 8)); // 合并第一行的前三列
// 设置普通文字行
XSSFRow blankRow = sheet.createRow(3);
blankRow.setHeightInPoints(25.5f);
XSSFCell blankCell = blankRow.createCell(0);
// 设置普通文字行
XSSFRow textRow = sheet.createRow(4);
XSSFCell textCell = textRow.createCell(0);
textCell.setCellValue("____镇(街道) ____村(社区)(盖章) 镇人民政府(街道办事处)(盖章)");
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(4, 4, 0, 8)); // 合并第一行的前三列
// 创建数据表头
XSSFRow headerRow = sheet.createRow(5);
// 设置行高为42.75磅
headerRow.setHeightInPoints(42.75f);
XSSFCellStyle titleCellStyle = workbook.createCellStyle();
titleCellStyle.setWrapText(true);
// 设置单元格居中对齐
titleCellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
// 设置边框
titleCellStyle.setBorderTop(BorderStyle.THIN);
titleCellStyle.setBorderBottom(BorderStyle.THIN);
titleCellStyle.setBorderLeft(BorderStyle.THIN);
titleCellStyle.setBorderRight(BorderStyle.THIN);
XSSFFont titleFont = workbook.createFont();
titleFont.setBold(true); // 加粗字体
titleFont.setFontHeightInPoints((short) 12); // 设置字体大小为三号(16pt)
titleCellStyle.setFont(titleFont);
XSSFCell cell0 = headerRow.createCell(0);
cell0.setCellStyle(titleCellStyle);
XSSFCell cell1 = headerRow.createCell(1);
cell1.setCellStyle(titleCellStyle);
XSSFCell cell2 = headerRow.createCell(2);
cell2.setCellStyle(titleCellStyle);
XSSFCell cell3 = headerRow.createCell(3);
cell3.setCellStyle(titleCellStyle);
XSSFCell cell4 = headerRow.createCell(4);
cell4.setCellStyle(titleCellStyle);
XSSFCell cell5 = headerRow.createCell(5);
cell5.setCellStyle(titleCellStyle);
XSSFCell cell6 = headerRow.createCell(6);
cell6.setCellStyle(titleCellStyle);
XSSFCell cell7 = headerRow.createCell(7);
cell7.setCellStyle(titleCellStyle);
XSSFCell cell8 = headerRow.createCell(8);
cell8.setCellStyle(titleCellStyle);
// 创建样式并启用换行
cell0.setCellValue("序号");
cell1.setCellValue("姓名(单位)");
cell2.setCellValue("身份证号码");
cell3.setCellValue("银行账号\n" +
"(一折通号、三代社保卡号、对公账号)");
cell4.setCellValue("补贴面积(亩)");
cell5.setCellValue("补贴标准(元/亩)");
cell6.setCellValue("补贴金额(元)");
cell7.setCellValue("联系电话");
cell8.setCellValue("户主签名");
// 一折通号(对公账号)
//补贴面积(亩)
// 补贴标准(元/亩)
// 补贴金额(元)
// 联系电话
// 添加一些示例数据
List<RiceSubsidyApplyExcel> listvo = this.listExcel(query);
XSSFCellStyle bodyCellStyle = workbook.createCellStyle();
bodyCellStyle.setWrapText(true);
XSSFFont bodyFont = workbook.createFont();
bodyFont.setFontName("宋体");
bodyFont.setFontHeightInPoints((short) 10); // 设置字体大小为三号(16pt)
bodyCellStyle.setFont(bodyFont);
// 设置边框
bodyCellStyle.setBorderTop(BorderStyle.THIN);
bodyCellStyle.setBorderBottom(BorderStyle.THIN);
bodyCellStyle.setBorderLeft(BorderStyle.THIN);
bodyCellStyle.setBorderRight(BorderStyle.THIN);
bodyCellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
bodyCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
for (int i = 0; i < listvo.size(); i++) {
XSSFRow dataRow = sheet.createRow(6 + i);
// 设置行高为33.75磅
dataRow.setHeightInPoints(33.75f); // 行高
// dataRow.setRowStyle(bodyCellStyle);
XSSFCell cell00 = dataRow.createCell(0);
cell00.setCellStyle(bodyCellStyle);
cell00.setCellValue(listvo.get(i).getRowNum());
XSSFCell cell01 = dataRow.createCell(1);
cell01.setCellStyle(bodyCellStyle);
cell01.setCellValue(listvo.get(i).getFarmerName());
XSSFCell cell02 = dataRow.createCell(2);
cell02.setCellStyle(bodyCellStyle);
cell02.setCellValue(listvo.get(i).getIdCardNo());
XSSFCell cell03 = dataRow.createCell(3);
cell03.setCellStyle(bodyCellStyle);
cell03.setCellValue(listvo.get(i).getSubsidyAccount());
XSSFCell cell04 = dataRow.createCell(4);
cell04.setCellStyle(bodyCellStyle);
cell04.setCellValue(listvo.get(i).getSubsidyArea().toString());
XSSFCell cell05 = dataRow.createCell(5);
cell05.setCellStyle(bodyCellStyle);
String standard = listvo.get(i).getSubsidyStandard();
standard = getRealStandard(standard);
cell05.setCellValue(standard);
XSSFCell cell06 = dataRow.createCell(6);
cell06.setCellStyle(bodyCellStyle);
cell06.setCellValue(listvo.get(i).getSubsidyPrice().toString());
XSSFCell cell07 = dataRow.createCell(7);
cell07.setCellStyle(bodyCellStyle);
cell07.setCellValue(listvo.get(i).getContactPhone());
XSSFCell cell08 = dataRow.createCell(8);
cell08.setCellStyle(bodyCellStyle);
cell08.setCellValue("");
}
// 调整列宽以适应内容
/*for (int i = 0; i < 8; i++) {
sheet.autoSizeColumn(i);
}*/
// 设置表尾
// 合计
XSSFRow countRow = sheet.createRow(6 + listvo.size());
countRow.setHeightInPoints(30);
XSSFCell countCell = countRow.createCell(0);
countCell.setCellValue("合计");
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(6 + listvo.size(), 6 + listvo.size(), 0, 3)); // 合并第一行的前三列
countCell.setCellStyle(bodyCellStyle);
XSSFCell countCell1 = countRow.createCell(1);
countCell1.setCellStyle(bodyCellStyle);
XSSFCell countCell2 = countRow.createCell(2);
countCell2.setCellStyle(bodyCellStyle);
XSSFCell countCell3 = countRow.createCell(3);
countCell3.setCellStyle(bodyCellStyle);
// 补贴面积合计
XSSFCell areaCell = countRow.createCell(4);
areaCell.setCellValue(listvo.stream().map(RiceSubsidyApplyExcel::getSubsidyArea).reduce(BigDecimal.ZERO, BigDecimal::add).toString());
areaCell.setCellStyle(bodyCellStyle);
XSSFCell countCell5 = countRow.createCell(5);
countCell5.setCellStyle(bodyCellStyle);
// 补贴金额合计
XSSFCell priceCell = countRow.createCell(6);
priceCell.setCellValue(listvo.stream().map(RiceSubsidyApplyExcel::getSubsidyPrice).reduce(BigDecimal.ZERO, BigDecimal::add).toString());
priceCell.setCellStyle(bodyCellStyle);
XSSFCell countCell7 = countRow.createCell(7);
countCell7.setCellStyle(bodyCellStyle);
XSSFCell countCell8 = countRow.createCell(8);
countCell8.setCellStyle(bodyCellStyle);
XSSFRow tailRow = sheet.createRow(8 + listvo.size());
tailRow.setHeightInPoints(30f);
XSSFCell tailCell = tailRow.createCell(0);
tailCell.setCellValue("村民委员会(社区)主任(签名): 数据采集人:(签名):");
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(8 + listvo.size(), 8 + listvo.size(), 0, 8)); // 合并第一行的前三列
// 设置表尾
XSSFRow tailRow2 = sheet.createRow(8 + listvo.size() + 1);
XSSFCell tailCell2 = tailRow2.createCell(0);
tailCell2.setCellValue("市级举报电话:市财政xxx 农业农村局xx 镇(街道)举报电话:xxx");
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(8 + listvo.size() + 1, 8 + listvo.size() + 1, 0, 8)); // 合并第一行的前三列
// 设置表尾
XSSFRow tailRow3 = sheet.createRow(8 + listvo.size() + 2);
XSSFCell tailCell3 = tailRow3.createCell(0);
tailCell3.setCellValue("注:1.此表由村民委员会(社区)填报,镇人民政府(街道办事处)加盖公章后在村(社区)公示。公示无异议后镇(街道)填报附件2,连同此表一并上报市财政、市农业农村局,并由村民委员会(社区)、镇人民政府(街道办事处)、镇(街道)财政所分别留档。");
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(8 + listvo.size() + 2, 8 + listvo.size() + 2, 0, 8)); // 合并第一行的前三列
// 2.补贴面积保留2位小数。
// 设置表尾
XSSFRow tailRow4 = sheet.createRow(8 + listvo.size() + 3);
XSSFCell tailCell4 = tailRow4.createCell(0);
tailCell4.setCellValue("2.补贴面积保留2位小数。");
// 合并单元格以使大标题横跨所有列
sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(8 + listvo.size() + 3, 8 + listvo.size() + 3, 0, 8)); // 合并第一行的前三列
// 设置响应类型和头部
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=稻谷补贴.xlsx");
// 将工作簿写入响应输出流
try (OutputStream out = response.getOutputStream()) {
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭工作簿
try {
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}