欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java使用poi操作word

程序员文章站 2024-03-25 14:08:58
...

准备工作

创建word模板.docx文件

使用模板操作,因为自己使用poi去写word过于麻烦,耦合性太高
java使用poi操作word

${XXX}理解成占位符,会替换为填充的数据,可配置为其他比如*{xxx}*

编写模板格式.xml文件

创建的.docx文件顺序基本是乱的,需要另存为.xml格式手动更改格式
java使用poi操作word
用编译器打开(我用的IDEA)找到要替换的占位符的位置

java使用poi操作word

把所有要替换的位置都找到改为一行

java使用poi操作word
以此类推改完所有替换内容的标识

改完之后在改成.docx格式

java上手poi

maven依赖

        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.16</version>
        </dependency>

使用到的包

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

具体应用

	/**
     * 读取模板
     * @param HttpServletResponse 
     * @throws Exception
     */
public void operatorWord(HttpServletResponse response) throws Exception {
	//获得模板文件
	InputStream docis = new FileInputStream("C:\Users\16630\Desktop\模板A.docx");
	//转成word
	CustomXWPFDocument document = new CustomXWPFDocument(docis);
	//写入图片
	this.insertImage(document);
	//写入表格
	this.insertTable(document);
	//段落替换对象
	this.insertText(document)
    //把doc输出到输出流
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/msword");
    //文件名
    String fileName = "考试成绩分析" + htmlDataTime.getStartData();
    response.setHeader("Content-Disposition", "attachment;fileName="+ new String(fileName.getBytes("UTF-8"),"ISO-8859-1"));
    ServletOutputStream responseOutputStream = response.getOutputStream();
    document.write(responseOutputStream);
    responseOutputStream.flush();
    responseOutputStream.close();
    in.close();
	
}

对应封装方法 ----------图片插入指定位置操作

	/**
     * 写入图片在word中
     * @param document
     * @throws IOException
     * @throws InvalidFormatException
     */
    private void insertImage(CustomXWPFDocument document) throws IOException, InvalidFormatException {
    	//图片
    	FileInputStream in = new FileInputStream(new("C:\Users\16630\Desktop\image.jpg"));
        //段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            //获取到段落中的所有文本内容
            String text = paragraph.getText();
            //判断此段落中是否有需要进行替换的文本
            if (WordUtil.checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    String key = "${image}";
                    if (run.toString().indexOf(key) != -1) {
                        byte[] ba = new byte[in.available()];
                        int len = in.read(ba);
                        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(ba, 0, len);
                        //设置图片
                        document.addPictureData(byteInputStream, XWPFDocument.PICTURE_TYPE_PNG);
                        //创建一个word图片,并插入到文档中-->像素可改
                        document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
                    }
                    break;
                }
                break;
            }
        }
    }

图片操作使用到的工具类


/**
 * @author BM_hyjw
 */
import java.io.IOException;
import java.io.InputStream;
 
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
 
public class CustomXWPFDocument extends XWPFDocument{
	public CustomXWPFDocument(InputStream in) throws IOException {
		super(in);
	}
 
	public CustomXWPFDocument() {
		super();
	}
 
	public CustomXWPFDocument(OPCPackage pkg) throws IOException {
		super(pkg);
	}
 
	/**
	 * @param id
	 * @param width
	 *            宽
	 * @param height
	 *            高
	 * @param paragraph
	 *            段落
	 */
	public void createPicture(int id, int width, int height,
			XWPFParagraph paragraph) {
		final int EMU = 9525;
		width *= EMU;
		height *= EMU;
		String blipId = super.getRelationId(super.getAllPictures().get(id));
		CTInline inline = paragraph.createRun().getCTR().addNewDrawing()
				.addNewInline();
		String picXml = ""
				+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
				+ "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
				+ "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
				+ "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""
				+ id
				+ "\" name=\"Generated\"/>"
				+ "            <pic:cNvPicPr/>"
				+ "         </pic:nvPicPr>"
				+ "         <pic:blipFill>"
				+ "            <a:blip r:embed=\""
				+ blipId
				+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
				+ "            <a:stretch>"
				+ "               <a:fillRect/>"
				+ "            </a:stretch>"
				+ "         </pic:blipFill>"
				+ "         <pic:spPr>"
				+ "            <a:xfrm>"
				+ "               <a:off x=\"0\" y=\"0\"/>"
				+ "               <a:ext cx=\""
				+ width
				+ "\" cy=\""
				+ height
				+ "\"/>"
				+ "            </a:xfrm>"
				+ "            <a:prstGeom prst=\"rect\">"
				+ "               <a:avLst/>"
				+ "            </a:prstGeom>"
				+ "         </pic:spPr>"
				+ "      </pic:pic>"
				+ "   </a:graphicData>" + "</a:graphic>";
 
		inline.addNewGraphic().addNewGraphicData();
		XmlToken xmlToken = null;
		try {
			xmlToken = XmlToken.Factory.parse(picXml);
		} catch (XmlException xe) {
			xe.printStackTrace();
		}
		inline.set(xmlToken);
 
		inline.setDistT(0);
		inline.setDistB(0);
		inline.setDistL(0);
		inline.setDistR(0);
 
		CTPositiveSize2D extent = inline.addNewExtent();
		extent.setCx(width);
		extent.setCy(height);
 
		CTNonVisualDrawingProps docPr = inline.addNewDocPr();
		docPr.setId(id);
		docPr.setName("图片名称");
		docPr.setDescr("描述信息");
	}
}

对应封装方法 ----------表格操作

    private void insertTable(CustomXWPFDocument document) {
        //创建表格接受参数-->外层list是行内层是列
        List<List<String>> tableList = new ArrayList();

        List<String> cells = new ArrayList<>();
        cells.add("1");
        cells.add("张三");
        cells.add("100");
        tableList.add(cells);
        List<String> cellList = new ArrayList<>();
        cellList.add("2");
        cellList.add("李四");
        cellList.add("10");
        tableList.add(cellList);
        //获取表格位置
        List<XWPFTable> tables = document.getTables();
        WordUtil.insertTable(tables.get(0),tableList);
    }

表格操作用到的工具类

    /**
     * 为表格插入数据,行数不够添加新行
     *
     * @param table     需要插入数据的表格
     * @param tableList 插入数据集合
     */
    public static void insertTable(XWPFTable table, List<List<String>> tableList) {
        //创建行,根据需要插入的数据添加新行,不处理表头
        for (int i = 1; i <= tableList.size(); i++) {
            table.createRow();
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1; i < rows.size(); i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                cell.setText(tableList.get(i - 1).get(j));
                //表格样式一致-->没有此段表格会默认左对齐
                //有此段会使表格格式一致
                CTTc cttc = cell.getCTTc();
                CTTcPr ctPr = cttc.addNewTcPr();
                ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
            }
        }
    }

对应封装方法 ----------段落内容替换操作

    private void insertText(CustomXWPFDocument document) {
        //声明替换模板对象
		Map textMap = new HashMap();
		textMap.put("${maxName}","张三");
        textMap.put("${maxScore}", "100");
        textMap.put("${minName}","李四");
        textMap.put("${minScore}", "10");
        //替换模板数据
        WordUtil.changeText(document,textMap);
    }

段落内容操作用到的工具类

        /**
     * 替换段落文本
     *
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeText(XWPFDocument document, Map<String, Object> textMap) {
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            //获取到段落中的所有文本内容
            String text = paragraph.getText();
            //判断此段落中是否有需要进行替换的文本
            if (checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    run.setText(changeValue(run.toString(), textMap), 0);
                }
            }
        }
    }

效果图

java使用poi操作word

如果想设置单独的样式

比如加颜色、居中等,要确保.xml中替换单位为一行
java使用poi操作word
效果
java使用poi操作word