poi操作word向word中写入复杂的表格(合并行、合并列)

一、准备工作
能遇到这种问题的相信大家都有jar包了,如果没有那就度娘找一下吧。
闲话不多直接上代码
二、代码

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Iterator;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableCell.XWPFVertAlign;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;

import com.google.common.base.Strings;

/**
 * poi操作word向word中写入复杂的表格(合并行、合并列)
 * 
 * @author Christmas_G
 *
 */
public class Test {

	public static void main(String[] args) throws Exception {
		String tableContent = "<table cellspacing=\"0\" cellpadding=\"0\" width=\"0\"><tbody><tr><td align=\"CENTER\" style=\"border: 1px solid gray\" width=\"121\">班级</td><td align=\"CENTER\" style=\"border: 1px solid gray\" width=\"95\">班级人数</td><td align=\"CENTER\" style=\"border: 1px solid gray\" width=\"95\">近视人数</td><td align=\"CENTER\" style=\"border: 1px solid gray\" width=\"312\">近视人数占全班人数的百分数(除不尽的百分号前保留一位小数)</td></tr><tr><td align=\"CENTER\" style=\"border: 1px solid gray\">六一班</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td><td align=\"CENTER\" style=\"border: 1px solid gray\">8</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td></tr><tr><td align=\"CENTER\" style=\"border: 1px solid gray\">六二班</td><td align=\"CENTER\" style=\"border: 1px solid gray\">32</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td></tr><tr><td align=\"CENTER\" style=\"border: 1px solid gray\">六三班</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td><td align=\"CENTER\" style=\"border: 1px solid gray\">.</td><td align=\"CENTER\" style=\"border: 1px solid gray\">22.2%</td></tr><tr><td align=\"CENTER\" style=\"border: 1px solid gray\">合计</td><td align=\"CENTER\" style=\"border: 1px solid gray\">117</td><td align=\"CENTER\" style=\"border: 1px solid gray\">26</td><td align=\"CENTER\" style=\"border: 1px solid gray\">22.2%</td></tr></tbody></table>";
		Element node = supplementTable(tableContent);

		XWPFDocument set = setTable(node);
		OutputStream stream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test\\cc.docx");
		set.write(stream);
		set.close();
	}

	/**
	 * 向word中写表格
	 * 
	 * @author Christmas_G
	 * @param element
	 * @return
	 * @throws Exception
	 */
	private static XWPFDocument setTable(Element element) throws Exception {
		Document tableDoc = element.ownerDocument();

		Elements trList = tableDoc.getElementsByTag("tr");
		Elements tdList = trList.first().getElementsByTag("td");

		XWPFDocument document = new XWPFDocument();
		XWPFTable table = document.createTable(trList.size(), tdList.size());

		boolean[][] colspanFlag = new boolean[trList.size()][tdList.size()];
		boolean[][] rowspanFlag = new boolean[trList.size()][tdList.size()];
		for (int row = 0; row < trList.size(); row++) {
			Element tr = trList.get(row);
			Elements tds = tr.getElementsByTag("td");

			for (int col = 0; col < tds.size(); col++) {
				Element td = tds.get(col);

				String colspan = td.attr("colspan");
				String rowspan = td.attr("rowspan");

				String align = td.attr("align");
				String widthStyle = td.attr("width");
				String style = td.attr("style");
				
				// 记录需要合并的列
				if (!StringUtils.isEmpty(colspan)) {
					int colCount = Integer.parseInt(colspan);
					for (int i = 0; i < colCount - 1; i++) {
						colspanFlag[row][col + i + 1] = true;
					}
				}
				// 记录需要合并的行
				if (!StringUtils.isEmpty(rowspan)) {
					int rowCount = Integer.parseInt(rowspan);
					for (int i = 0; i < rowCount - 1; i++) {
						rowspanFlag[row + i + 1][col] = true;
					}
				}
				// 处理合并
				XWPFTableCell cell = table.getRow(row).getCell(col);
				if (colspanFlag[row][col]) {
					setColMerge(cell, STMerge.CONTINUE);
					continue;
				} else {
					setColMerge(cell, STMerge.RESTART);
				}
				if (rowspanFlag[row][col]) {
					setRowMerge(cell, STMerge.CONTINUE);
					continue;
				} else {
					setRowMerge(cell, STMerge.RESTART);
				}
				// 设置列宽
				if (!Strings.isNullOrEmpty(widthStyle) && !"0".equals(widthStyle)) {
					int width = Integer.parseInt(widthStyle);

					setWidth(cell, width);
				}

				XWPFParagraph paragraph = null;
				int size = cell.getParagraphs().size();
				if (size == 0) {
					paragraph = cell.addParagraph();
				} else {
					paragraph = cell.getParagraphs().get(size - 1);
				}
				// 设置水平样式
				if ("CENTER".equalsIgnoreCase(align)) {
					paragraph.setAlignment(ParagraphAlignment.CENTER);
				} else if ("LEFT".equalsIgnoreCase(align)) {
					paragraph.setAlignment(ParagraphAlignment.LEFT);
				}
				// 设置垂直居中
				cell.setVerticalAlignment(XWPFVertAlign.CENTER);
				
				// 设置没有边框
				if (!style.contains("border:")) {
					setNotBorder(cell);
				}

				XWPFRun run = paragraph.createRun();
				run.setText(td.text());
			}
		}
		return document;
	}

	/**
	 * 设置行合并属性
	 * 
	 * @author Christmas_G
	 * @date 2019-05-31 14:08:02
	 * @param tableCell
	 * @param mergeVlaue
	 */
	private static void setRowMerge(XWPFTableCell tableCell, STMerge.Enum mergeVlaue) {
		CTTc ctTc = tableCell.getCTTc();
		CTTcPr cpr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
		CTVMerge merge = cpr.isSetVMerge() ? cpr.getVMerge() : cpr.addNewVMerge();
		merge.setVal(mergeVlaue);
	}

	/**
	 * 设置列合并属性
	 * 
	 * @author Christmas_G
	 * @date 2019-05-31 14:07:50
	 * @param tableCell
	 * @param mergeVlaue
	 */
	private static void setColMerge(XWPFTableCell tableCell, STMerge.Enum mergeVlaue) {
		CTTc ctTc = tableCell.getCTTc();
		CTTcPr cpr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
		CTHMerge merge = cpr.isSetHMerge() ? cpr.getHMerge() : cpr.addNewHMerge();
		merge.setVal(mergeVlaue);
	}

	/**
	 * 补全表格
	 * 
	 * @author Christmas_G
	 * @date 2019-05-31 13:32:52
	 * @param tableHtml
	 * @return
	 */
	private static Element supplementTable(String tableHtml) {
		Document tableDoc = Jsoup.parse(tableHtml);
		Elements trels = tableDoc.getElementsByTag("tr");
		// 补全合并的列
		supplementMergedColumns(trels);
		// 补全合并的行
		supplementMergedRows(trels);
		return tableDoc.getElementsByTag("table").first();
	}

	/**
	 * 补全合并的列
	 * 
	 * @author Christmas_G
	 * @date 2019-05-31 11:57:36
	 * @param trels
	 */
	private static void supplementMergedColumns(Elements trels) {
		// 所有tr
		Iterator<Element> trelIter = trels.iterator();
		while (trelIter.hasNext()) {
			Element trel = trelIter.next();
			// 获取所有td
			Elements tdels = trel.getElementsByTag("td");
			Iterator<Element> tdelIter = tdels.iterator();
			while (tdelIter.hasNext()) {
				Element tdel = tdelIter.next();
				// 删除样式
				tdel.removeAttr("class");
				// 取到合并的列数量
				String colspanIndex = tdel.attr("colspan");
				if (StringUtils.isEmpty(colspanIndex)) {
					continue;
				}
				Integer colspanVal = Integer.parseInt(colspanIndex);
				for (int i = 1; i < colspanVal; i++) {
					trel.appendElement("td");
				}
			}
		}
	}

	/**
	 * 补全合并的行(调用此方法前 需要调用 “补全合并的列”方法)
	 * 
	 * @author Christmas_G
	 * @date 2019-05-31 11:57:47
	 * @param trels
	 */
	private static void supplementMergedRows(Elements trels) {
		// 获取最大的列
		int tdSize = 0;
		Iterator<Element> iterator = trels.iterator();
		while (iterator.hasNext()) {
			Element element = iterator.next();
			int size = element.getElementsByTag("td").size();
			if (size > tdSize) {
				tdSize = size;
			}
		}

		for (int i = 0; i < trels.size(); i++) {
			Element currTr = trels.get(i);
			int currTrTds = currTr.getElementsByTag("td").size();
			if (currTrTds == tdSize) {
				continue;
			}

			int count = tdSize - currTrTds;
			for (int j = 0; j < count; j++) {
				currTr.appendElement("td");
			}
		}
	}

	/**
	 * 设置列宽
	 * 
	 * @author Christmas_G
	 * @date 2019-06-28 11:30:22
	 * @param cell
	 * @param width
	 */
	private static void setWidth(XWPFTableCell cell, int width) {
		CTTblWidth ctTblWidth = cell.getCTTc().addNewTcPr().addNewTcW();
		// 此处乘以20是我以最接近A4上创建表格的宽度手动设置的
		// 目前没有找到将px转换为word里单位的方式
		ctTblWidth.setW(BigInteger.valueOf(width).multiply(BigInteger.valueOf(20)));
		ctTblWidth.setType(STTblWidth.DXA);
	}

	/**
	 * 设置表格为没有边框线
	 * 
	 * @author Christmas_G
	 * @date 2019-06-28 11:33:48
	 * @param cell
	 */
	private static void setNotBorder(XWPFTableCell cell) {
		CTTcBorders cTTcBorders = cell.getCTTc().getTcPr().addNewTcBorders();
		CTBorder clBorder = cTTcBorders.addNewLeft();
		clBorder.setVal(STBorder.Enum.forString("none"));
		clBorder.setShadow(STOnOff.ON);
		CTBorder crBorder = cTTcBorders.addNewRight();
		crBorder.setVal(STBorder.Enum.forString("none"));
		crBorder.setShadow(STOnOff.ON);
		CTBorder cbBorder = cTTcBorders.addNewBottom();
		cbBorder.setVal(STBorder.Enum.forString("none"));
		cbBorder.setShadow(STOnOff.ON);
		CTBorder ctBorder = cTTcBorders.addNewTop();
		ctBorder.setVal(STBorder.Enum.forString("none"));
		ctBorder.setShadow(STOnOff.ON);
	}

}

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值