首页 > 其他分享 >根据模板动态生成word(二)使用poi生成word

根据模板动态生成word(二)使用poi生成word

时间:2023-07-10 20:13:29浏览次数:41  
标签:word String java textMap poi 生成 org import public

@

目录

一、准备模板

1、创建模板文件

创建一个word文件,输入如下图所示的内容:
请添加图片描述

二、代码实践

1、引入依赖

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

2、自定义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;

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("描述信息");
    }
}

2、公用的方法和变量

	private final String REGEX = "\\$\\{(.+?)\\}";

    private CustomXWPFDocument document;

    public PoICreateWordFactory(String templatePath) throws IOException {
        loadTemplate(templatePath);
    }

    /**
     * 加载模板
     *
     * @param templatePath 模板路径
     * @return 包含返回true, 不包含返回false
     */
    private void loadTemplate(String templatePath) throws IOException {
        try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
            //转成word
            this.document = new CustomXWPFDocument(in);
        }
    }

    /**
     * 生成word
     *
     * @param targetFile word生成路径
     * @return 包含返回true, 不包含返回false
     */
    public void createWordFile(String targetFile) throws IOException {
        try (FileOutputStream out = new FileOutputStream(targetFile)){
            document.write(out);
        }
    }

    /**
     * 判断文本中是否包含$
     *
     * @param text 文本
     * @return 包含返回true, 不包含返回false
     */
    public boolean checkText(String text) {
        boolean check = false;
        if (text.indexOf("$") != -1) {
            check = true;
        }
        return check;
    }

3、工具类引用的包名

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

4、段落文本替换

	/**
     * 替换段落文本
     *
     * @param textMap(数据源)
     */
    public void replaceText(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) {
                    //替换模板原来位置
                    Pattern pattern = Pattern.compile(REGEX);
                    Matcher matcher = pattern.matcher(run.toString());
                    if (matcher.find()) {
                        String key = matcher.group(1);
                        if(textMap.containsKey(key)){
                            run.setText(String.valueOf(textMap.get(key)), 0);
                        }
                    }
                }
            }
        }
    }

5、图片替换

	/**
     * 替换图片
     *
     * @param imageMap(数据源)
     */
    public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
        //段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
        for (XWPFParagraph paragraph : paragraphs) {
            //获取到段落中的所有文本内容
            String text = paragraph.getText();
            //判断此段落中是否有需要进行替换的文本
            if (checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    Pattern pattern = Pattern.compile(REGEX);
                    String runText = run.toString();
                    Matcher matcher = pattern.matcher(runText);
                    if (matcher.find()) {
                        String key = matcher.group(1);
                        if(imageMap.containsKey(key)){
                            //清空原有内容
                            run.setText("", 0);
                            //设置图片
                            document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
                            //创建一个word图片,并插入到文档中-->像素可改
                            document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
                            break;
                        }
                    }
                }
            }
        }
    }

6、表格替换

	/**
     * 替换表格内容
     *
     * @param index(表格索引:第几个表格)
     * @param tableList(数据源)
     * @Return void
     * @Exception
     */
    public void replaceTable(int index, List<List<String>> tableList) {
        XWPFTable table = document.getTables().get(index);
        //创建行,根据需要插入的数据添加新行,不处理表头
        for (int i = 1; i <= tableList.size(); i++) {
            table.createRow();
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1; i < tableList.size()+1; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            List<String> rowData = tableList.get(i - 1);
            for (int j = 0; j < rowData.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                String text = rowData.get(j);
                cell.setText(text);
                //表格样式一致-->没有此段表格会默认左对齐
                //有此段会使表格格式一致
                CTTc cttc = cell.getCTTc();
                CTTcPr ctPr = cttc.addNewTcPr();
                ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
            }
        }
    }

7、完整的工具类代码

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PoICreateWordFactory {
    

    /**
     * 生成ord
     *
     */
    public  void crateWord(Map<String, Object> dataMap, String templatePath, String targetFile) throws IOException, InvalidFormatException {
        //加载模板文件
        loadTemplate(templatePath);

        //将dataMap拆分成 textMap、imageMap、tableMap TODO 烂尾中

        //段落替换变量
        Map<String, Object> textMap = new HashMap<>();
        //替换模板数据
        replaceText(textMap);

        //图片替换变量
        Map<String, byte[]> imageMap = new HashMap<>();
        replaceImage(imageMap);

        //写入表格
        List<List<String>> arrearsList = new ArrayList<>();
        replaceTable(0, arrearsList);

        //生成新的word
        createWordFile(targetFile);
    }

    private final String REGEX = "\\$\\{(.+?)\\}";

    private CustomXWPFDocument document;

    public PoICreateWordFactory() {}

    public PoICreateWordFactory(String templatePath) throws IOException {
        loadTemplate(templatePath);
    }

    /**
     * 加载模板
     *
     * @param templatePath 模板路径
     * @return 包含返回true, 不包含返回false
     */
        public void loadTemplate(String templatePath) throws IOException {
        try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
            //转成word
            this.document = new CustomXWPFDocument(in);
        }
    }

    /**
     * 生成word
     *
     * @param targetFile word生成路径
     * @return 包含返回true, 不包含返回false
     */
    public void createWordFile(String targetFile) throws IOException {
        try (FileOutputStream out = new FileOutputStream(targetFile)){
            document.write(out);
        }
    }

    /**
     * 判断文本中是否包含$
     *
     * @param text 文本
     * @return 包含返回true, 不包含返回false
     */
    public boolean checkText(String text) {
        boolean check = false;
        if (text.indexOf("$") != -1) {
            check = true;
        }
        return check;
    }


    /**
     * 替换段落文本
     *
     * @param textMap(数据源)
     */
    public void replaceText(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) {
                    //替换模板原来位置
                    Pattern pattern = Pattern.compile(REGEX);
                    Matcher matcher = pattern.matcher(run.toString());
                    if (matcher.find()) {
                        String key = matcher.group(1);
                        if(textMap.containsKey(key)){
                            run.setText(String.valueOf(textMap.get(key)), 0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换图片
     *
     * @param imageMap(数据源)
     */
    public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
        //段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
        for (XWPFParagraph paragraph : paragraphs) {
            //获取到段落中的所有文本内容
            String text = paragraph.getText();
            //判断此段落中是否有需要进行替换的文本
            if (checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    Pattern pattern = Pattern.compile(REGEX);
                    String runText = run.toString();
                    Matcher matcher = pattern.matcher(runText);
                    if (matcher.find()) {
                        String key = matcher.group(1);
                        if(imageMap.containsKey(key)){
                            //清空原有内容
                            run.setText("", 0);
                            //设置图片
                            document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
                            //创建一个word图片,并插入到文档中-->像素可改
                            document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换表格内容
     *
     * @param index(表格索引:第几个表格)
     * @param tableList(数据源)
     * @Return void
     * @Exception
     */
    public void replaceTable(int index, List<List<String>> tableList) {
        XWPFTable table = document.getTables().get(index);
        //创建行,根据需要插入的数据添加新行,不处理表头
        for (int i = 1; i <= tableList.size(); i++) {
            table.createRow();
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1; i < tableList.size()+1; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            List<String> rowData = tableList.get(i - 1);
            for (int j = 0; j < rowData.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                String text = rowData.get(j);
                cell.setText(text);
                //表格样式一致-->没有此段表格会默认左对齐
                //有此段会使表格格式一致
                CTTc cttc = cell.getCTTc();
                CTTcPr ctPr = cttc.addNewTcPr();
                ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
            }
        }
    }
}

三、验证模板生成

1、测试代码

public static void main(String[] args) throws IOException, InvalidFormatException {
        String templatePath = "D:\\文章\\word生成\\poi\\qiantiao.docx";
        String targetFile = "D:\\test\\qiantiao.docx";
        //初始化,并加载模板文件
        PoICreateWordFactory poICreateWordFactory = new PoICreateWordFactory(templatePath);

        //段落替换变量
        LocalDate currentDate = LocalDate.now();
        LocalDate endDate = currentDate.plusYears(1L);
        Map<String, Object> textMap = new HashMap<>();
        textMap.put("debtor", "陈有楚");
        textMap.put("nowYear", String.valueOf(currentDate.getYear()));
        textMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
        textMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
        textMap.put("arrears", "一顿老魏、贵州大黄牛、v我50");
        textMap.put("endYear", String.valueOf(endDate.getYear()));
        textMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
        textMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
        textMap.put("creditor", "知北游");
        //替换模板数据
        poICreateWordFactory.replaceText(textMap);

        //图片替换变量
        FileInputStream imageInput = new FileInputStream("D:\\picture\\其他\\24-05-23-142418.png");
        byte[] bytes = new byte[imageInput.available()];
        imageInput.read(bytes);
        imageInput.close();
        Map<String, byte[]> imageMap = new HashMap<>();
        imageMap.put("image1", bytes);
        poICreateWordFactory.replaceImage(imageMap);

        //写入表格
        List<List<String>> arrearsList = new ArrayList<>();
        arrearsList.add(Arrays.asList("一顿老魏", "1", "三月内"));
        arrearsList.add(Arrays.asList("贵州大黄牛", "1", "一年内"));
        arrearsList.add(Arrays.asList("v我50", "1", "一月内"));
        //获取表格位置 0代表第一个表格,写死第一个,模板里也只有一个模板
        poICreateWordFactory.replaceTable(0, arrearsList);

        //生成新的word
        poICreateWordFactory.createWordFile(targetFile);

    }

2、生成效果

请添加图片描述

四、总结

其实从测试代码里就可以发现这其实只是一个半成品代码,文本替换、图片替换、表格替换甚至需要分别传递不同的数据map。本来是打算合并成一个dataMap,然后根据参数类来区分是文本、图片、表格的。然后拆分成多个数据map。但是在写这些代码时发现了也是基于poi开发的开源项目poi-tl。功能很全,我想实现的功能他都有,顿时我写的上面这些代码就失去了意义,然后就烂尾了。。。后面有时间介绍一下poi-tl这个开源项目使用方式吧,经过试验这个确实功能完善,非常推荐。

标签:word,String,java,textMap,poi,生成,org,import,public
From: https://www.cnblogs.com/fhey/p/17542195.html

相关文章

  • python3使用pip安装wordcloud报错error: Microsoft Visual C++ 14.0 or greater is re
    背景:使用的是Anaconda集成环境,python版本是:3.10,安装wordcloud包,使用的命令是:pipinstallwordcloud,出现报错:error:MicrosoftVisualC++14.0orgreaterisrequired.Getitwith"MicrosoftC++BuildTools":https://visualstudio.microsoft.com/visual-cpp-build-tools/......
  • Apache POI根据Excel模板填充数据
    pom.xml导入依赖(chooseversion)参考https://mvnrepository.com/<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version>......
  • 考虑多风场出力相关性的可再生能源场景生成/风电场景生成,并通过聚类算法场景削减成几
    考虑多风场出力相关性的可再生能源场景生成/风电场景生成,并通过聚类算法场景削减成几个场景,每个场景都有确定的出现概率。完美复现《考虑多风电场出力Copula相关关系的场景生成方法》Copula函数(连接函数)描述空间相邻风电场间的相关性,提出一种基于Copula函数生成风电场出力......
  • MATLAB代码:基于列约束生成法CCG的两阶段问题求解 关键词:两阶
    MATLAB代码:基于列约束生成法CCG的两阶段问题求解关键词:两阶段鲁棒列约束生成法CCG算法参考文档:《Solvingtwo-stagerobustoptimizationproblemsusingacolumn-and-constraintgenerationmethod》仿真平台:MATLABYALMIP+CPLEX主要内容:代码构建了两阶段鲁棒优化模型,并用文......
  • SVPWM仿真和基于DSP28335的PIL(处理器在环) 仿真模型(将matlab仿真算法生成代码在DSP中
    SVPWM仿真和基于DSP28335的PIL(处理器在环)仿真模型(将matlab仿真算法生成代码在DSP中在线运行返回数据给Matlab)验证算法可行性和实时性。对于数字信号处理很有用。ID:73400638006173885......
  • SQ工具|3|界址点线生成|ZDZHDM赋值
    以 不动产登记数据库TD/T1066-2021数据库规范中的宗地及界址点线为依据界面介绍: 此工具主要实现了界址线属性的计算,以ZDZHDM(记录相邻界址点、界址线的宗地代码)为主,所需数据包括对应的宗地数据界址点自动赋值包括:界址线自动赋值包括:如果缺少界址点、界址线数据,点击......
  • SpringBoot集成JApiDocs实现自动生成接口文档
    一、概念JApiDocs是一个符合Java编程习惯的Api文档生成工具。最大程度地利用Java的语法特性,你只管用心设计好接口,添加必要的注释,JApiDocs会帮你导出一份漂亮的Html文档,并生成相关的Java和Object-C相关数据模型代码,从此,Android和IOS的同学可以少敲很多代码了,你也不......
  • abc065d <贪心+最小生成树> [lambda表达式]
    D-Built?//https://atcoder.jp/contests/abc065/tasks/arc076_b//贪心+最小生成树//关键在于意识到,连接x或y相邻的边代价最小,因而无需考虑全部的边,仅需考虑这些相邻边即可(贪心)//学习://1.lambda写法https://www.cnblogs.com/yaya12138/p/11815475.html//......
  • 标小智AI智能Logo生成器,免费设计logo生成,堪称神站!
    1.标小智是什么?标小智LOGO神器是国内最早自研的一款logo生成器产品,受到很多朋友喜欢的智能logo创建工具。只需要输入logo名称,即可智能生成上百款不重样的logo设计方案,以及配套企业VI助您打造个性品牌。 拥有极其丰富的Logo创意,它最厉害的一点是把设计行业里普通人难以理解......
  • 暗黑2能用Java开发?还能生成APP?
    最近烧哥发现个宝藏项目,竟然用Java开发了暗黑2出来。众所周知,暗黑2是暴雪开发的一款经典游戏,距今虽有20多年,仍然有很多粉丝。粉丝延续热情的方式有很多,一种是做Mod,比如魔电,对怪物、技能、物品、场景、甚至游戏机制都有大改,目前还在定期更新,并有战网提供。另一种是纯怀旧,用另......