POI根据Word模板导出

段落/表格混合导出
有结束符号“##{foreachRows}##”

/**
	 *	表格+段落
	 * @param inputUrl 模板路径
	 * @param out	OutputStream 输出流
	 * @param map	表格外数据
	 * @param list	表格数据
	 */
public void expor(String inputUrl,OutputStream out,Map<String,String> map,List<Map<String,String>> list){
		try {
			// 获取docx解析对象
			XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
			// 表格外替换
			if (map != null) {
				replaceInAllParagraphs(document.getParagraphs(), packMap(map));
			}
			// 表格内替换
			List<XWPFTable> tables = document.getTables();
			XWPFTable table = tables.get(0);
			System.out.println(checkText(table.getText()));
			if (checkText(table.getText())) {
				List<XWPFTableRow> templateTableRows = table.getRows();
				int startRowsIndex = 0;// 标签行indexs
				int endRowIndex = 0;// 循环结束行标签索引
				for (int i = 0, size = templateTableRows.size(); i < size; i++) {
					String rowText = templateTableRows.get(i).getCell(0).getText();// 获取到表格行的第一个单元格
					if (rowText.indexOf("##{foreachRows}##") > -1) {
						startRowsIndex = i;
						continue;
					}
					if (rowText.indexOf("##{endForeachRows}##") > -1) {
						endRowIndex = i;
						break;
					}
				}
				// 获取到模板行
				startRowsIndex = startRowsIndex + 1;
				// 复制模板行和替换数据
				replaceAndCopyRows(startRowsIndex, endRowIndex, table, list,true);
				if (map != null) {
					// 替换表格中段落数据
					replaceInTable(table, packMap(map));
				}
			}
			System.out.println(document.getTables());
			document.write(out);
			out.close();
		}catch (Exception e){
			e.printStackTrace();
		}
	}

无结束符号“##{foreachRows}##”

/**
	 * 根据模板生成新word文档 (一个表格模板,多行数据循环,混合表格外文本数据)
	 */
	public static void exportWord(String inputUrl, OutputStream out,
								  Map<String, String> map, List<Map<String, String>> list) {
		try {
			// 获取docx解析对象
			XWPFDocument document = new XWPFDocument(new FileInputStream(
					inputUrl));
			if (map != null) {
				// 表格外替换
				replaceInAllParagraphs(document.getParagraphs(), packMap(map));
			}
			// 表格内替换
			List<XWPFTable> tables = document.getTables();
			XWPFTable table = tables.get(0);
			if (checkText(table.getText())) {
				List<XWPFTableRow> templateTableRows = table.getRows();

				int tagRowsIndex = 0;
				for (int i = 0, size = templateTableRows.size(); i < size; i++) {
					String rowText = templateTableRows.get(i).getCell(0)
							.getText();// 获取到表格行的第一个单元格
					if (rowText.indexOf("##{foreachRows}##") > -1) {
						tagRowsIndex = i;
						break;
					}
				}
				// 获取到模板行
				tagRowsIndex = tagRowsIndex + 1;
				// 复制模板行和替换数据
				replaceAndCopyRows(tagRowsIndex, templateTableRows.size(),
						table, list, false);
			}
			document.write(out);
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

可以根据模板样式选择调用方法

/**
	 * 替换一个表格中的所有行
	 * @param xwpfTable 一个表格
	 * @param params 所有替换数据集合
	 */
	private static void replaceInTable(XWPFTable xwpfTable,Map<String, String> params) {
		List<XWPFTableRow> rows = xwpfTable.getRows();
		replaceInRows(rows, params);
	}
	/**
	 * 替换表格中的一行
	 * @param rows 所有行
	 * @param params 所有替换数据集合
	 */
	private static void replaceInRows(List<XWPFTableRow> rows,Map<String, String> params) {
		for (int i = 0; i < rows.size(); i++) {
			XWPFTableRow row = rows.get(i);
			replaceInCells(row.getTableCells(), params);
		}
	}
	/**
	 * 在指定行位置开始替换数据
	 * @param startIndex 开始索引
	 * @param endIndex 结束索引
	 * @param table 模板表格
	 * @param tableList 需要替换的数据集合
	 */
	private static Integer replaceAndCopyRows(int startIndex, int endIndex,XWPFTable table, List<Map<String, String>> tableList,boolean endFlag) {
		tableList = packListMap(tableList);
		List<XWPFTableRow> templateTableRows = table.getRows();
		XWPFTableRow tempRow = templateTableRows.get(startIndex);
		int rsIndex = 0;
		int exitTempRow = endIndex - startIndex;
		// 模板行数 < 需替换的集合数量, 复制相差的模板行数
		if (exitTempRow < tableList.size()) {
			int moreRow = tableList.size() - exitTempRow;
			rsIndex = endIndex + moreRow;
			for (int m = 0; m < moreRow; m++) {
				table.insertNewTableRow(endIndex + m);
				copyTableRow(tempRow, templateTableRows.get(endIndex + m));// 复制模板行
			}
			if (endFlag) {
				table.removeRow(endIndex + moreRow);
			}
		}
		// 模板行数 > 需要替换的集合数据,删除多余的模板行数
		if (exitTempRow > tableList.size()) {
			int deleteRow = exitTempRow - tableList.size();
			rsIndex = endIndex - deleteRow;
			if (endFlag) {
				for (int m = 0; m <= deleteRow; m++) {
					table.removeRow(endIndex - m);
				}
			} else {
				for (int m = 1; m <= deleteRow; m++) {
					table.removeRow(endIndex - m);
				}
			}
		}
		// 在模板的基础上循环替换为数据
		for (int j = 0; j < tableList.size(); j++) {
			XWPFTableRow newCreateRow = templateTableRows.get(j + startIndex);
			replaceTableRow(newCreateRow, tableList.get(j));// 处理标签替换
		}
		table.removeRow(startIndex - 1);// 移除多出来的标签行
		return rsIndex;
	}
	/**
	 * 替换一行
	 */
	private static void replaceTableRow(XWPFTableRow row,Map<String, String> textMap) {
		List<XWPFTableCell> cells = row.getTableCells();
		replaceInCells(cells, packMap(textMap));
	}
	/**
	 * 替换一行中所有的单元格
	 * @param xwpfTableCellList 所有段落
	 * @param params 所有替换数据集合
	 */
	private static void replaceInCells(List<XWPFTableCell> xwpfTableCellList, Map<String, String> params) {
		for (XWPFTableCell cell : xwpfTableCellList) {
			replaceInCell(cell, params);
		}
	}
	/**
	 * 替换表格中每一行中的每一个单元格中的所有段落
	 * @param cell 一个单元格
	 * @param params 所有替换数据集合
	 */
	private static void replaceInCell(XWPFTableCell cell,Map<String, String> params) {
		List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
		replaceInAllParagraphs(cellParagraphs, params);
	}
	/**
	 * 复制一行
	 */
	private static void copyTableRow(XWPFTableRow source, XWPFTableRow target) {
		// 复制样式
		if (source.getCtRow() != null) {
			target.getCtRow().setTrPr(source.getCtRow().getTrPr());
		}
		// 复制单元格
		for (int i = 0; i < source.getTableCells().size(); i++) {
			XWPFTableCell cell1 = target.getCell(i);
			XWPFTableCell cell2 = source.getCell(i);
			if (cell1 == null) {
				cell1 = target.addNewTableCell();
			}
			copyTableCell(cell2, cell1);
		}
	}
	/**
	 * 复制单元格,从source到target
	 */
	private static void copyTableCell(XWPFTableCell source, XWPFTableCell target) {
		// 列属性
		if (source.getCTTc() != null) {
			target.getCTTc().setTcPr(source.getCTTc().getTcPr());
		}
		// 删除段落
		for (int pos = 0; pos < target.getParagraphs().size(); pos++) {
			target.removeParagraph(pos);
		}
		// 添加段落
		for (XWPFParagraph sp : source.getParagraphs()) {
			XWPFParagraph targetP = target.addParagraph();
			copyParagraph(sp, targetP);
		}
	}
	/**
	 * 复制段落,从source到target
	 */
	private static void copyParagraph(XWPFParagraph source, XWPFParagraph target) {
		// 设置段落样式
		target.getCTP().setPPr(source.getCTP().getPPr());
		// 移除所有的run
		for (int pos = target.getRuns().size() - 1; pos >= 0; pos--) {
			target.removeRun(pos);
		}
		// copy 新的run
		for (XWPFRun s : source.getRuns()) {
			XWPFRun targetrun = target.createRun();
			copyRun(s, targetrun);
		}
	}
	/**
	 * 复制RUN,从source到target
	 */
	private static void copyRun(XWPFRun source, XWPFRun target) {
		// 设置run属性
		target.getCTR().setRPr(source.getCTR().getRPr());
		// 设置文本
		target.setText(source.getText(0));
	}
	/**
	 * 重新组装List<Map<String,String>>数据(自动生成序号)
	 */
	private static List<Map<String, String>> packListMap(List<Map<String, String>> list) {
		int count = 0;
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				count++;
				Map<String, String> map = list.get(i);
				map.put("index", count + "");
			}
		}
		return list;
	}
	/**
	 * 判断文本中时候包含$
	 * @param text 文本
	 * @return 包含返回true,不包含返回false
	 */
	private static boolean checkText(String text) {
		boolean check = false;
		if (text.indexOf("$") != -1) {
			check = true;
		}
		return check;

	}
	/**
	 * 重新组装map数据
	 */
	private static Map<String, String> packMap(Map<String, String> map) {
		Map<String, String> newMap = new HashMap<>();
		for (Map.Entry<String, String> e : map.entrySet()) {
			String key = "${" + e.getKey() + "}";
			newMap.put(key, e.getValue());
		}
		return newMap;
	}
	/**
	 * 替换所有段落中的标记(表格外替换)
	 * @param xwpfParagraphList 所有段落集合
	 * @param params 所有替换数据集合
	 */
	private static void replaceInAllParagraphs(List<XWPFParagraph> xwpfParagraphList, Map<String, String> params) {
		for (XWPFParagraph paragraph : xwpfParagraphList) {
			if (paragraph.getText() == null || paragraph.getText().equals("")){
				continue;
			}
			for (String key : params.keySet()) {
				if (paragraph.getText().contains(key)) {
					replaceInParagraph(paragraph, key, params.get(key));
				}
			}
		}
	}
	/**
	 * 替换段落中的字符串
	 * @param xwpfParagraph 一个段落
	 * @param oldString 模板字符串
	 * @param newString 替换的数据字符串
	 */
	private static void replaceInParagraph(XWPFParagraph xwpfParagraph,String oldString, String newString) {
		Map<String, Integer> pos_map = findSubRunPosInParagraph(xwpfParagraph,oldString);
		if (pos_map != null) {
			List<XWPFRun> runs = xwpfParagraph.getRuns();
			XWPFRun modelRun = runs.get(pos_map.get("end_pos"));
			XWPFRun xwpfRun = xwpfParagraph.insertNewRun(pos_map.get("end_pos") + 1);
			xwpfRun.setText(newString);
			if (modelRun.getFontSize() != -1){
				xwpfRun.setFontSize(modelRun.getFontSize());// 默认值是五号字体,但五号字体getFontSize()时,返回-1
			}
			xwpfRun.setFontFamily(modelRun.getFontFamily());
			for (int i = pos_map.get("end_pos"); i >= pos_map.get("start_pos"); i--) {
				xwpfParagraph.removeRun(i);
			}
		}
	}
	/*
	 * 找到段落中子串的起始XWPFRun下标和终止XWPFRun的下标
	 * @param xwpfParagraph 一个段落
	 * @param substring 需要替换的包含${}的字符串
	 * @return
	 */
	private static Map<String, Integer> findSubRunPosInParagraph(XWPFParagraph xwpfParagraph, String substring) {
		List<XWPFRun> runs = xwpfParagraph.getRuns();
		int start_pos = 0;
		int end_pos = 0;
		String subtemp = "";
		for (int i = 0; i < runs.size(); i++) {
			subtemp = "";
			start_pos = i;
			for (int j = i; j < runs.size(); j++) {
				if (runs.get(j).getText(runs.get(j).getTextPosition()) == null){
					continue;
				}
				subtemp += runs.get(j).getText(runs.get(j).getTextPosition());
				if (subtemp.equals(substring)) {
					end_pos = j;
					Map<String, Integer> map = new HashMap<>();
					map.put("start_pos", start_pos);
					map.put("end_pos", end_pos);
					return map;
				}
			}
		}
		return null;
	}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值