POI动态下载Excel模板案例

目录

一、简介

二、代码实现

三、总结


一、简介

最近项目中有个需求,需要根据后台配置的一些参数动态生成Excel导入模板,Excel表头是动态查询数据库获取的。下面具体看代码实现。

二、代码实现

(1). 控制层代码:

@ApiOperation(value = "下载测评项分数导入模板", notes = "下载测评项分数导入模板", httpMethod = "POST")
	@ApiImplicitParams({ @ApiImplicitParam(paramType = "body", name = "request", value = "参数", required = true, dataType = "HttpServletRequest"),
	        @ApiImplicitParam(paramType = "body", name = "response", value = "参数", required = true, dataType = "HttpServletResponse"), })
	@RequestMapping(value = "/exportDynamicExcelTemplate", method = RequestMethod.GET)
	public void exportDynamicExcelTemplate(HttpServletRequest request, HttpServletResponse response) {
		// 当前导入的环节ID
		String cphjid = request.getParameter("cphjid");
		// 1.创建Excel模板工作簿对象(动态组装表头、必填标识等)
		XSSFWorkbook xssfWorkbook = hjcpxqService.createXSSFWorkbook(cphjid);
		// 2.导出的Excel模板文件名称
		DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
		StringBuilder fileName = new StringBuilder("测评项分数导入模板表").append(dateFormat.format(new Date())).append(".xlsx");
		// 3.清空response
		response.reset();
		// 4.设置response的Header
		String excelFileName;
		OutputStream os = null;
		try {
			// 需要指定文件名的编码方式为ISO-8859-1,否则会出现文件名中的中文字符丢失的问题
			excelFileName = new String(fileName.toString().getBytes("gb2312"), "ISO-8859-1");
			response.addHeader("Content-Disposition", "attachment;filename=" + excelFileName);
			os = new BufferedOutputStream(response.getOutputStream());
			// 5.设置消息头内容格式,并指定编码格式
			response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
			// 6.将Excel写入到输出流中
			xssfWorkbook.write(os);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 7. 关闭文件流
			try {
				if (null != os) {
					os.flush();
					os.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

这里需要注意的地方:

【a】需要指定文件名的编码方式为ISO-8859-1,否则会出现文件名中的中文字符丢失的问题:
excelFileName = new String(fileName.toString().getBytes("gb2312"), "ISO-8859-1");

【b】注意这个是.xlsx后缀的Excel,  .xls的是application/vnd.ms-excel,.xlsx的如下所示:
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

(2). 业务层代码:

@Override
	public XSSFWorkbook createXSSFWorkbook(String cphjid) {
		/**
		 * 1.动态组装Excel表头列标题
		 */
		// 根据环节ID查询环节对应的导入模板信息
		List<Map<String, Object>> templateList = cpxMbdrbService.getImportTemplateByHjid(cphjid);
		List<Map<String, Object>> titleHeaders = new ArrayList<>();
		Map<String, Object> xhMap = new HashMap<>();
		Map<String, Object> xmMap = new HashMap<>();
		xhMap.put("TYPE", "FIXED");
		xhMap.put("VALUE", EXCEL_HEADER_XH);
		xmMap.put("TYPE", "FIXED");
		xmMap.put("VALUE", EXCEL_HEADER_NAME);
		titleHeaders.add(xmMap);
		titleHeaders.add(xhMap);
		if (CollectionUtils.isNotEmpty(templateList)) {
			HashMap<String, Object> cpxmcMap = null;
			for (Map<String, Object> map : templateList) {
				// 测评项名称
				String cpxmc = null != map.get("LABEL") ? map.get("LABEL").toString() : "";
				cpxmcMap = new HashMap<>();
				cpxmcMap.put("TYPE", "LABEL");
				cpxmcMap.put("VALUE", cpxmc);
				titleHeaders.add(cpxmcMap);
			}
		}

		/**
		 * 2.设置Excel工作簿信息、Excel样式等
		 */
		// 创建一个工作簿(Excel的文档对象)
		XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
		// 创建一个Sheet(Excel的表单)
		XSSFSheet xssfSheet = xssfWorkbook.createSheet("测评项分数导入模板表");
		// 创建Excel表头(rowNum:0表示表头),从0开始
		XSSFRow xssfRow = xssfSheet.createRow(1);
		// 设置缺省列高
		xssfSheet.setDefaultRowHeightInPoints(25);
		// 设置行的高度
		xssfRow.setHeightInPoints(25);
		// 格子单元样式
		XSSFCellStyle xssfCellStyle = xssfWorkbook.createCellStyle();
		XSSFFont xssfFont = xssfWorkbook.createFont();
		// 设置字体加粗
		xssfFont.setBold(true);
		// 设置“等线”字体
		xssfFont.setFontName("等线");
		// 设置字体大小(14号)
		xssfFont.setFontHeightInPoints((short) 14);
		xssfCellStyle.setFont(xssfFont);
		// 设置水平居中
		xssfCellStyle.setAlignment(HorizontalAlignment.CENTER);
		// 设置垂直居中
		xssfCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		// 设置表格默认列宽度为15个字节
		xssfSheet.setDefaultColumnWidth((short) 16);

		/**
		 * 3.Excel第一行: 合并单元格可以说明导入注意事项等
		 */
		// 在sheet里创建第一行,参数为行索引(excel的行)
		XSSFRow firstRow = xssfSheet.createRow(0);
		firstRow.setHeightInPoints(90);
		// 创建单元格(excel的单元格,参数为列索引)
		XSSFCell firstCell = firstRow.createCell(0);
		// 合并单元格, 参数依次表示起始行(0),截至行(0),起始列(0), 截至列(titleHeaders.size() - 1)
		xssfSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, titleHeaders.size() - 1));
		// 设置单元格内容
		firstCell.setCellValue("测评项分数导入提示:\n 1.红色字体代表必填项;\n 2.分数必须按照指定格式填写;\n 3.线下导入可能会覆盖线上测评的分数;");
		CellStyle firstRowCellStyle = xssfWorkbook.createCellStyle();
		// 左对齐
		firstRowCellStyle.setAlignment(HorizontalAlignment.LEFT);
		// 顶端对齐
		firstRowCellStyle.setVerticalAlignment(VerticalAlignment.TOP);
		// 强制单元格内容换行
		// 必须加上setWrapText(true)才能强制换行
		firstRowCellStyle.setWrapText(true);
		XSSFFont tipFont = xssfWorkbook.createFont();
		// 设置“华文楷体”字体
		tipFont.setFontName("华文楷体");
		tipFont.setColor(IndexedColors.RED.getIndex());
		// 设置字体大小
		tipFont.setFontHeightInPoints((short) 14);
		firstRowCellStyle.setFont(tipFont);
		firstCell.setCellStyle(firstRowCellStyle);

		/**
		 * 4.Excel表头、内容
		 */
		XSSFFont contentFont = xssfWorkbook.createFont();
		XSSFCellStyle contentCellStyle;
		// Excel模板表头相关信息设置 导出的Excel的标题列
		for (int i = 0; i < titleHeaders.size(); i++) {
			Map<String, Object> titleHeader = titleHeaders.get(i);
			XSSFCell cell = xssfRow.createCell(i);
			String type = titleHeader.get("TYPE").toString();
			String value = titleHeader.get("VALUE").toString();
			String realText = value;
			if (value.length() > 7) {
				realText = value.substring(0, 7) + "...";
			}
			XSSFRichTextString text = new XSSFRichTextString(realText);
			cell.setCellValue(text);

			// 设置批注 (对表头超长的时候,设置一些提示信息)
			Sheet sheet = cell.getSheet();
			Drawing p = sheet.createDrawingPatriarch();
			XSSFClientAnchor an = new XSSFClientAnchor(0, 0, 0, 0, 3, 0, 5, 5);
			Comment comment = p.createCellComment(an);
			XSSFRichTextString rtf = new XSSFRichTextString(value);
			Font commentFormatter = sheet.getWorkbook().createFont();
			rtf.applyFont(commentFormatter);
			comment.setString(rtf);
			cell.setCellComment(comment);

			switch (type) {
			case "FIXED":
				// 设置字体样式等
				contentCellStyle = this.buildContentCellStyle(contentFont, xssfWorkbook);
				cell.setCellStyle(contentCellStyle);
				break;
			case "LABEL":
				cell.setCellStyle(xssfCellStyle);
				break;
			default:
				break;
			}
		}
		return xssfWorkbook;
	}

	/**
	 * 组装Excel必填项的一些样式
	 */
	private XSSFCellStyle buildContentCellStyle(XSSFFont contentFont, XSSFWorkbook xssfWorkbook) {
		XSSFCellStyle contentCellStyle = xssfWorkbook.createCellStyle();
		// 粗体
		contentFont.setBold(true);
		// 字体颜色
		contentFont.setColor(IndexedColors.RED.getIndex());
		contentFont.setFontName("等线");
		// 设置字体大小
		contentFont.setFontHeightInPoints((short) 14);
		contentCellStyle.setFont(contentFont);
		// 水平居中
		contentCellStyle.setAlignment(HorizontalAlignment.CENTER);
		// 垂直居中
		contentCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		// 设置图案样式
		contentCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		// 设置图案颜色
		contentCellStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
		return contentCellStyle;
	}

以上代码有几点主要注意的地方:

【a】注意excel表格头部如果出现超长,可以参照我这里的处理方式,当然可能还有更好的方式,大家都可以尝试一下;

【b】注意excel文档一般都有一些提示语,注意在excel中强制换行的使用方法;

【c】注意可以为excel表头设置一些必填的标识等等;

(3). 运行结果如下:

前端调用方式:

<a href={`api/sm-comprehensive-evaluation/evaluationMng/exportDynamicExcelTemplate?cphjid=${this.props.cphjid}`} target={'_blank'}>

由于笔者使用的是react,所以支持上面的语法。

后端动态excel表头配置:

表头内容超出单元格的宽度时的一种处理方法,对表头内容进行截取,使用省略号代替,然后创建一个批注,鼠标悬停上去会提示表头的全部内容.

三、总结

以上就是关于POI操作Excel动态生成导入模板的示例,需要注意的地方就是.xls和.xlsx两种格式的excel的contentType不一致,必须要设置对,使用的Excel API相关对象也不一致,笔者踩过这个坑,在这里提醒一下,避免大家再次踩这个坑,本文只是笔者的一些学习总结和见解,大家如果需要相关的需求可以参考下,如果有更好的用法欢迎大家提出来,共同学习共同进步!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值