Spire.Doc for Java(cracked)实现复制word中的表格(2)

先看效果,符不符合你的需求。

背景: 

word插入的表格数据填充到该表格时,如果数据量超过该的表格数,应将表格在下一页重新创建该表格,并将剩余数据继续填充到新的表格中。

再简单点:word表格只有5行,但是数据有20行,表格不够添加,就还需要复制3份一样的表格,中间需要分页符隔开,最终得到4份表格。

效果: 

用java实现,table是模板,table2是生成的。

table中有1个表格(可以有多个表格,现在演示就只创了1个)

表格可以填写的数据为:{"小武的一天":10,"小李的一天":20,"小赵的一天":12}

填充的数据为:[{"小武的一天":25},{"小李的一天":30},{"小赵的一天":18}]

还需要复制:{"小武的一天":2,"小李的一天":1,"小赵的一天":1}

选择最大值:2就是要复制的数量。

最终table2得到3个表格数量

 

 

表格可以填写的数据为:{"小武的一天":10,"小李的一天":20,"小赵的一天":12}

这个10、20、12

是插入的表格数量。 

 

上代码: 依赖需要用我上一个发的,不然操作表格有限制(还有别的限制💥💥),不能操作超过25个表格等等。

http://t.csdnimg.cn/UUICw  看这个获取cracked的jar

pom 

    <repositories>
        <repository>
            <id>com.e-iceblue</id>
            <name>e-iceblue</name>
            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
    </repositories> 

<!--    POI    -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>5.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
         <!--配合jar包使用;-->
        <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.doc</artifactId>
            <version>11.4.2</version>
        </dependency>
        <!-- jar包-->
        <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spirej.doc.cracked</artifactId>
            <version>11.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20210307</version> <!-- 或者使用最新版本 -->
        </dependency>

json 

{
  "id": 184567839137890,
  "data": [
    {
      "name": "名称",
      "type": "String",
      "value": "小李"
    },
    {
      "name": "年龄",
      "type": "String",
      "value": "18"
    },
    {
      "name": "身高",
      "type": "String",
      "value": "181"
    },
    {
      "name": "人员",
      "type": "String",
      "value": "小李、小武、小赵"
    },
    {
      "name": "日期",
      "type": "String",
      "value": "2024-08-22"
    },
    {
      "name": "小赵签字",
      "type": "String",
      "value": "我想睡觉"
    },
    {
      "name": "小武签字",
      "type": "String",
      "value": "帅名字"
    },
    {
      "name": "小李的一天",
      "type": "Row",
      "value": [
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ],
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ],
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ],
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ],
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ],
        [
          "起床洗漱",
          "饭后来一根",
          "听歌摸鱼",
          "健身",
          "emo"
        ]
      ]
    },
    {
      "name": "小武的一天",
      "type": "Row",
      "value": [
        [
          "起床洗漱",
          "饭后睡一觉",
          "摸鱼",
          "diss小赵睡觉",
          "diss小赵磨牙"
        ],
        [
          "起床洗漱",
          "饭后睡一觉",
          "摸鱼",
          "diss小赵睡觉",
          "diss小赵磨牙"
        ],
        [
          "起床洗漱",
          "饭后睡一觉",
          "摸鱼",
          "diss小赵睡觉",
          "diss小赵磨牙"
        ],
        [
          "起床洗漱",
          "饭后睡一觉",
          "摸鱼",
          "diss小赵睡觉",
          "diss小赵磨牙"
        ],
        [
          "起床洗漱",
          "饭后睡一觉",
          "摸鱼",
          "diss小赵睡觉",
          "diss小赵磨牙"
        ]
      ]
    },
    {
      "name": "小赵的一天",
      "type": "Row",
      "value": [
        [
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉"
        ],
		[
		  "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉"
        ],
		[
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉",
          "睡觉"
        ]
      ]
    }
  ]
}

javaUtil

json数据在上面,模板自己创一个就行



import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.spire.doc.*;
import com.spire.doc.collections.*;
import com.spire.doc.documents.BorderStyle;
import com.spire.doc.documents.BreakType;
import com.spire.doc.documents.Paragraph;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.json.JSONArray;
import org.json.JSONObject;

import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author HaoLin Xie
 * @Date 2024/8/1 22:36
 * @PackageName:org.example.utils
 * @ClassName: CopyTable
 * @Description: 根据数据复制新的表格并添加分页符
 * @Version 1.0
 */
public class CopyTable {
    public static void main(String[] args) {

        String JsonFilePath = "Table.json"; // JSON 文件路径
        String path = "Table.docx"; //模板
        String file = "Table2.docx"; //生成

        //获取传来的json数据
        ArrayList<JSONObject> jsonObjectArrayList = jsonDataBase(JsonFilePath);
        System.out.println("json-->" + jsonObjectArrayList);
        System.out.println();

        //创建对象
        Document document = new Document();
        document.loadFromFile(path);

        // 获取文档中的所有节
        SectionCollection sections = document.getSections();

        // 遍历每个节
        for (int secIndex = 0; secIndex < sections.getCount(); secIndex++) {
            //获取当前索引的节对象
            Section section = sections.get(secIndex);

            // 获取节中的所有表格
            TableCollection tables = section.getTables();

            // 遍历每个表格,并把表格数据放进list
            LinkedList<LinkedList> list = BiaoGeSize(tables);

            //存放还要复制多少个表格的集合
            LinkedList<Integer> linkedListfuzhi = new LinkedList();

            //算还要复制多少个表格
            for (LinkedList linkedList : list) {

                //得到每个表格的数据,把表格需要填充的list 添加占位标识符
                insertStartAndEndTags(linkedList);

                //获取表格占位符,得到表格的格子数量
                JSONObject jsonObjectTable = getzhanweifu(linkedList);
                System.out.println("表格:" + jsonObjectTable);

                //计算数据的表格数量
                JSONArray jsonArrayJsonData = jisuandatabase(jsonObjectArrayList, jsonObjectTable);
                System.out.println("数据:" + jsonArrayJsonData);

                //计算还要复制多少表格
                int remainder = remainder(jsonObjectTable, jsonArrayJsonData);
                System.out.println("要复制的表格数: " + remainder);

                //把还需要复制多少表格全部放进一个集合
                linkedListfuzhi.add(remainder);
                System.out.println();
            }

            //该文档中所有的表格总数
            int count = tables.getCount();
            System.out.println("当前文档共有表格数量为->" + count);
            System.out.println("复制表格list:" + linkedListfuzhi);

            //开始复制表格
            cloneBiaoGe(tables, count, linkedListfuzhi, section);

            int count2 = tables.getCount();
            System.out.println("复制后当前文档共有表格数量为->" + count2);

            //删除最后1页的分页符
            delFenYe(section, sections);
        }
        //生成
        document.saveToFile(file, FileFormat.Docx_2013);
        document.dispose();
        System.out.println("去除头部警告!");
        //去水印(头部警告)
        restWord(file);
        System.out.println("复制表格完成");
    }


    /**
     * @param table 表格
     * @param data  json数据
     * @return 还要复制的页数
     * <p>
     * 计算还要复制多少表格
     */
    private static int remainder(JSONObject table, JSONArray data) {
        // 创建结果的 JSONObject
        JSONObject result = new JSONObject();

        // 遍历数据
        for (int i = 0; i < data.length(); i++) {
            org.json.JSONObject item = data.getJSONObject(i);
            String key = item.keys().next(); // 获取键
            int dataValue = item.getInt(key); // 数据值
            int tableValue = table.getInt(key); // 表格值

            // 计算商和余数
            int quotient = dataValue / tableValue;
            int remainder = dataValue % tableValue;

            // 根据余数决定是否加一
            if (remainder != 0) {
                quotient += 1;
            }

            // 将结果存入 result
            result.put(key, quotient - 1);
        }

        // 打印结果
        System.out.println("还需要复制:" + result.toString());

        // 初始化最大值和对应的键
        int maxValue = 0;

        for (String key : result.keySet()) {
            int value = result.getInt(key);
            if (value > maxValue) {
                maxValue = value;
            }
        }
        //返回最大值
        return maxValue;
    }


    /**
     * @param jsonFilePath json路径
     * @return 获取传来的json数据
     *
     * 获取传来的json数据
     */
    private static ArrayList<JSONObject> jsonDataBase(String jsonFilePath) {
        // 读取 JSON 文件内容
        ArrayList<JSONObject> jsonObjectArrayList = new ArrayList<>();

        try (FileReader reader = new FileReader(jsonFilePath)) {
            JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject();
            JsonArray dataArray = jsonObject.getAsJsonArray("data");

            // 处理 JSON 数据
            for (int i = 0; i < dataArray.size(); i++) {
                JsonObject item = dataArray.get(i).getAsJsonObject();
                if (item.get("type").getAsString().equals("Row")) {
                    JSONObject jsonObject1 = new JSONObject();
                    jsonObject1.put("name", item.get("name").getAsString());
                    jsonObject1.put("type", item.get("type").getAsString());
                    jsonObject1.put("value", item.get("value").toString());
                    jsonObjectArrayList.add(jsonObject1);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObjectArrayList;
    }

    /**
     * @param section  节对象
     * @param sections 所有节
     * <p>
     * 删除最后1页的分页符
     */
    private static void delFenYe(Section section, SectionCollection sections) {
        Paragraph lastParagraph = section.getParagraphs().get(section.getParagraphs().getCount() - 1);
        // 检查最后一页是否为空白
        if (lastParagraph.getText().trim().isEmpty()) {

            // 删除最后一页的段落或内容
            section.getParagraphs().remove(lastParagraph);

            // 如果需要删除最后一页的章节(如果它是唯一的章节且为空)
            if (section.getParagraphs() == null) {
                sections.remove(section);
            }
        }
    }


    /**
     * @param jsonObjectArrayList json数据
     * @param getzhanweifu        上一步算出的表格的名称和长度
     * @return 数据的名称和长度
     * <p>
     * 计算数据的长度
     */
    private static JSONArray jisuandatabase(ArrayList<JSONObject> jsonObjectArrayList, JSONObject getzhanweifu) {
        List<JSONObject> matchedObjects = new ArrayList<>();

        for (String key : getzhanweifu.keySet()) {
            for (JSONObject jsonObject : jsonObjectArrayList) {
                if (jsonObject.getString("name").equals(key)) {
                    matchedObjects.add(jsonObject);
                    break;
                }
            }
        }

        JSONArray jsonArray = new JSONArray();
        for (JSONObject obj : matchedObjects) {
            String name = obj.getString("name");
            String valueString = obj.getString("value");
            JSONArray outerArray = new JSONArray(valueString);
            //初始化
            int totalLength = 0;

            for (int i = 0; i < outerArray.length(); i++) {
                JSONArray innerArray = outerArray.getJSONArray(i);
                totalLength += innerArray.length();
            }

            JSONObject resultJson = new JSONObject();
            resultJson.put(name, totalLength);
            jsonArray.put(resultJson);
        }
        return jsonArray;
    }


    /**
     * @param es 每个表格
     * <p>
     * 给表格自动添加占位符
     */
    private static void insertStartAndEndTags(LinkedList es) {
        List<Integer> arrList = new LinkedList<>();
        for (int i = 0; i < es.size(); i++) {
            if (es.get(i).equals("")) {
                if (!es.get(i - 1).equals("") && !es.get(i - 1).equals("${start}")) {
                    es.set(i, "${start}");
                }
                if (!es.get(i + 1).equals("") && !es.get(i + 1).equals("${end}")) {
                    es.set(i, "${end}");
                } else {
                    es.set(es.size() - 1, "${end}");
                }
            }
        }
        for (int j = 0; j < es.size(); j++) {
            if (es.get(j).equals("${start}") || es.get(j).equals("${end}")) {
                if (es.get(j).equals("${end}") && es.size() - 1 == j && !es.get(j - 1).equals("")) {
                    arrList.add(j);
                } else if (!es.get(j - 1).equals("") && !es.get(j + 1).equals("")) {
                    arrList.add(j);
                }
            }
        }
        for (int k = 0; k < arrList.size(); k++) {
            es.set(arrList.get(k), "");
        }
    }

    /**
     * @param list 每个表格
     * @return 返回文档内表格的名称和格子长度
     *
     * 获取占位符的下标
     */
    private static JSONObject getzhanweifu(LinkedList list) {

        System.out.println("修改后的-->" + list);
        //获取表格内填充表格的名字
        LinkedList<String> stringLinkedList = FindAllListsName(list);

        LinkedList<Integer> startIndices = new LinkedList(); //开始
        LinkedList<Integer> endIndices = new LinkedList(); //结束
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).equals("${start}")) {
                startIndices.add(i);
            } else if (list.get(i).equals("${end}")) {
                endIndices.add(i);
            }
        }
        LinkedList<Integer> linkedList = new LinkedList<>();

        for (int i = 0; i < Math.min(startIndices.size(), endIndices.size()); i++) {
            int startIndex = startIndices.get(i);
            int endIndex = endIndices.get(i);
            linkedList.add((endIndex - startIndex) + 1);
            //System.out.println("第 " + (i + 1) + " 对: ${start} 位置 = " + startIndex + ", ${end} 位置 = " + endIndex + ", 有" + ((endIndex - startIndex) + 1) + "个");
        }
        // 创建 JSONObject
        JSONObject jsonObject = new JSONObject();
        for (int i = 0; i < stringLinkedList.size(); i++) {
            jsonObject.put(stringLinkedList.get(i), linkedList.get(i));
        }

        return jsonObject;
    }


    /**
     * @param list 修改后的list
     * @return
     *
     * 获取表格内填充表格的名字
     */
    private static LinkedList<String> FindAllListsName(LinkedList list) {
        LinkedList<String> stringLinkedList = new LinkedList<>();
        // 将 LinkedList 转换为一个字符串
        String data = String.join("", list);

        // 正则表达式模式用于匹配 ${} 标记
        Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
        Matcher matcher = pattern.matcher(data);

        // 存储所有 `${start}` 的位置
        LinkedList<Integer> startPositions = new LinkedList<>();
        while (matcher.find()) {
            if (matcher.group().equals("${start}")) {
                startPositions.add(matcher.start());
            }
        }

        // 如果没有找到 `${start}` 标记
        if (startPositions.isEmpty()) {
            System.out.println("没有找到 `${start}` 标记。");
            return null;
        }

        // 再次匹配所有 `${}` 标记
        matcher = pattern.matcher(data);
        String lastMarker = "";
        int lastMarkerPos = -1;

        // 遍历所有 `${start}` 的位置
        for (int startPos : startPositions) {
            // 查找最近的 `${}` 标记
            while (matcher.find()) {
                String marker = matcher.group();
                if (matcher.start() >= startPos) {
                    break;
                }
                lastMarker = marker;
                lastMarkerPos = matcher.start();
            }

            // 提取 `${start}` 前面最近的 `${}` 包住的内容
            if (!lastMarker.isEmpty() && lastMarkerPos != -1) {
                int lastMarkerEndPos = lastMarkerPos + lastMarker.length();
                String result = data.substring(lastMarkerPos + 2, lastMarkerEndPos - 1); // 提取 `${}` 包住的内容
                stringLinkedList.add(result);
            } else {
                System.out.println("`${start}` 之前没有找到 `${}` 标记。");
            }

            // 重置 `Matcher` 对象,以便继续查找下一个 `${start}`
            matcher = pattern.matcher(data);
        }
        return stringLinkedList;
    }

    /**
     * @param tables 所有表格
     * @return 获取表格下标,遍历表格内
     */
    private static LinkedList<LinkedList> BiaoGeSize(TableCollection tables) {
        LinkedList<LinkedList> es2 = new LinkedList();

        for (int tableIndex = 0; tableIndex < tables.getCount(); tableIndex++) {
            LinkedList es1 = new LinkedList<>();
            Table table = tables.get(tableIndex);

            // 遍历表格中的行
            RowCollection rows = table.getRows();
            for (int rowIndex = 0; rowIndex < rows.getCount(); rowIndex++) {
                TableRow row = rows.get(rowIndex);
                CellCollection cells = row.getCells();
                for (int cellIndex = 0; cellIndex < cells.getCount(); cellIndex++) {
                    //内容
                    TableCell cell = cells.get(cellIndex);
                    String cellText = cell.getParagraphs().get(0).getText();
                    es1.add(cellText);
                }
            }
            es2.add(es1);
        }
        return es2;
    }

    /**
     * @param tables      所有表格
     * @param count       表格总数
     * @param fuzhibiaoge 要复制多少表格的Lsit
     * @param section     节对象
     *                    <p>
     *                    复制表格
     */
    private static void cloneBiaoGe(TableCollection tables, int count, LinkedList<Integer> fuzhibiaoge, Section section) {
        for (int j = 0; j < count; j++) {
            // 处理每个表格  必须是表格的下标
            Table table2 = tables.get(j);

            // 获取表格的行数和列数
            int rowCount = table2.getRows().getCount(); //行
            //int columnCount = table2.getRows().get(0).getCells().getCount(); //列

            System.out.println("表格的行数:" + rowCount);

            for (int n = 0; n < fuzhibiaoge.size(); n++) {
                if (j == n) {
                    for (int k = 0; k < fuzhibiaoge.get(n); k++) {
                        //创建一个新表格
                        Table table = addTable(section);
                        section.addParagraph().appendBreak(BreakType.Page_Break);
                        for (int i = 0; i < rowCount; i++) {
                            TableRow row1 = table2.getRows().get(i).deepClone();
                            table.getRows().insert(i, row1); //放进新表格
                        }
                        table.autoFit(AutoFitBehaviorType.Fixed_Column_Widths);
                    }
                }
            }
        }
    }


    /**
     * @param section 每一节
     * @return
     * 创建一个新表格
     */
    private static Table addTable(Section section) {
        //创建一个新表格
        Table table1 = section.addTable(true);
        //黑色
        table1.getTableFormat().getBorders().getTop().setColor(Color.BLACK);
        table1.getTableFormat().getBorders().getBottom().setColor(Color.BLACK);
        table1.getTableFormat().getBorders().getLeft().setColor(Color.BLACK);
        table1.getTableFormat().getBorders().getRight().setColor(Color.BLACK);
        //粗边框
        table1.getTableFormat().getBorders().getTop().setBorderType(BorderStyle.Hairline);
        table1.getTableFormat().getBorders().getBottom().setBorderType(BorderStyle.Hairline);
        table1.getTableFormat().getBorders().getLeft().setBorderType(BorderStyle.Hairline);
        table1.getTableFormat().getBorders().getRight().setBorderType(BorderStyle.Hairline);
        //边框大小
        float size = 2.5F;
        table1.getTableFormat().getBorders().getTop().setLineWidth(size);
        table1.getTableFormat().getBorders().getBottom().setLineWidth(size);
        table1.getTableFormat().getBorders().getLeft().setLineWidth(size);
        table1.getTableFormat().getBorders().getRight().setLineWidth(size);
        return table1;
    }

    /**
     * 使用spire.Doc 会出现一个水印(头部警告)可以通过这个方法去除水印
     *
     * @param docFilePath 生成的新路径
     */
    private static void restWord(String docFilePath) {
        try (FileInputStream in = new FileInputStream(docFilePath)) {
            XWPFDocument doc = new XWPFDocument(OPCPackage.open(in));
            List<XWPFParagraph> paragraphs = doc.getParagraphs();

            if (paragraphs.size() < 1) {
                return;
            }
            XWPFParagraph firstParagraph = paragraphs.get(0);
            if (firstParagraph.getText().contains("Spire.Doc")) {
                doc.removeBodyElement(doc.getPosOfParagraph(firstParagraph));
            }
            OutputStream out = new FileOutputStream(docFilePath);
            doc.write(out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 三克油

 

 

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值