使用poi根據模版生成word文檔,支持插入圖片,複製表格,插入、循環插入數據,繼承模板大部分格式及樣式(優化版)

一、製作word模版,${xxxx}是一會要替換的內容,最下面的表格是要插入數據,根據是否以$開頭來判斷是需要替換還是插入數據,

  • 注意如果是需要循環插入數據,製作的表格模版需要一行全部輸入井號#,格式樣式可以對#設置
  • 表格中${header}和${hearder2}是放入需要替換的圖片
  • 替換數據的格式樣式同$的一樣
  • 如果需要根據數據再確定需要在哪替換圖片,可以使用帶ImgAgain的方法,原理是數據先替換爲*{}佔位符,再替換一遍
  • 一些設置參數,看getWord方法參數
  • 支持:段落插表格(有兩個插入表格的方法)
  • 支持公式:看六,得具體分析
  • 不支持特殊格式:如上下標、雙行合一等
  • 複製表格時及循環插入不支持特殊樣式:如高亮、藝術字體、快速樣式(複製表格,循環時無法複製高亮樣式)等
  • 複製表格時,若字體原來爲默認五號,則複製是變爲10號字體,應爲10.5,但只支持傳整數 :(
  • 表格中特殊符號:#、$、{、}、,使用時需注意,在循環插入數據的單元格內 [ ] 中括號也是特殊符號
  • 循環插數據的表格列數支持多或少;支持調換列的順序
  • 循環插數據的表格行中每個單元格都要有#
  • 在循環單元格內允許有多個段落,單插入數據的段落需是單獨段落,且#號開頭
  • 循環插數據的以#開頭,後面跟 [ ] ,裏面寫數據順序的序號(注意第一列是以零0開頭),若按默認循序則不用加 [ ] ,若在數據長度內的單元格又不想填數據則中括號沒填-1及 [-1]
  • 循環插數據的數據格式樣式同#,所以模板可以自定義#格式樣式

循環數據行舉例:

結果:

下面是測試模板

二、添加poi所需要的jar包文件,我用的maven對jar包進行管理

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.15</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-scratchpad</artifactId>
	<version>3.15</version>
</dependency>

三、由於poi自身bug,會出現圖片無法顯示問題,這裏需要自定義一個類繼承XWPFDocument類,接下來使用的都是我們自己創建的這個類來操作word對象,這個

  類對XWPFDocument進行了繼承,所以不用擔心會有什麼問題

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;
import java.io.IOException;
import java.io.InputStream;

/******************************************* 
 *
 * @Package com.cccuu.project.myUtils
 * @Author duan
 * @Date 2018/3/29 17:55
 * @Version V1.0
 *******************************************/
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 = getAllPictures().get(id).getPackageRelationship().getId();
        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("圖片"+ id);
        docPr.setDescr("測試");
        }
}

四、接下來就是導出word的工具類了

import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <b> 通過word模板生成新的word工具類
 * </b><br><br><i>Description</i> :
 * <br><br>Date: 2019/12/9 ${time}    <br>Author : dxl
 */
public class WordGrtUtil {
    public static void main(String[] args) throws Exception {
//        wordGrtUtil.copyTbaleByLoop("C:\\Users\\00\\Desktop\\baogao\\testmodel.docx",0,4,"C:\\Users\\00\\Desktop\\baogao\\testmodel-copy.docx");
//        WordGrtUtil wordGrtUtil=new WordGrtUtil();
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("${position}", "*{aaa}");
        params.put("${name}", "222段然濤222");
        params.put("${sex}", "男");
        params.put("${national}", "漢族");
        params.put("${birthday}", "生日");
        params.put("${address}", "許昌");
        params.put("${height}", "165cm");
        params.put("${biYeDate}", "1994-02-03");
        params.put("${landscape}", "團員");
        params.put("${zhuanYe}", "社會工作");
        params.put("${xueLi}", "本科");
        params.put("${school}", "江西科技師範大學");
        params.put("${phone}", "177");
        params.put("${eMail}", "157");

        try{
            Map<String,Object> header = new HashMap<String, Object>();
            header.put("width", 50);
            header.put("height", 50);
            header.put("type", "jpg");
            header.put("content", inputStream2ByteArray(new FileInputStream("C:\\Users\\00\\Desktop\\baogao\\tupian\\垂直度.jpg"), true));
            params.put("${tihuan}",header);
            params.put("*{aaa}",header);
//            Map<String,Object> header2 = new HashMap<String, Object>();
//            header2.put("width", 100);
//            header2.put("height", 150);
//            header2.put("type", "jpg");
//            header2.put("content", WordUtils.inputStream2ByteArray(new FileInputStream("C:/Users/Administrator/Desktop/jar包/22.jpg"), true));
//            params.put("${header2}",header2);
            List<String[]> testList = new ArrayList<String[]>();
            testList.add(new String[]{"1","1AA","1BB","1CC"});
            testList.add(new String[]{"2","2AA","2BB","2CC"});
            testList.add(new String[]{"3","3AA","3BB","3CC"});
            testList.add(new String[]{"4","4AA","4BB","4CC"});
            String modelPath="C:\\Users\\00\\Desktop\\baogao\\testmodel3.docx";  //模板文件位置
            String stroePath="C:\\Users\\00\\Desktop\\baogao\\aaaa.docx";  //模板文件位置
            String fileName= new String("測試文檔.docx".getBytes("UTF-8"),"iso-8859-1");    //生成word文件的文件名
            List<List<Integer>> mergeRowLists = new ArrayList<>();
            WordGrtUtil.getWordStore(modelPath,params,testList,stroePath,false,0,2,false,null);
//            wordGrtUtil.getWord(path,params,testList,fileName);


        }catch(Exception e){
            e.printStackTrace();
        }

    }
    /**
     * 根據模板生成word 並存儲
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要循環插入的參數
     * @param storePath 生成的word文件存儲路徑,包含文件名全稱
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     * @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordStore(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInPara(doc, params);    //替換文本里面的變量
            OutputStream os =  new FileOutputStream(storePath);
            doc.write(os);
            close(os);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInPara(doc, params);    //替換文本里面的變量
            OutputStream os =  new FileOutputStream(storePath);
            doc.write(os);
            close(os);
            close(is);
        }
    }
    /**
     * 根據模板生成word 不存儲直接下載
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要插入的參數
     * @param fileName 生成word文件的文件名
     * @param response
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     * @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordDown(String srcPath, Map<String, Object> params, List<String[]> tableList, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInPara(doc, params);    //替換文本里面的變量
            OutputStream os = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(os);
            close(os);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInPara(doc, params);    //替換文本里面的變量
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            OutputStream os = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(os);
            close(os);
            close(is);
        }
    }
    /**
     * 根據模板生成word 存儲並下載
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要插入的參數
     * @param fileName 生成word文件的文件名
     * @param response
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     * @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordStoreAndDown(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInPara(doc, params);    //替換文本里面的變量
            OutputStream oss =  new FileOutputStream(temPath);
            OutputStream osd = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(oss);
            doc.write(osd);
            close(oss);
            close(osd);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInPara(doc, params);    //替換文本里面的變量
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            OutputStream oss =  new FileOutputStream(storePath);
            OutputStream osd = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(oss);
            doc.write(osd);
            close(oss);
            close(osd);
            close(is);
        }
    }

    /**
     * 根據模板生成word 並存儲
     * 因爲有的地方替換圖片不確定,先替換成其他佔位符,在替換掉
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要循環插入的參數
     * @param storePath 生成的word文件存儲路徑,包含文件名全稱
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     *  @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordStoreImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            OutputStream os =  new FileOutputStream(storePath);
            doc.write(os);
            close(os);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            OutputStream os =  new FileOutputStream(storePath);
            doc.write(os);
            close(os);
            close(is);
        }
    }
    /**
     * 根據模板生成word 不存儲直接下載
     * 因爲有的地方替換圖片不確定,先替換成其他佔位符,在替換掉
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要插入的參數
     * @param fileName 生成word文件的文件名
     * @param response
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     *  @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordDownImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            OutputStream os = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(os);
            close(os);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            OutputStream os = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(os);
            close(os);
            close(is);
        }
    }
    /**
     * 根據模板生成word 存儲並下載
     * 因爲有的地方替換圖片不確定,先替換成其他佔位符,在替換掉
     * @param srcPath     模板的路徑
     * @param params   需要替換的參數
     * @param tableList   需要插入的參數
     * @param fileName 生成word文件的文件名
     * @param response
     * @param isCopyTable 是否需要循環複製表格,
     * @param copyTableIndex 複製第幾個表格,若copyTable爲false,後兩個參數隨便填
     * @param copyTableNum  複製幾個表格
     * @param isMergeRow  是否自動合併行
     * @param mergeRowLists    List<Integer>應包含三個,第一個爲要合併的列,第二個合併的起始行,第三個合併的結束行
     */
    public static void getWordStoreAndDownImgAgain(String srcPath, Map<String, Object> params, List<String[]> tableList, String storePath, String fileName, HttpServletResponse response,boolean isCopyTable,int copyTableIndex,int copyTableNum,boolean isMergeRow,List<List<Integer>> mergeRowLists) throws Exception {
        fileName= new String(fileName.getBytes("UTF-8"),"iso-8859-1");
        File file = new File(srcPath);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(isCopyTable){
            String temPath = file.getParentFile()+"/tem"+System.currentTimeMillis()+file.getName();
            copyTbaleByLoop(srcPath,copyTableIndex,copyTableNum,temPath);
            File fileTem = new File(temPath);
            InputStream is = new FileInputStream(fileTem);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            OutputStream oss =  new FileOutputStream(temPath);
            OutputStream osd = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(oss);
            doc.write(osd);
            close(oss);
            close(osd);
            close(is);
            File fileDel = new File(temPath);
            if(fileDel.exists()){
                fileDel.delete();
            }
        }else {
            InputStream is = new FileInputStream(file);
            CustomXWPFDocument doc = new CustomXWPFDocument(is);
            replaceInParaImgAgain(doc, params);    //替換文本里面的變量
            replaceInTable(doc, params,tableList,isMergeRow,mergeRowLists); //替換表格裏面的變量
            OutputStream oss =  new FileOutputStream(storePath);
            OutputStream osd = response.getOutputStream();
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            doc.write(oss);
            doc.write(osd);
            close(oss);
            close(osd);
            close(is);
        }
    }

    /**
    * <b> 循環複製Word中的表格
    * </b><br><br><i>Description</i> :
    * @param srcPath 模板路徑, srcTableIndex 模板中複製目標表格的下標, copyNum 複製個數, storePath 存儲路徑(包含文件名全稱)
    * @return void
    * <br><br>Date: 2019/12/9 13:21     <br>Author : dxl
    */
    public static void copyTbaleByLoop(String srcPath, int srcTableIndex,int copyNum,String storePath) throws Exception {
        File file = new File(srcPath);
        InputStream is = new FileInputStream(file);
        CustomXWPFDocument doc = new CustomXWPFDocument(is);
        XWPFTable sourceTable = doc.getTableArray(srcTableIndex);
        for(int j = 0; j < copyNum; j++){
            XWPFTable tableOne = doc.createTable();
            for(int i = 0; i < sourceTable.getRows().size(); i++){
                copy(tableOne,sourceTable.getRow(i),i);
            }
            doc.createParagraph();
            tableOne.removeRow(tableOne.getRows().size()-1);
        }
        OutputStream os =  new FileOutputStream(storePath);

        doc.write(os);
        close(os);
        close(is);

    }

    /**
     * 替換段落裏面的變量
     * @param doc 要替換的文檔
     * @param params 參數
     */
    private static void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) throws IOException {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
//        List<XWPFParagraph> paragraphs = doc.getParagraphs();
//        for(int i = paragraphs.size()-1; i >= 0; i--){
//            replaceInPara(paragraphs.get(i), params, doc);
//            insertTableInParaFromAtherDoc("C:\\Users\\00\\Desktop\\baogao\\testmodel4.docx",0,doc,paragraphs.get(i),false);
//        }
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            replaceInPara(para, params, doc);
        }
    }
    /**
     * 替換段落裏面的變量
     * @param doc 要替換的文檔
     * @param params 參數
     */
    private static void replaceInParaImgAgain(CustomXWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            replaceInPara(para, params, doc);
            replaceImgAgain(para, params, doc);
        }
    }

    /**
     * 替換段落裏面的變量
     *
     * @param para   要替換的段落
     * @param params 參數
     */
    private static void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {
        List<XWPFRun> runs;
        Matcher matcher;
        if (matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();
            int start = -1;
            int end = -1;
            String str = "";
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                if ((runText.length() > 0 && runText.contains("${"))
                        || (runText.length() > 0 && '$' == runText.charAt(runText.length() - 1) && i+1 <runs.size() && '$' == runs.get(i+1).toString().charAt(0))) {
                    start = i;
                }
                if (runText.length() > 0 && runText.contains("}")) {
                    if (start != -1) {
                        end = i;
                        break;
                    }
                }
            }
            for(int i = start; i <= end; i++){
                str = str + runs.get(i).toString();
            }
            //去掉標識符開始之後到結束的run,保留第一個run是爲了使用run的樣式
            for (int i = start+1; i <= end; i++) {
                para.removeRun(i);
                i--;
                end--;
            }
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                if (str.indexOf(key) != -1) {
                    Object value = entry.getValue();
                    if (value instanceof String) {
                        str = str.replace(key, value.toString());
                        para.getRuns().get(start).setText(str,0);//替換保留的第一個run中的內容,若沒有0就變爲插入了
                        break;
                    } else if (value instanceof Map) {
                        str = str.replace(key, "");
                        Map pic = (Map) value;
                        int width = Integer.parseInt(pic.get("width").toString());
                        int height = Integer.parseInt(pic.get("height").toString());
                        int picType = getPictureType(pic.get("type").toString());
                        byte[] byteArray = (byte[]) pic.get("content");
                        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                        try {
                            //int ind = doc.addPicture(byteInputStream,picType);
                            //doc.createPicture(ind, width , height,para);
                            doc.addPictureData(byteInputStream, picType);
                            if(start == 0){
                                para.getRuns().get(0).setText("",0);
                                doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start);
                            }else {
                                para.removeRun(start);
                                doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start-1);
                            }
                            break;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        if (matcher(para.getParagraphText()).find()) {
            replaceInPara(para, params, doc);
        }
    }

    /**
     * 爲表格插入數據,行數不夠添加新行
     * 說明:當表格中出現一行中每一個單元格都爲'#'時,認爲需要循環插入
     * @param tableList 插入數據集合
     */
    private static void insertTable(XWPFTable table, List<String[]> tableList,boolean isMergeRow,List<List<Integer>> mergeRowLists) {
        int headRowNum = 0;
        int tailRowNum = 0;
        List<XWPFTableRow> rows = table.getRows();
        List<Integer> cellOrder = new ArrayList<>();
        for(int i = 0; i < rows.size(); i++){
            String flagHead = "";
            String flagFor = "";
            for(int j = 0; j < rows.get(i).getTableCells().size(); j++){
                String cellText = rows.get(i).getTableCells().get(j).getText().replace(" ","");
                if(cellText.length() > 0){
                    if(cellText.contains("#")){
                        flagHead = flagHead + "#";
                    }
                    if(cellText.contains("#[") && cellText.contains("]") && cellText.indexOf("]") > cellText.indexOf("[")+1
                            && cellOrder.size() < rows.get(i).getTableCells().size()){
                        cellOrder.add(Integer.valueOf(cellText.substring(cellText.indexOf("[")+1,cellText.indexOf("]"))));
                    }else if(cellText.contains("#")  && cellOrder.size() < rows.get(i).getTableCells().size()){
                        cellOrder.add(null);
                    }
                }
                //刪除循環單元格內多餘段落,不想單元格內有默認數據放開註釋
//                List<XWPFParagraph> paragraphs = rows.get(i).getTableCells().get(j).getParagraphs();
//                if(paragraphs.size() > 1){
//                    for(int k = paragraphs.size()-1; k >= 0; k--){
//                        if(!paragraphs.get(k).getText().contains("#")){
//                            rows.get(i).getTableCells().get(j).removeParagraph(k);
//                        }
//                    }
//                }
                //刪除循環單元格內要替換段落後的多餘run
                if(rows.get(i).getTableCells().get(j).getParagraphs().size() > 0){
                    for(XWPFParagraph paragraph : rows.get(i).getTableCells().get(j).getParagraphs()){
                        if(paragraph.getText().indexOf("#") == 0){
                            for(int k = paragraph.getRuns().size()-1; k > 0; k--){
                                paragraph.removeRun(k);
                            }
                        }
                    }
                }
                flagFor = flagFor + "#";
            }
            if(flagFor.equals(flagHead)){
                headRowNum = i;
                break;
            }
        }
        if(headRowNum > 0){
            tailRowNum = rows.size()- headRowNum - 1;
            //創建行,根據需要插入的數據添加新行,不處理表頭
            for (int i = 0; i < tableList.size(); i++) {
                copy(table,table.getRow(headRowNum),headRowNum+1+i);
            }
            //遍歷表格插入數據

            int length = table.getRows().size();
            for (int i = headRowNum; i < length - tailRowNum - 1; i++) {
                XWPFTableRow newRow = table.getRow(i);
                List<XWPFTableCell> cells = newRow.getTableCells();
                for (int j = 0; j < cells.size(); j++) {
                    XWPFTableCell cell = cells.get(j);
                    String s ="";
                    if(j < tableList.get(i - headRowNum).length){
                        if(cellOrder.get(j) != null && !cellOrder.get(j).equals(-1)){
                            s = tableList.get(i - headRowNum)[cellOrder.get(j)];
                        }else if(cellOrder.get(j) != null &&cellOrder.get(j).equals(-1)){
                            s = "";
                        }else {
                            s = tableList.get(i - headRowNum)[j];
                        }
                    }else if(cellOrder.get(j) != null && !cellOrder.get(j).equals(-1)){
                        s = tableList.get(i - headRowNum)[cellOrder.get(j)];
                    }
                    for(XWPFParagraph paragraph : cell.getParagraphs()){
                        if(paragraph.getText().contains("#")){
                            paragraph.getRuns().get(0).setText(s,0);
                        }
                    }
                }
            }
            table.removeRow(table.getRows().size()-1-tailRowNum);
            if(isMergeRow && mergeRowLists.size() > 0){
                for(List<Integer> listInts : mergeRowLists){
                    mergeCellsRow(table,listInts.get(0),listInts.get(1),listInts.get(2));
                }
            }
//            mergeCellsCol(table,1,2,3);

        }
    }

    /**
     * 替換表格裏面的變量
     * @param doc    要替換的文檔
     * @param params 參數
     */
    private static void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList,boolean isMergeRow,List<List<Integer>> mergeRowLists) {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
            if (table.getRows().size() > 1) {
                insertTable(table,tableList,isMergeRow,mergeRowLists);
                //判斷表格是需要替換還是需要插入,判斷邏輯有$爲替換,表格無$爲插入
//                if (matcher(table.getText()).find()) {
                    rows = table.getRows();
                    for (XWPFTableRow row : rows) {
                        cells = row.getTableCells();
                        for (XWPFTableCell cell : cells) {
                            paras = cell.getParagraphs();
                            for (XWPFParagraph para : paras) {
                                replaceInPara(para, params, doc);
                            }
                        }
                    }
            }
        }
    }

    /**
    * <b> 再次替換圖片
    * </b><br><br><i>Description</i> : 因爲有的地方替換圖片不確定,先替換成其他佔位符,在替換掉
    * @param para 要替換的段落
    * @param params 參數
    * @param doc 文檔
    * @return void
    * <br><br>Date: 2019/12/9 15:54     <br>Author : dxl
    */
    private static void replaceImgAgain(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {
        List<XWPFRun> runs;
        if (matcherStar(para.getParagraphText()).find()) {
            runs = para.getRuns();
            int start = -1;
            int end = -1;
            String str = "";
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                if ((runText.length() > 0 && runText.contains("*{"))
                        || (runText.length() > 0 && '*' == runText.charAt(runText.length() - 1) && i+1 <runs.size() && '$' == runs.get(i+1).toString().charAt(0))) {
                    start = i;
                }
                if (runText.length() > 0 && runText.contains("}")) {
                    if (start != -1) {
                        end = i;
                        break;
                    }
                }
            }
            for(int i = start; i <= end; i++){
                str = str + runs.get(i).toString();
            }
            //去掉標識符開始之後到結束的run,保留第一個run是爲了使用run的樣式
            for (int i = start+1; i <= end; i++) {
                para.removeRun(i);
                i--;
                end--;
            }
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                if (str.indexOf(key) != -1) {
                    Object value = entry.getValue();
                    if (value instanceof String) {
                        str = str.replace(key, value.toString());
                        para.getRuns().get(start).setText(str,0);//替換保留的第一個run中的內容,若沒有0就變爲插入了
                        break;
                    } else if (value instanceof Map) {
                        str = str.replace(key, "");
                        Map pic = (Map) value;
                        int width = Integer.parseInt(pic.get("width").toString());
                        int height = Integer.parseInt(pic.get("height").toString());
                        int picType = getPictureType(pic.get("type").toString());
                        byte[] byteArray = (byte[]) pic.get("content");
                        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                        try {
                            //int ind = doc.addPicture(byteInputStream,picType);
                            //doc.createPicture(ind, width , height,para);
                            doc.addPictureData(byteInputStream, picType);
                            if(start == 0){
                                para.getRuns().get(0).setText("",0);
                                doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start);
                            }else {
                                para.removeRun(start);
                                doc.createPicture(doc.getAllPictures().size() - 1, width, height, para,start-1);
                            }
                            break;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        if (matcher(para.getParagraphText()).find()) {
            replaceInPara(para, params, doc);
        }
    }
    /**
     * 正則匹配字符串
     *
     * @param str
     * @return
     */
    private static Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }
    /**
     * 正則匹配字符串
     *
     * @param str
     * @return
     */
    private static Matcher matcherStar(String str) {
        Pattern pattern = Pattern.compile("\\*\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    /**
     * 根據圖片類型,取得對應的圖片類型代碼
     *
     * @param picType
     * @return int
     */
    private static int getPictureType(String picType) {
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
        if (picType != null) {
            if (picType.equalsIgnoreCase("png")) {
                res = CustomXWPFDocument.PICTURE_TYPE_PNG;
            } else if (picType.equalsIgnoreCase("dib")) {
                res = CustomXWPFDocument.PICTURE_TYPE_DIB;
            } else if (picType.equalsIgnoreCase("emf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_EMF;
            } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
            } else if (picType.equalsIgnoreCase("wmf")) {
                res = CustomXWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }

    /**
     * 將輸入流中的數據寫入字節數組
     *
     * @param in
     * @return
     */
    public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
        byte[] byteArray = null;
        try {
            int total = in.available();
            byteArray = new byte[total];
            in.read(byteArray);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (isClose) {
                try {
                    in.close();
                } catch (Exception e2) {
                    e2.getStackTrace();
                }
            }
        }
        return byteArray;
    }


    /**
     * 關閉輸入流
     *
     * @param is
     */
    private static void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 關閉輸出流
     *
     * @param os
     */
    private static void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
    * <b> 複製表格
    * </b><br><br><i>Description</i> :
    * @param table, sourceRow, rowIndex
    * @return void
    * <br><br>Date: 2019/12/9 13:23     <br>Author : dxl
    */
    public static void copy(XWPFTable table,XWPFTableRow sourceRow,int rowIndex){
        //在表格指定位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
        //複製行屬性
        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        List<XWPFTableCell> cellList = sourceRow.getTableCells();
        if (null == cellList) {
            return;
        }
        //複製列及其屬性和內容
        XWPFTableCell targetCell = null;
        for (XWPFTableCell sourceCell : cellList) {
            targetCell = targetRow.addNewTableCell();
            //處理一個單元格內有多個段落
            List<XWPFParagraph> paragraphs = sourceCell.getParagraphs();
            if(paragraphs.size() > 1){
                for(int i = 1; i < paragraphs.size(); i++){
                    targetCell.addParagraph();
                }
            }
            //列屬性
            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            //段落屬性
            if(sourceCell.getParagraphs()!=null&&sourceCell.getParagraphs().size()>0){
                for(int i = 0; i < sourceCell.getParagraphs().size();i++){
                    targetCell.getParagraphs().get(i).getCTP().setPPr(sourceCell.getParagraphs().get(i).getCTP().getPPr());
                    if(sourceCell.getParagraphs().get(i).getRuns()!=null&&sourceCell.getParagraphs().get(i).getRuns().size()>0){
                        for(int j = 0; j < sourceCell.getParagraphs().get(i).getRuns().size(); j++){
                            XWPFRun cellR = targetCell.getParagraphs().get(i).createRun();
                            cellR.setText(sourceCell.getParagraphs().get(i).getRuns().get(j).getText(0));
                            cellR.setBold(sourceCell.getParagraphs().get(i).getRuns().get(j).isBold());
                            cellR.setColor(sourceCell.getParagraphs().get(i).getRuns().get(j).getColor());
                            if(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontSize() == -1){
                                cellR.setFontSize(10);
                            }else {
                                cellR.setFontSize(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontSize());
                            }
                            cellR.setCapitalized(sourceCell.getParagraphs().get(i).getRuns().get(j).isCapitalized());
                            cellR.setDoubleStrikethrough(sourceCell.getParagraphs().get(i).getRuns().get(j).isDoubleStrikeThrough());
                            cellR.setEmbossed(sourceCell.getParagraphs().get(i).getRuns().get(j).isEmbossed());
                            cellR.setFontFamily(sourceCell.getParagraphs().get(i).getRuns().get(j).getFontFamily());
                            cellR.setImprinted(sourceCell.getParagraphs().get(i).getRuns().get(j).isImprinted());
                            cellR.setItalic(sourceCell.getParagraphs().get(i).getRuns().get(j).isItalic());
                            cellR.setKerning(sourceCell.getParagraphs().get(i).getRuns().get(j).getKerning());
                            cellR.setShadow(sourceCell.getParagraphs().get(i).getRuns().get(j).isShadowed());
                            cellR.setStrikeThrough(sourceCell.getParagraphs().get(i).getRuns().get(j).isStrikeThrough());
                            cellR.setSmallCaps(sourceCell.getParagraphs().get(i).getRuns().get(j).isSmallCaps());
                            cellR.setSubscript(sourceCell.getParagraphs().get(i).getRuns().get(j).getSubscript());
                            cellR.setTextPosition(sourceCell.getParagraphs().get(i).getRuns().get(j).getTextPosition());
                            cellR.setUnderline(sourceCell.getParagraphs().get(i).getRuns().get(j).getUnderline());
                        }
                    }else{
                        targetCell.setText(sourceCell.getText());
                    }
                }

            }else{
                targetCell.setText(sourceCell.getText());
            }
        }
    }
    /**
    * <b> 在段落中插入表格
    * </b><br><br><i>Description</i> : 表格單元格中建段落再插入表格,原段落會擠到下一個段落,用isDelNullPara控制刪除空原段落,
     * isDelNullPara爲true時要注意循環迭代,最好倒序循環para,插入表格後還有對para操作時也要注意,可能isDelNullPara要設爲false
    * @param sourceTable 要插入的源表格
     * @param targetDoc 要插入的文檔
     * @param  para 要插入表格的段落
     * @param  isDelNullPara 是否刪除para爲空是多出來的空段落
    * @return void
    * <br><br>Date: 2019/12/12 11:39     <br>Author : dxl
    */
    public static void insertTableInPara(XWPFTable sourceTable,CustomXWPFDocument targetDoc,XWPFParagraph para,boolean isDelNullPara){
        XmlCursor cursor = para.getCTP().newCursor();
        XWPFTable tableOne = targetDoc.insertNewTbl(cursor);
        for(int i = 0; i < sourceTable.getRows().size(); i++){
            copy(tableOne,sourceTable.getRow(i),i+1);
        }
        if(isDelNullPara){
            if(para.getText() != null && para.getText().length() > 0){
            }else {
                targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(para));
            }
        }
        tableOne.removeRow(0);
    }
    /**
     * <b> 在段落中插入表格--源表格來源於其他Word
     * </b><br><br><i>Description</i> : 表格單元格中建段落再插入表格,原段落會擠到下一個段落,用isDelNullPara控制刪除空原段落,
     * isDelNullPara爲true時要注意循環迭代,最好倒序循環para,插入表格後還有對para操作時也要注意,可能isDelNullPara要設爲false
     * @param srcPath 源表格所在源Word的路徑
     * @param tableIndex 源表格所在源Word中是第幾個,即下標
     * @param targetDoc 要插入的文檔
     * @param  para 要插入表格的段落
     * @param  isDelNullPara 是否刪除para爲空是多出來的空段落
     * @return void
     * <br><br>Date: 2019/12/12 11:39     <br>Author : dxl
     */
    public static void insertTableInParaFromAtherDoc(String srcPath,int tableIndex,CustomXWPFDocument targetDoc,XWPFParagraph para,boolean isDelNullPara) throws IOException {
        XmlCursor cursor = para.getCTP().newCursor();
        File file = new File(srcPath);
        InputStream is = new FileInputStream(file);
        CustomXWPFDocument srcDoc = new CustomXWPFDocument(is);
        XWPFTable sourceTable = srcDoc.getTableArray(tableIndex);
        XWPFTable tableOne = targetDoc.insertNewTbl(cursor);
        for(int i = 0; i < sourceTable.getRows().size(); i++){
            copy(tableOne,sourceTable.getRow(i),i+1);
            tableOne.removeRow(0);
        }
        if(isDelNullPara){
            if(para.getText() != null && para.getText().length() > 0){
            }else {
                targetDoc.removeBodyElement(targetDoc.getPosOfParagraph(para));
            }
        }
        close(is);
    }

    /**
     * @Description: 跨列合併
     */
    public static void mergeCellsCol(XWPFTable table, int row, int fromCell, int toCell) {
        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if ( cellIndex == fromCell ) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }
    /**
     * @Description: 跨行合併
     */
    public static void mergeCellsRow(XWPFTable table, int col, int fromRow, int toRow) {
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            if ( rowIndex == fromRow ) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

}

五、最後生成的word文檔

六、Word中公式解析(好似得具體公式具體分析)

6.1需要在上面依賴基礎上添加依賴

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>ooxml-schemas</artifactId>
	<version>1.4</version>
</dependency>

6.2以最簡單的公式爲例:

在WordGrtUtil中的代碼測試的

/**
     * 替換段落裏面的變量
     * @param doc 要替換的文檔
     * @param params 參數
     */
    private static void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            System.out.println(".........000.......:   "+para.getCTP().getOMathList());
            if(para.getCTP().getOMathList().size() > 0){
                System.out.println("..........111......:   "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getE().getRList().get(0).getT2List().get(0).getStringValue());
                System.out.println("........222........:   "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSub().getRList().get(0).getT2List().get(0).getStringValue());
                System.out.println("........333........:   "+para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).getStringValue());
                para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).setStringValue("www");
            }
            replaceInPara(para, params, doc);
        }
    }

6.3打印爲:

.........000.......:   []
.........000.......:   [<m:sSubSup xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
  <m:sSubSupPr>
    <m:ctrlPr>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
    </m:ctrlPr>
  </m:sSubSupPr>
  <m:e>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>a</m:t>
    </m:r>
  </m:e>
  <m:sub>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>n</m:t>
    </m:r>
  </m:sub>
  <m:sup>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>m</m:t>
    </m:r>
  </m:sup>
</m:sSubSup>, <m:sSubSup xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
  <m:sSubSupPr>
    <m:ctrlPr>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
    </m:ctrlPr>
  </m:sSubSupPr>
  <m:e>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>b</m:t>
    </m:r>
  </m:e>
  <m:sub>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>y</m:t>
    </m:r>
  </m:sub>
  <m:sup>
    <m:r>
      <w:rPr>
        <w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math"/>
      </w:rPr>
      <m:t>x</m:t>
    </m:r>
  </m:sup>
</m:sSubSup>]
..........111......:   a
........222........:   n
........333........:   m
.........000.......:   []

6.4分析:

  1. 第二個000行打印爲有公式時的集合(兩個),第一和第三000爲空 [ ];
  2. 公式是以<m:sSubSup 開頭的,所以 para.getCTP().getOMathList() 之後要拿到 SSubSup 集合,對應爲如 para.getCTP().getOMathList().get(0).getSSubSupList() ;
  3. 可以看到公式中的 “a” 在<m:sSubSup 標籤下三層標籤<m:e>  <m:r> <m:t> 中,獲得每一層都有對應的方法,如getE().getRList().get(0).getT2List() ,其中有的方法返回是集合有的不是;
  4. 拿到<m:t> 後就可以拿到具體的公式中的值了(a),如getE().getRList().get(0).getT2List().get(0).getStringValue() ;
  5.   111輸出打印的就是..........111......:   a
  6. 同理 上標 “m” 在<m:sup>   <m:r> <m:t> 標籤中,getSup().getRList().get(0).getT2List().get(0).getStringValue() 拿到 “ m”值;
  7. 同理拿到 “n”的值;
  8. 注意:每個標籤都有對應的獲取方法,通常應爲標籤中冒號後字符的對應如<m:sup> 對應 getSup(),  <m:r> 對應getRList();
  9. 改變值時使用getStringValue() 對應的 setStringValue() 即可,如:para.getCTP().getOMathList().get(0).getSSubSupList().get(0).getSup().getRList().get(0).getT2List().get(0).setStringValue("www");
  10. 新建公式是,應該是按照這個標籤層層新增,方法以 add 開頭,每個標籤都有對應的方法,對應關係應該同 8;
     

    6.5修改結果

     

    七、段落(單元格)插入表格

    7.1原word

7.2另外word制定表格

7.3插入表格

在方法replaceInPara中遍歷段落時使用insertTableInParaFromAtherDoc方法插入7.2中的表格;具體解釋看方法註釋

結果如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章