Freemarker整合poi导出带有图片的Excel教程

Freemarker整合poi导出带有图片的Excel教程

https://blog.csdn.net/x541211190/article/details/105675771
1.根据此人博客可完成此功能,但原文中有一处错误需要纠正,当单元格合并时,计算起始单元格有错误。

源代码:

	/**
	 * 构造合并单元格集合
	 *
	 * @param createRowIndex:
	 * @param cellRangeAddresses:
	 * @param startIndex:
	 * @param cellInfo:
	 * @param style:
	 * @return int
	 */
	private static int getCellRanges(int createRowIndex, List<CellRangeAddressEntity> cellRangeAddresses,
			int startIndex, Cell cellInfo, Style style) {
		if (cellInfo.getMergeAcross() != null || cellInfo.getMergeDown() != null) {
			CellRangeAddress cellRangeAddress = null;
			if (cellInfo.getMergeAcross() != null && cellInfo.getMergeDown() != null) {
				int mergeAcross = startIndex;
				if (cellInfo.getMergeAcross() != 0) {
					// 获取该单元格结束列数
					mergeAcross += cellInfo.getMergeAcross();
				}
				int mergeDown = createRowIndex;
				if (cellInfo.getMergeDown() != 0) {
					// 获取该单元格结束列数
					mergeDown += cellInfo.getMergeDown();
				}
				cellRangeAddress = new CellRangeAddress(createRowIndex, mergeDown, (short) startIndex,
						(short) mergeAcross);
			} else if (cellInfo.getMergeAcross() != null && cellInfo.getMergeDown() == null) {
				int mergeAcross = startIndex;
				if (cellInfo.getMergeAcross() != 0) {
					// 获取该单元格结束列数
					mergeAcross += cellInfo.getMergeAcross();
					// 合并单元格
					cellRangeAddress = new CellRangeAddress(createRowIndex, createRowIndex, (short) startIndex,
							(short) mergeAcross);
				}

			} else if (cellInfo.getMergeDown() != null && cellInfo.getMergeAcross() == null) {
				int mergeDown = createRowIndex;
				if (cellInfo.getMergeDown() != 0) {
					// 获取该单元格结束列数
					mergeDown += cellInfo.getMergeDown();
					// 合并单元格
					cellRangeAddress = new CellRangeAddress(createRowIndex, mergeDown, (short) startIndex,
							(short) startIndex);
				}
			}

			if (cellInfo.getMergeAcross() != null) {
				int length = cellInfo.getMergeAcross().intValue();
				for (int i = 0; i < length; i++) {
					startIndex += cellInfo.getMergeAcross();
				}
			}
			CellRangeAddressEntity cellRangeAddressEntity = new CellRangeAddressEntity();
			cellRangeAddressEntity.setCellRangeAddress(cellRangeAddress);
			if (style != null && style.getBorders() != null) {
				cellRangeAddressEntity.setBorders(style.getBorders());
			}
			cellRangeAddresses.add(cellRangeAddressEntity);
		}
		return startIndex;
	}

修改后代码:

	/**
	 * 构造合并单元格集合
	 *
	 * @param createRowIndex:
	 * @param cellRangeAddresses:
	 * @param startIndex:
	 * @param cellInfo:
	 * @param style:
	 * @return int
	 */
	private static int getCellRanges(int createRowIndex, List<CellRangeAddressEntity> cellRangeAddresses,
			int startIndex, Cell cellInfo, Style style) {
		if (cellInfo.getMergeAcross() != null || cellInfo.getMergeDown() != null) {
			CellRangeAddress cellRangeAddress = null;
			if (cellInfo.getMergeAcross() != null && cellInfo.getMergeDown() != null) {
				int mergeAcross = startIndex;
				if (cellInfo.getMergeAcross() != 0) {
					// 获取该单元格结束列数
					mergeAcross += cellInfo.getMergeAcross();
				}
				int mergeDown = createRowIndex;
				if (cellInfo.getMergeDown() != 0) {
					// 获取该单元格结束列数
					mergeDown += cellInfo.getMergeDown();
				}
				cellRangeAddress = new CellRangeAddress(createRowIndex, mergeDown, (short) startIndex,
						(short) mergeAcross);
			} else if (cellInfo.getMergeAcross() != null && cellInfo.getMergeDown() == null) {
				int mergeAcross = startIndex;
				if (cellInfo.getMergeAcross() != 0) {
					// 获取该单元格结束列数
					mergeAcross += cellInfo.getMergeAcross();
					// 合并单元格
					cellRangeAddress = new CellRangeAddress(createRowIndex, createRowIndex, (short) startIndex,
							(short) mergeAcross);
				}

			} else if (cellInfo.getMergeDown() != null && cellInfo.getMergeAcross() == null) {
				int mergeDown = createRowIndex;
				if (cellInfo.getMergeDown() != 0) {
					// 获取该单元格结束列数
					mergeDown += cellInfo.getMergeDown();
					// 合并单元格
					cellRangeAddress = new CellRangeAddress(createRowIndex, mergeDown, (short) startIndex,
							(short) startIndex);
				}
			}
             //此处应该去掉for循环,合并后应该是直接加上合并后的单元格个数,并不是循环
			if (cellInfo.getMergeAcross() != null) {
				int length = cellInfo.getMergeAcross().intValue();
				
					startIndex +=length;
				
			}
			CellRangeAddressEntity cellRangeAddressEntity = new CellRangeAddressEntity();
			cellRangeAddressEntity.setCellRangeAddress(cellRangeAddress);
			if (style != null && style.getBorders() != null) {
				cellRangeAddressEntity.setBorders(style.getBorders());
			}
			cellRangeAddresses.add(cellRangeAddressEntity);
		}
		return startIndex;
	}

2.在原基础上添加打印设置

/**
	 * 导出Excel到输出流(支持Excel2003版,xls格式)
	 *
	 * @param freemakerEntity
	 * @param outputStream
	 */
	private static void createImageExcleToStream(FreemarkerInput freemakerEntity, OutputStream outputStream) {
		Writer out = null;
		try {
			// 创建xml文件
			Template template = getTemplate(freemakerEntity.getTemplateName(), freemakerEntity.getTemplateFilePath());
			File tempXMLFile = new File(freemakerEntity.getXmlTempFile() + freemakerEntity.getFileName() + ".xml");
			FileUtils.forceMkdirParent(tempXMLFile);
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempXMLFile), "UTF-8"));
			template.process(freemakerEntity.getDataMap(), out);
			if (log.isDebugEnabled()) {
				log.debug("1.完成将文本数据导入到XML文件中");
			}
			SAXReader reader = new SAXReader();
			Document document = reader.read(tempXMLFile);
			Map<String, Style> styleMap = readXmlStyle(document);
			log.debug("2.完成解析XML中样式信息");
			List<Worksheet> worksheets = readXmlWorksheet(document);
			if (log.isDebugEnabled()) {
				log.debug("3.开始将XML信息写入Excel,数据为:" + worksheets.toString());
			}
			HSSFWorkbook wb = new HSSFWorkbook();
			for (Worksheet worksheet : worksheets) {
				HSSFSheet sheet = wb.createSheet(worksheet.getName());
				Table table = worksheet.getTable();
				List<Row> rows = table.getRows();
				List<Column> columns = table.getColumns();
				// 填充列宽
				int columnIndex = 0;
				for (int i = 0; i < columns.size(); i++) {
					Column column = columns.get(i);
					columnIndex = getCellWidthIndex(columnIndex, i, column.getIndex());
					sheet.setColumnWidth(columnIndex, (int) column.getWidth() * 50);
				}
				int createRowIndex = 0;
				List<CellRangeAddressEntity> cellRangeAddresses = new ArrayList<>();
				for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) {
					Row rowInfo = rows.get(rowIndex);
					if (rowInfo == null) {
						continue;
					}
					createRowIndex = getIndex(createRowIndex, rowIndex, rowInfo.getIndex());
					HSSFRow row = sheet.createRow(createRowIndex);
					if (rowInfo.getHeight() != null) {
						Integer height = rowInfo.getHeight() * 20;
						row.setHeight(height.shortValue());
					}
					List<Cell> cells = rowInfo.getCells();
					if (CollectionUtils.isEmpty(cells)) {
						continue;
					}
					int startIndex = 0;
					for (int cellIndex = 0; cellIndex < cells.size(); cellIndex++) {
						Cell cellInfo = cells.get(cellIndex);
						if (cellInfo == null) {
							continue;
						}
						// 获取起始列
						startIndex = getIndex(startIndex, cellIndex, cellInfo.getIndex());
						HSSFCell cell = row.createCell(startIndex);
						String styleID = cellInfo.getStyleID();
						Style style = styleMap.get(styleID);
						/*设置数据单元格格式*/
						CellStyle dataStyle = wb.createCellStyle();
						// 设置边框样式
						setBorder(style, dataStyle);
						// 设置对齐方式
						setAlignment(style, dataStyle);
						// 填充文本
						setValue(wb, cellInfo, cell, style, dataStyle);
						// 填充颜色
						setCellColor(style, dataStyle);
						cell.setCellStyle(dataStyle);
						//单元格注释
						if (cellInfo.getComment() != null) {
							Data data = cellInfo.getComment().getData();
							Comment comment = sheet.createDrawingPatriarch()
									.createCellComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
							comment.setString(new HSSFRichTextString(data.getText()));
							cell.setCellComment(comment);
						}
						// 合并单元格
						startIndex = getCellRanges(createRowIndex, cellRangeAddresses, startIndex, cellInfo, style);
					}
				}
				// 添加合并单元格
				addCellRange(sheet, cellRangeAddresses);
			   //添加打印设置
			   HSSFPrintSetup ps=sheet.getPrintSetup();
			   ps.setLandscape(false);//打印方向,true:横向 ,false:纵向
			   ps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);//纸张A4
			 sheet.setMargin(HSSFSheet.BottomMargin,(double)0.5);//页边距(下)
			 sheet.setMargin(HSSFSheet.LeftMargin,(double)0.3);//页边距(左)
			 sheet.setMargin(HSSFSheet.RightMargin,(double)0.3);//页边距(右)
			 sheet.setMargin(HSSFSheet.TopMargin,(double)0.5);//页边距(右)
			 sheet.setHorizontallyCenter(true);//设置打印页面为水平居中
			 sheet.setAutobreaks(true);//将整个工作表缩放打印在一页上  
			}
			// 加载图片到excel
			log.debug("4.开始写入图片:" + freemakerEntity.getExcelImageInputs());
			if (!CollectionUtils.isEmpty(freemakerEntity.getExcelImageInputs())) {
				writeImageToExcel(freemakerEntity.getExcelImageInputs(), wb);
			}
			log.debug("5.完成写入图片:" + freemakerEntity.getExcelImageInputs());
			// 写入excel文件,response字符流转换成字节流,template需要字节流作为输出
			wb.write(outputStream);
			outputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
			log.error("导出excel异常:" + e.getMessage());
		} finally {
			try {
				out.close();
			} catch (Exception e) {

			}
		}
	}

3.边框设置

/**
	 * 设置边框
	 *
	 * @param style:
	 * @param dataStyle:
	 * @return void
	 */
	private static void setBorder(Style style, CellStyle dataStyle) {
		if (style != null && style.getBorders() != null) {
			for (int k = 0; k < style.getBorders().size(); k++) {
				Style.Border border = style.getBorders().get(k);
				if (border != null) {
					if ("Bottom".equals(border.getPosition())) {
						dataStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
						//当weight等于1时,线宽为默认样式;当weight等于2时,线宽为样式为中等粗线,其他样式可根据绘制Excel线宽进行对比weight值对应那种线宽样式
						if(border.getWeight()==1){
						dataStyle.setBorderBottom(BorderStyle.THIN);
						}else if(border.getWeight()==2){
						dataStyle.setBorderBottom(BorderStyle.MEDIUM);
						}
						
					}
					if ("Left".equals(border.getPosition())) {
						dataStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
						//当weight等于1时,线宽为默认样式;当weight等于2时,线宽为样式为中等粗线,其他样式可根据绘制Excel线宽进行对比weight值对应那种线宽样式
						if(border.getWeight()==1){
						dataStyle.setBorderLeft(BorderStyle.THIN);
						}else if(border.getWeight()==2){
						dataStyle.setBorderLeft(BorderStyle.MEDIUM);
						}
				
					}
					if ("Right".equals(border.getPosition())) {
						dataStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
						//当weight等于1时,线宽为默认样式;当weight等于2时,线宽为样式为中等粗线,其他样式可根据绘制Excel线宽进行对比weight值对应那种线宽样式
						if(border.getWeight()==1){
						dataStyle.setBorderRight(BorderStyle.THIN);
						}else if(border.getWeight()==2){
						dataStyle.setBorderRight(BorderStyle.MEDIUM);
						}
					
					}
					if ("Top".equals(border.getPosition())) {
						dataStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
						//当weight等于1时,线宽为默认样式;当weight等于2时,线宽为样式为中等粗线,其他样式可根据绘制Excel线宽进行对比weight值对应那种线宽样式
						if(border.getWeight()==1){
						dataStyle.setBorderTop(BorderStyle.THIN);
						}else if(border.getWeight()==2){
						dataStyle.setBorderTop(BorderStyle.MEDIUM);
						}
					}
				}

			}
		}
	}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Spring Boot 中集成 Freemarker 导出 Excel,可以通过以下步骤实现: 1. 首先,需要在 Spring Boot 中添加 Freemarker 和 Apache POI 依赖: ```xml <dependencies> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>${freemarker.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${apache.poi.version}</version> </dependency> </dependencies> ``` 2. 创建 Excel 模板文件,可以使用 Freemarker 的模板语法来定义表头和数据内容,同时在模板中可以使用 `img` 标签来引用图片,例如: ```html <html> <head> <title>Excel Template</title> </head> <body> <table> <thead> <tr> <th>Name</th> <th>Age</th> <th>Photo</th> </tr> </thead> <tbody> <#list users as user> <tr> <td>${user.name}</td> <td>${user.age}</td> <td><img src="${user.photo}" /></td> </tr> </#list> </tbody> </table> </body> </html> ``` 其中,`users` 是一个包含数据的列表,每个元素是一个包含 `name`、`age` 和 `photo` 属性的对象,`photo` 属性是图片的 URL。 3. 在 Spring Boot 中定义一个控制器,用于处理导出 Excel 的请求: ```java @Controller public class ExcelController { @Autowired private Configuration freemarkerConfig; @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws Exception { // 读取 Excel 模板文件 Template template = freemarkerConfig.getTemplate("excel-template.ftl"); // 准备数据 List<User> users = prepareData(); // 创建 Excel 工作簿 Workbook workbook = new XSSFWorkbook(); // 渲染模板,生成 Excel 文件 Map<String, Object> model = new HashMap<>(); model.put("users", users); StringWriter out = new StringWriter(); template.process(model, out); InputStream is = new ByteArrayInputStream(out.toString().getBytes("UTF-8")); workbook = WorkbookFactory.create(is); // 设置响应头,告诉浏览器文件类型是 Excel response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-disposition", "attachment; filename=users.xlsx"); // 将 Excel 文件写入响应流中 OutputStream os = response.getOutputStream(); workbook.write(os); os.flush(); os.close(); } private List<User> prepareData() { // TODO: 从数据库或其他来源读取数据 return Arrays.asList( new User("Alice", 25, "https://example.com/alice.jpg"), new User("Bob", 30, "https://example.com/bob.jpg"), new User("Charlie", 20, "https://example.com/charlie.jpg") ); } private static class User { private String name; private int age; private String photo; public User(String name, int age, String photo) { this.name = name; this.age = age; this.photo = photo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPhoto() { return photo; } public void setPhoto(String photo) { this.photo = photo; } } } ``` 在该控制器中,我们注入了 `Configuration` 类,它是 Freemarker 的配置类,用于加载 Excel 模板文件。在 `exportExcel` 方法中,我们先准备数据,然后通过 `template.process` 方法渲染模板,生成 Excel 文件。最后将 Excel 文件写入响应流中,浏览器会自动下载该文件。 4. 如果 Excel 模板中包含图片,那么需要在渲染模板之前,将图片下载到本地,然后将图片的本地路径传递给模板。例如: ```java private String downloadImage(String imageUrl) throws Exception { URL url = new URL(imageUrl); String fileName = url.getFile(); String filePath = "images/" + fileName.substring(fileName.lastIndexOf("/") + 1); FileUtils.copyURLToFile(url, new File(filePath)); return filePath; } @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws Exception { // 读取 Excel 模板文件 Template template = freemarkerConfig.getTemplate("excel-template.ftl"); // 准备数据 List<User> users = prepareData(); // 下载图片并将本地路径传递给模板 for (User user : users) { String photoPath = downloadImage(user.getPhoto()); user.setPhoto(photoPath); } // 创建 Excel 工作簿 Workbook workbook = new XSSFWorkbook(); // 渲染模板,生成 Excel 文件 Map<String, Object> model = new HashMap<>(); model.put("users", users); StringWriter out = new StringWriter(); template.process(model, out); InputStream is = new ByteArrayInputStream(out.toString().getBytes("UTF-8")); workbook = WorkbookFactory.create(is); // 设置响应头,告诉浏览器文件类型是 Excel response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-disposition", "attachment; filename=users.xlsx"); // 将 Excel 文件写入响应流中 OutputStream os = response.getOutputStream(); workbook.write(os); os.flush(); os.close(); } ``` 在该示例中,我们定义了一个 `downloadImage` 方法,用于下载图片,并将图片保存到 `images` 目录下。然后在 `exportExcel` 方法中,遍历用户列表,调用 `downloadImage` 方法下载每个用户的图片,并将本地路径传递给模板。注意,模板中使用的图片路径应该和下载到本地的路径一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值