easypoi模板导出word多页导出加强版

news2024/11/15 21:41:09

说明

上一篇文章提到多页导出,但是后边发现一个问题,如果用同一个模板导出多页内容,我们去获取多页内容的时候,会发现全部都一样,举个例子:

XWPFDocument document = WordExportUtil.exportWord07(outputUrl, maps);
List<XWPFTable> tables = document.getTables();
List<XWPFParagraph> paragraphs = document.getParagraphs();

通过上边的代码,不管获取tables 还是paragraphs,集合里边的内容都是一样的,而且表格只有一张,即使你导出的时候多页都有表格,但是代码获取的时候就只有一张表。

另一个问题,就是,到处之后会莫名多出一个空白页。

在这里插入图片描述

解决问题

因为获取不到除第一页的其他页内容,那么照这个方法就没办法了,那么只能转变思路,导出多页,那么就让多页数据在导出的时候独立起来,也就是说我们创建出多个XWPFDocument,最后把这些XWPFDocument合并起来,不再使用前一篇文章提到的官方方法exportWord07(String url, List<Map<String, Object>> list)了,这样不仅可以解决多页内容获取不到的问题,还能解决另一个问题(导出的word总是多出一页空白页)。

具体操作

创建工具类:

import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.springframework.util.CollectionUtils;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * WordUtils
 *
 * @author ZENG.XIAO.YAN
 * @version 1.0
 * @Date 2019-09-20
 */
public final class WordUtils {
 
    /**
     * word文件合并
     * @param wordList
     * @return
     * @throws Exception
     */
    public static  XWPFDocument mergeWord(List<XWPFDocument> wordList) throws Exception{
        if (CollectionUtils.isEmpty(wordList)) {
            throw  new RuntimeException("待合并的word文档list为空");
        }
        XWPFDocument doc = wordList.get(0);
        int size = wordList.size();
        if (size > 1) {
            //不要设置分页符,否则第二页第一行总会多出一个换行符,具体需不需要根据自己的需求来定
            doc.createParagraph().setPageBreak(false);
            for (int i = 1; i < size; i++) {
                // 从第二个word开始合并
                XWPFDocument nextPageDoc = wordList.get(i);
                // 最后一页不需要设置分页符
                if (i != (size-1)) {
                    nextPageDoc.createParagraph().setPageBreak(false);
                }
                appendBody(doc, nextPageDoc);
            }
        }
        return doc;
    }
 
    private static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();
        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String,String> map = new HashMap<>();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }
        appendBody(src1Body, src2Body,map);
 
    }
 
    private static void appendBody(CTBody src, CTBody append,Map<String,String> map) throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);
        String srcString = src.xmlText();
        String prefix = srcString.substring(0,srcString.indexOf(">")+1);
        String mainPart = srcString.substring(srcString.indexOf(">")+1,srcString.lastIndexOf("<"));
        String sufix = srcString.substring( srcString.lastIndexOf("<") );
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix+mainPart+addPart+sufix);
        src.set(makeBody);
    }
 
}

关键代码:

//用来装每个需要合并的XWPFDocument
List<XWPFDocument> wordList = new ArrayList<>();
XWPFDocument document = WordExportUtil.exportWord07(outputUrl, map);
XWPFTable table = document.getTables().get(0);
   for (int row = 4; row <= table.getNumberOfRows() - 4; row++) {
       // 从第二行开始,合并上一行和当前行
       XWPFTableRow row1 = table.getRow(row);
       if (row == 4) {
           XWPFTableCell cell = row1.getCell(6);
           cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
           cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
           cell.setText("根据物资的形状、性能、特点、数量、重量进行五五式合理摆放,必须做到稳固、定量、整理、方便和安全");
       } else if (row == table.getNumberOfRows() - 4) {
           XWPFTableCell cell = row1.getCell(7);
           CTTc ctTc = cell.getCTTc();
           if (ctTc != null) {
               CTTcPr tcPr = ctTc.getTcPr();
               if (tcPr == null) {
                   tcPr = ctTc.addNewTcPr();
               }
               if (tcPr.getVMerge() == null) {
                   tcPr.addNewVMerge();
               }
               tcPr.getVMerge().setVal(STMerge.CONTINUE);
           }
           cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
       } else {
           XWPFTableCell cell = row1.getCell(10);
           CTTc ctTc = cell.getCTTc();
           if (ctTc != null) {
               CTTcPr tcPr = ctTc.getTcPr();
               if (tcPr == null) {
                   tcPr = ctTc.addNewTcPr();
               }
               if (tcPr.getVMerge() == null) {
                   tcPr.addNewVMerge();
               }
               tcPr.getVMerge().setVal(STMerge.CONTINUE);
           }
           cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
       }
   }
   wordList.add(document);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2073694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习入门-第4章-神经网络的学习

学习就是从训练数据中自动获取最优权重参数的过程。引入损失函数这一指标&#xff0c;学习的目的是找出使损失函数达到最小的权重参数。使用函数斜率的梯度法来找这个最小值。 人工智能有两派&#xff0c;一派认为实现人工智能必须用逻辑和符号系统&#xff0c;自顶向下看问题…

java-Mybatis框架

简介 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQl、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Java Obje…

DFS 算法:全排列问题

我的个人主页 {\large \mathsf{{\color{Red} 我的个人主页} } } 我的个人主页 往 {\color{Red} {\Huge 往} } 往 期 {\color{Green} {\Huge 期} } 期 文 {\color{Blue} {\Huge 文} } 文 章 {\color{Orange} {\Huge 章}} 章 DFS 算法&#xff1a;记忆化搜索 此系列更新频繁&…

k8s中service对象

文章目录 一、Service简介Service和kube-proxy的作用与区别Service的工作过程kube-proxy的工作过程总结 二、具体实践ClusterIPClusterIP 基本概念应用场景 NodePortNodePort 简介应用场景 ExternalName简介应用场景 一、Service 简介 Kubernetes (k8s) 中的 Service 对象是一…

使用redis设计延迟队列

目录 延迟队列概念与重要性 定义&#xff1a;延迟队列的基本概念 重要性&#xff1a;延迟队列在处理异步任务中的关键作用 图表&#xff1a;延迟队列的工作流程图 ​编辑延迟队列设计案例 背景介绍 设计目标 系统架构 设计要点 现有物理拓扑 图表&#xff1a;有赞延迟…

GStreamer 简明教程(五):Pad 相关概念介绍,Pad Capabilities/Templates

系列文章目录 GStreamer 简明教程&#xff08;一&#xff09;&#xff1a;环境搭建&#xff0c;运行 Basic Tutorial 1 Hello world! GStreamer 简明教程&#xff08;二&#xff09;&#xff1a;基本概念介绍&#xff0c;Element 和 Pipeline GStreamer 简明教程&#xff08;三…

自修C++Primer----3.2标准库类型string

目录 1.String的相关操作 1.1拷贝初始化&&直接初始化 1.2显示创建临时对象 1.3读取string对象内容 1.4一次读取多个未知对象 1.5使用getline读取一整行内容 1.6size()的返回值size_type类型 1.7两个string对象比较 1.8string对象赋值 1.9两个string对象相加 1…

策略产品 ①算法逻辑

目录 一、机器学习与AI的关系 二、机器学习全流程 1. 问题定义 2. 数据处理 3. 特征工程 4. 模型训练 5. 模型评估 6. 模型应用 机器学习是AI的关键技术之一&#xff0c;是指机器从历史数据中学习规律&#xff0c;从而提升系统某个性能度量的过程。这篇文章&#xff0c;我们在作…

C Primer Plus第十四章编程练习,仅供参考

第十四章编程练习 第一个问题让我们改写复习题5&#xff0c;创建一个函数去计算一年到某个月份的天数&#xff0c;在一个结构数组中去存储相关数据。完整程序代码以及运行结果如下&#xff1a; #include<stdio.h> #include<string.h> #include<ctype.h> st…

当外接硬盘接入到macOS上,只读不可写时,应当格式化

当windows磁盘格式例如 NTFS 的硬盘接入到macOS上时&#xff0c;会发现无法新建文件夹&#xff0c;无法删除、重命名。原因是磁盘格式对不上macOS&#xff0c;需要进行格式化。格式化时请注意备份重要数据。具体做法如下&#xff0c;在macOS中找到磁盘工具&#xff0c;然后对磁…

【HTML】常用几种模拟动画效果【附源代码】

1. 模拟音频波纹加载效果 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthde…

计算机视觉编程

目录 灰色度 缩略图 拷贝粘贴区域 调整图像尺寸 旋转图像45 画图线、描点 灰色度 灰度是指图像中每个像素的亮度值&#xff0c;用来描述图像中各个像素的明暗程度。在计算机视觉中&#xff0c;灰度可以通过以下方式来计算&#xff1a; 1. 平均值法&#xff1a;将图像中每…

如何在程序中创建出多条线程

多线程是编程中的一个重要概念&#xff0c;它允许程序同时执行多个任务&#xff0c;每个任务可以看作是一个线程。在Java中&#xff0c;多线程尤为常见且强大&#xff0c;它通过允许程序在并发环境下运行&#xff0c;提高了程序的执行效率和响应速度。以下是对Java多线程的详细…

数学建模~~~预测方法--决策树模型

目录 0.直击重点 1.决策树概念 2.节点特征的选择算法 3.基尼系数的计算 4.决策树的分类 5.模型的搭建 6.模型的改进和评价 ROC曲线 参数调优 &#xfeff;GridSearch网格搜索 使用搜索结果重新建模 0.直击重点 这个文章&#xff0c;我们从三个维度进行说明介绍&#…

如何使用Python快速修改文件的标签(如何将歌词嵌入到音乐文件中,含歌词嵌入接口源码)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Python与Music 📒📝 1. 初探音乐文件的标签📝 使用Python修改标签📝 将歌词嵌入音乐文件⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经听过一首好听的歌曲,却发现它的标签信息(元数据信息)杂乱无章?甚至找不到歌词?…

【Remi Pi开发板镜像烧录】使用sd卡进行瑞米派镜像的烧录

烧录大典 按照《软件开发指南》4.2.1和4.2.2的顺序进行&#xff0c;具体烧录哪个镜像结合你自己的需求&#xff0c;每个镜像的区别参考以下链接 https://mbb.eet-china.com/forum/topic/143906_1_1.html Tera term界面全屏如下设置看着比较舒服 设置完之后setup->save-&g…

智能优化特征选择|基于鹦鹉优化(2024年新出优化算法)的特征选择(分类器选用的是KNN)研究Matlab程序 【优化算法可以替换成其他优化方法】

智能优化特征选择|基于鹦鹉优化&#xff08;2024年新出优化算法&#xff09;的特征选择&#xff08;分类器选用的是KNN&#xff09;研究Matlab程序 【优化算法可以替换成其他优化方法】 文章目录 一、PO基本原理PO基本原理基本流程示例应用 二、实验结果三、核心代码四、代码获…

npm pack使用

npm pack 的作用主要是从包中创建一个压缩文件&#xff08;tarball&#xff09;&#xff0c;通常具有.tgz扩展名&#xff0c;包含了打包的模块及其依赖&#xff0c;可用于分发或部署。其应用场景包括私有库或组件的分发、离线环境的依赖安装、CI/CD 自动化构建等。 在使用npm管…

UE管理内容 —— FBX Material Pipeline

目录 Material Support Multiple Materials Material Naming Material Ordering Texture Import FBX管道将应用于网格体&#xff08;静态网格体和骨架网格体&#xff09;的材质和纹理&#xff0c;从3D应用程序传输到虚幻&#xff1b; 要转换简单材质&#xff0c;可以导入源…

Gameplay Ability System(通过GameplayEffect里的Execution修改角色属性)

一、关于GameplayEffectExecutionCalculation类 1、查看GameplayEffectExecutionCalculation类的Execute函数 这个函数将编辑器里设置的参数传进来&#xff0c;然后通过计算再返回出去&#xff0c;这个函数被标记为BlueprintNativeEvent&#xff0c;所以我们可以在自己的类Pla…