java使用poi操作word模板,插入图片、段落、表格

其他链接

java使用poi操作world生成饼图,柱状图,折线图,组合图:一
java使用poi操作world生成饼图,柱状图,折线图,组合图:二
问题链接

准备工作

创建word模板.docx文件

使用模板操作,因为自己使用poi去写word过于麻烦,耦合性太高
在这里插入图片描述

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

编写模板格式.xml文件

创建的.docx文件顺序基本是乱的,需要另存为.xml格式手动更改格式
在这里插入图片描述
用编译器打开(我用的IDEA)找到要替换的占位符的位置

在这里插入图片描述

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

在这里插入图片描述
以此类推改完所有替换内容的标识

改完之后在改成.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);
                }
            }
        }
    }
    /**
     * 判断文本中是否包含$
     *
     * @param text 文本
     * @return 包含返回true, 不包含返回false
     */
    public static boolean checkText(String text) {
        boolean check = false;
        if (text.indexOf("$") != -1) {
            check = true;
        }
        return check;
    }
    /**
     * 替换模板${}
     */
    private static Object changeValue(String value, Map<String, Object> textMap) {
		Set<Map.Entry<String, Object>> textSets = textMap.entrySet();
		Object valu = "";
		for (Map.Entry<String, Object> textSet : textSets) {
			// 匹配模板与替换值 格式${key}
			String key = textSet.getKey();
			if (value.contains(key)) {
				valu = textSet.getValue();
			}
		}
		return valu;
	}

效果图

在这里插入图片描述

如果想设置单独的样式

比如加颜色、居中等,要确保.xml中替换单位为一行
在这里插入图片描述
效果
在这里插入图片描述

  • 19
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
使用JavaPOI操作.doc Word模板替换并循环插入表格的步骤如下: 1. 导入POI库的相关依赖,例如Apache POI和Apache POI-OOXML。 2. 创建一个Word文档(.docx),该文档将作为模板使用。 3. 使用Apache POI的XWPFDocument类加载模板文档。 ```java XWPFDocument doc = new XWPFDocument(new FileInputStream("template.docx")); ``` 4. 声明一个XWPFTable对象,用于向文档中插入表格。 ```java XWPFTable table; ``` 5. 使用XWPFDocument类的getTables()方法获取文档中的所有表格,通常一个模板只有一个表格。 ```java List<XWPFTable> tables = doc.getTables(); table = tables.get(0); // 假设我们要操作表格是第一个表格 ``` 6. 使用XWPFTable对象的removeRow()方法删除表格中的所有行,这样就可以将模板中的行删除,以便后面插入新的行。 ```java for (int i = table.getRows().size() - 1; i > 0; i--) { table.removeRow(i); } ``` 7. 使用XWPFTable对象的createRow()方法创建新的行,并使用XWPFTableRow对象的createCell()方法创建单元格。 ```java for (int i = 0; i < data.size(); i++) { XWPFTableRow newRow = table.createRow(); // 将data中的数据添加到新行的单元格中 for (int j = 0; j < data.get(i).size(); j++) { XWPFTableCell newCell = newRow.getCell(j); newCell.setText(data.get(i).get(j)); } } ``` 8. 将替换完表格的文档保存为新的文档。 ```java FileOutputStream out = new FileOutputStream("output.docx"); doc.write(out); out.close(); ``` 这样,你就可以使用JavaPOI操作.doc Word模板,替换表格并循环插入新的表格了。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值