java poi给word(2007及以上)的书签动态替换文字、图片(可浮于文字上方)

一、因为原本的XWPFDocument类插入图片方法有bug,要么打不开word,要么打开了不显示图片,所以新建一个CustomXWPFDocument类继承XWPFDocument,重写插入图片方法。

二、插入到指定位置(书签)是获取所有段落、所有表格,遍历获取到的每一个段落(表格可以获取到cell后再获取cell里的段落),段落通过paragraph.getCTP().getBookmarkStartList()获得所有的书签,匹配需要的书签创建run,然后把图片添加到创建的run中。

三、插入图片默认为嵌入型,这里提供浮于文字上方方法(把anchor标签下的behindDoc属性设为0,同时添加一个的空标签)。

四、其中main方法里为启动方式

五、完整代码如下:

package com.enter.net.fhbusiness.construction.service.impl;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;

import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

/**
 * poi在指定书签位置添加图片
 */
public class CustomXWPFDocument extends XWPFDocument {
	public CustomXWPFDocument() {
		super();
	}

	public CustomXWPFDocument(OPCPackage opcPackage) throws IOException {
		super(opcPackage);
	}

	public CustomXWPFDocument(InputStream in) throws IOException {
		super(in);
	}

	public void addPictureToRun(XWPFRun run, String blipId, int id, int width, int height) {
		final int EMU = 9525;
		width *= EMU;
		height *= EMU;

		String picXml = "" +
				"" +
				"   " +
				"      " +
				"         " +
				"            " +
				"            " +
				"         " +
				"         " +
				"            " +
				"            " +
				"               " +
				"            " +
				"         " +
				"         " +
				"            " +
				"               " +
				"               " +
				"            " +
				"            " +
				"               " +
				"            " +
				"         " +
				"      " +
				"   " +
				"";

		XmlToken xmlToken = null;
		try {
			xmlToken = XmlToken.Factory.parse(picXml);
		} catch(XmlException xe) {
			xe.printStackTrace();
		}
		CTPositiveSize2D extent = null;
		CTNonVisualDrawingProps docPr = null;
		CTInline inline = run.getCTR().addNewDrawing().addNewInline();
		inline.set(xmlToken);
		inline.setDistT(0);
		inline.setDistB(0);
		inline.setDistL(0);
		inline.setDistR(0);
		extent = inline.addNewExtent();
		docPr = inline.addNewDocPr();

		extent.setCx(width);
		extent.setCy(height);

		docPr.setId(id);
		docPr.setName("Picture " + id);
		docPr.setDescr("Generated");
	}

	public static void main(String[] args) throws IOException, InvalidFormatException {
//		String doc_path = "E:\\apache-tomcat-8.0.30\\webapps\\jeefh\\fh\\doc\\pageoffice\\c3f13d99bb1e455fb585691271a9d729.doc";
		String doc_path = "D:\\11.docx";
		String img_path = "E:\\apache-tomcat-8.0.30\\webapps\\jeefh\\fh\\doc\\pageoffice\\img\\jsk.png";
		new CustomXWPFDocument().runText("PO_user_name1",doc_path, "d");//书签替换内容
		new CustomXWPFDocument().runImg("PO_user_name1",doc_path, img_path, true, 100, 100, 0, 0);//书签替换图片
//		new CustomXWPFDocument().runText("PO_user_name2",doc_path, "              bb");//书签替换内容
//		new CustomXWPFDocument().runImg("PO_user_name2",doc_path, img_path, true, 100, 100, 80, 0);//书签替换图片
//		new CustomXWPFDocument().runText("PO_user_name3",doc_path, "              cc");//书签替换内容
//		new CustomXWPFDocument().runImg("PO_user_name3",doc_path, img_path, true, 100, 100, 160, 0);//书签替换图片
	}

	/**
	 * @param name 书签名
	 * @param doc_path word路径
	 * @param text 替换的内容
	 */
	public void runText(String name,String doc_path,String text) {
		CustomXWPFDocument document = null;
		try {
			document = new CustomXWPFDocument(new FileInputStream(doc_path));
			Iterator it = document.getTablesIterator();//获取所有表格
			boolean flag = false;
			while(it.hasNext()){
				XWPFTable table = it.next();
				List rows = table.getRows();//每一行数据
				for (XWPFTableRow row : rows) {
					List cells = row.getTableCells();//每一列数据
					for (XWPFTableCell cell : cells) {
						List paragraphs = cell.getParagraphs();
						flag = document.setText(document, paragraphs,name,text);
						if (flag) {
							break;
						}
					}
					if (flag) {
						break;
					}
				}
				if (flag) {
					break;
				}
			}
			List list = document.getParagraphs();//获取所有段落
			if (!flag) {//表格里没找到需要的书签,段落里接着找
				document.setText(document, list,name,text);
			}
			FileOutputStream fos = new FileOutputStream(doc_path);
			document.write(fos);
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}catch (InvalidFormatException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 * @param document
	 * @param paragraphs 所有段落
	 * @param name 书签名
	 * @param text 替换的内容
	 * @return boolean
	 * @throws InvalidFormatException
	 * @throws FileNotFoundException
	 */
	private boolean setText(CustomXWPFDocument document, List paragraphs,String name,String text) throws InvalidFormatException, FileNotFoundException {
		boolean flag = false;
		for (XWPFParagraph paragraph : paragraphs) {//遍历段落
			List bookmarkStartList = paragraph.getCTP().getBookmarkStartList();//当前段落里的所有书签
			for (CTBookmark bookmark : bookmarkStartList) {//遍历当前段落里的所有书签
				String bookmarkName = bookmark.getName();
				if (name.equals(bookmarkName)) {//找到需要的书签
					XWPFRun run = paragraph.createRun();//创建run
					run.setText(text);
					return true;
				}
			}
		}
		return flag;
	}

	/**
	 * @param name 书签名
	 * @param doc_path word路径
	 * @param img_path 图片路径
	 * @param behindDoc 是否浮于文字上方 true是浮于,false是不浮
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param leftOffset 图片水平偏移:负数向左,正数向右
	 * @param topOffset 图片垂直偏移:负数向上,正数向下
	 */
	public void runImg(String name,String doc_path,String img_path,boolean behindDoc,int width, int height,int leftOffset, int topOffset) {
		CustomXWPFDocument document = null;
		try {
			document = new CustomXWPFDocument(new FileInputStream(doc_path));
			Iterator it = document.getTablesIterator();//获取所有表格
			boolean flag = false;
			while(it.hasNext()){
				XWPFTable table = it.next();
				List rows = table.getRows();//每一行数据
				for (XWPFTableRow row : rows) {
					List cells = row.getTableCells();//每一列数据
					for (XWPFTableCell cell : cells) {
						List paragraphs = cell.getParagraphs();
						flag = document.setPicture(document, paragraphs,name,img_path,behindDoc,width,height,leftOffset,topOffset);
						if (flag) {
							break;
						}
					}
					if (flag) {
						break;
					}
				}
				if (flag) {
					break;
				}
			}
			List list = document.getParagraphs();//获取所有段落
			if (!flag) {//表格里没找到需要的书签,段落里接着找
				document.setPicture(document, list,name,img_path,behindDoc,width,height,leftOffset,topOffset);
			}
			FileOutputStream fos = new FileOutputStream(doc_path);
			document.write(fos);
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}catch (InvalidFormatException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 * @param document
	 * @param paragraphs 所有段落
	 * @param name 书签名
	 * @param img_path 图片路径
	 * @param behindDoc 是否浮于文字上方 true是浮于,false是不浮
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param leftOffset 图片水平偏移:负数向左,正数向右
	 * @param topOffset 图片垂直偏移:负数向上,正数向下
	 * @return boolean
	 * @throws InvalidFormatException
	 * @throws FileNotFoundException
	 */
	private boolean setPicture(CustomXWPFDocument document, List paragraphs,String name,String img_path,boolean behindDoc,int width, int height,
							   int leftOffset, int topOffset) throws InvalidFormatException, FileNotFoundException {
		boolean flag = false;
		for (XWPFParagraph paragraph : paragraphs) {//遍历段落
			List bookmarkStartList = paragraph.getCTP().getBookmarkStartList();//当前段落里的所有书签
			for (CTBookmark bookmark : bookmarkStartList) {//遍历当前段落里的所有书签
				String bookmarkName = bookmark.getName();
				if (name.equals(bookmarkName)) {//找到需要的书签
					XWPFRun run = paragraph.createRun();//创建run
					String picId = document.addPictureData(new FileInputStream(img_path), XWPFDocument.PICTURE_TYPE_PNG);
					document.addPictureToRun(run, picId, document.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), width, height);//把图片添加到创建的run中
					//设置图片浮于文字上方
					if (behindDoc) {
						CTDrawing drawing = run.getCTR().getDrawingArray(0);
						CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
						//拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
						CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "11",
								Units.toEMU(width), Units.toEMU(height),//图片大小
								Units.toEMU(leftOffset), Units.toEMU(topOffset));//相对当前段落位置的偏移位置,左右偏移:负数向左,正数向右,上下偏移:负数向上,正数向下
						drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
						drawing.removeInline(0);//删除行内属性
					}
					return true;
				}
			}
		}
		return flag;
	}

	/**
	 * @param ctGraphicalObject 图片数据
	 * @param deskFileName      图片描述
	 * @param width             宽
	 * @param height            高
	 * @param leftOffset        水平偏移:负数向左,正数向右
	 * @param topOffset         垂直偏移:负数向上,正数向下
	 * @return CTAnchor
	 * @throws Exception
	 */
	public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
												String deskFileName, int width, int height,
												int leftOffset, int topOffset) {
		//浮在文字上的设置主要是anchor标签下的behindDoc属性设为0,同时添加一个的空标签。
		if (StringUtils.isBlank(deskFileName)) {
			deskFileName = new Random().nextInt(999) + "";//描述不能为空,赋值一个随机数
		}
		String anchorXML =
				""
						+ ""
						+ ""
						+ "" + leftOffset + ""
						+ ""
						+ ""
						+ "" + topOffset + "" +
						""
						+ ""
						+ ""
						+ ""
						+ ""
						+ "";
		CTDrawing drawing = null;
		try {
			drawing = CTDrawing.Factory.parse(anchorXML);
		} catch (XmlException e) {
			e.printStackTrace();
		}
		CTAnchor anchor = drawing.getAnchorArray(0);
		anchor.setGraphic(ctGraphicalObject);
		return anchor;
	}

}

六、用到的相关jar包maven

		
			org.apache.poi
			poi
			3.9
		
		
			org.apache.poi
			poi-examples
			3.9
		
		
			org.apache.poi
			poi-ooxml
			3.9
		
		
			org.apache.poi
			poi-ooxml-schemas
			3.9
		
		
			org.apache.poi
			ooxml-schemas
			1.1
		
		
			org.apache.xmlbeans
			xmlbeans
			2.6.0
		
		
			org.apache.poi
			poi-scratchpad
			3.9
		

 

你可能感兴趣的:(java poi给word(2007及以上)的书签动态替换文字、图片(可浮于文字上方))