首页 > 其他分享 >SpringBoot - poi-tl合并word文件表格,复杂word表格

SpringBoot - poi-tl合并word文件表格,复杂word表格

时间:2024-10-24 10:19:24浏览次数:3  
标签:Map word SpringBoot 表格 int new poi import table

简介:

        上篇文章说到开发中我们需要通过在word中使用占位符来动态渲染一些数据,

        原文链接SpringBoot poi-tl通过模板占位符生成word文件-CSDN博客

        本文讲解poi-tl实现word表格之合并表格。


1. word格式
2. 导出后的docx文件 样式

3. 依赖

上篇文章有说过

SpringBoot poi-tl通过模板占位符生成word文件-CSDN博客

4. 实现代码

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class EditWordUtil {
    public static void main(String[] args) {
        String filePath = "D:/biao4.docx";

        try (FileInputStream resourceAsStream = new FileInputStream(new File(filePath));) {

            Map<String, Object> map = new HashMap<>();

            ArrayList<Map<String, Object>> dataList = new ArrayList<>();

            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 2; j++) {
                    HashMap<String, Object> maps = new HashMap<>();
                    maps.put("name", "龙龙" + (i + 1));
                    maps.put("skill", "Java" + j);
                    maps.put("lv", (j + 1) + "级");
                    maps.put("remak", "无");
                    dataList.add(maps);
                }
            }
            map.put("list", dataList);
            // 调用生成 Word 文件方法,将结果保存到本地
            EditWordUtil.mergeTablesFun("D:/out.docx", resourceAsStream, map, 0, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

  
    /**
     * 导出有合并表格的word
     *
     * @param outputPath
     * @param templatePath
     * @param data
     * @param pos              表格在文档的第几个表中,获取表格 从0开始
     * @param mergeColumnIndex 合并 相同的数据 第几列的单元格 从0开始
     * @return
     * @throws IOException
     */
    public static boolean mergeTablesFun(String outputPath, InputStream templatePath, Map<String, Object> data,
                                         int pos, int mergeColumnIndex

    ) throws IOException {
        try (FileOutputStream out = new FileOutputStream(outputPath);
             BufferedOutputStream bos = new BufferedOutputStream(out)) {

            ConfigureBuilder builder = Configure.builder();
            LoopRowTableRenderPolicy loopRowTableRenderPolicy = new LoopRowTableRenderPolicy();

            handleEmptyKeys(data);

            // 动态绑定
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                if (entry.getValue() instanceof ArrayList) {
                    builder.bind(entry.getKey(), loopRowTableRenderPolicy);

                    // 如果是嵌套列表,递归绑定
                    bindNestedLists(entry.getKey(), entry.getValue(), builder);
                }
            }

            Configure configure = builder.build();

            // 读取模板并渲染数据
            XWPFTemplate template = XWPFTemplate.compile(templatePath, configure).render(data);

            // 获取文档对象
            XWPFDocument document = template.getXWPFDocument();

            // 表格在文档的第pos个表中,获取表格
            XWPFTable table = document.getTableArray(pos);

            // 合并 相同的数据 第mergeColumnIndex列的单元格
            mergeCellsWithSameValue(table, mergeColumnIndex);

            try {
                template.write(bos);
                template.close();
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }

            out.flush();
            bos.flush();
        }
        return true;
    }

    // 递归绑定嵌套列表
    private static void bindNestedLists(String key, Object value, ConfigureBuilder builder) {
        if (value instanceof ArrayList) {
            for (Object item : (ArrayList<?>) value) {
                if (item instanceof Map) {
                    for (Map.Entry<String, Object> nestedEntry : ((Map<String, Object>) item).entrySet()) {
                        if (nestedEntry.getValue() instanceof ArrayList) {
                            // 绑定嵌套列表
                            builder.bind(nestedEntry.getKey(), new LoopRowTableRenderPolicy());
                            bindNestedLists(nestedEntry.getKey(), nestedEntry.getValue(), builder);
                        }
                    }
                }
            }
        }
    }


    // 递归检查map的key是否为空, 为空返回 ---
    public static void handleEmptyKeys(Map<String, Object> map) {
        // 遍历 Map 中的所有键值对
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            // 如果键为空或者键值为null
            if (key == null || key.isEmpty()) {
                map.put(key, "---");
            }

            // 如果值是 Map 类型,递归调用
            if (value instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> nestedMap = (Map<String, Object>) value;

                // 递归检查嵌套的 Map
                handleEmptyKeys(nestedMap);

                // 如果嵌套Map为空, 也设置为 "---"
                if (nestedMap.isEmpty()) {
                    map.put(key, "---");
                }
            }

            // 如果值为空
            else if (value == null) {
                map.put(key, "---");
            }
        }
    }


    // 合并相同值的单元格,colIndex 是要合并的列索引
    private static void mergeCellsWithSameValue(XWPFTable table, int colIndex) {
        String previousValue = null;
        int startRow = -1;
        int rowCount = table.getNumberOfRows();

        for (int i = 0; i < rowCount; i++) {
            XWPFTableRow row = table.getRow(i);
            XWPFTableCell cell = row.getCell(colIndex);
            String cellValue = cell.getText();

            // 如果当前值与前一个值相同,继续合并
            if (cellValue.equals(previousValue)) {
                continue;
            }

            // 如果前一个值不为空,且有多行需要合并,执行合并
            if (previousValue != null && i > startRow + 1) {
                mergeCellsVertically(table, colIndex, startRow, i - 1);
            }

            // 更新为当前值,并记录新起始行
            previousValue = cellValue;
            startRow = i;
        }

        // 处理最后一组相同值的合并
        if (startRow < rowCount - 1) {
            mergeCellsVertically(table, colIndex, startRow, rowCount - 1);
        }
    }

    // 合并表格垂直方向的单元格
    private static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        for (int i = fromRow; i <= toRow; i++) {
            XWPFTableCell cell = table.getRow(i).getCell(col);
            CTVMerge vMerge = CTVMerge.Factory.newInstance();
            if (i == fromRow) {
                // 第一个合并的单元格设置为 RESTART
                vMerge.setVal(STMerge.RESTART);
            } else {
                // 其他单元格设置为 CONTINUE
                vMerge.setVal(STMerge.CONTINUE);
            }
            cell.getCTTc().getTcPr().setVMerge(vMerge);
        }
    }
}


结语

标签:Map,word,SpringBoot,表格,int,new,poi,import,table
From: https://blog.csdn.net/longshehui/article/details/143200182

相关文章

  • 【磐维数据库】WDR(Wordload Dignosis Report)报告
    WDR(WordloadDignosisReport)报告简介WDR报告是磐维数据库的工作负载诊断报告,它基于两个不同时间点系统的性能快照数据WDRSnapshot,生成这两个时间点之间的性能报告。WDRSnapshot的数据来源于DBE_PERFSchema内的视图。通过WDR报告,我们可以深入了解数据库在特定时间段内的运......
  • springboot校园论坛网站-毕业设计源码11401
    基于Java,web的校园论坛网站设计与实现摘 要基于Java语言和Springboot框架的校园论坛网站设计与实现,为校园内的师生提供了丰富的功能和便捷的服务。本论文旨在详细介绍该网站的设计思路、功能特点以及技术实现。论文介绍了网站的注册与登录功能,用户可以通过提供必要信息......
  • Springboot知识点总结
    一、传统使用配置文件方式创建Java对象:1、创建一个普通的Maven项目,并加入依赖:<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.1</version></dependency>&......
  • Java Springboot 接收前端上传图片,并返回路径让前端显示图片
    一、接收前端图片并保存并为前端返回一个图片路径. @RestController@RequestMapping("/upload")publicclassUploadImgController{@Autowired(required=false)privateResourceLoaderresourceLoader;@Value(value="/Users/user/Java/Upload/Serve......
  • 我耗费大半年为PPT和Word开发了增强版拼音指南
    无论是WPS还是Word的拼音指南,抑或是市面上已有的汉字转拼音在线工具,采用的都是极其简单的上下文规则,利用已有的词库或字典数据,进行上下文匹配,从而完成拼音标注。但汉字的拼音标注,实际上比我们想象得更为复杂。如果只是采取简单的上下文匹配的规则,还不足以确保拼音标注在一个较......
  • springboot 整合mybatis
    1、SpringBoot+MyBatis一、简单回顾一下MyBatis核心对象包括以下三个:SqlSessionFactoryBuliderSqlSessionFactorySqlSessionSqlSessionFactoryBuilder-->SqlSessionFactory-->SqlSession 关于MyBatis的事务管理机制(两种)<transactionManagertype="JDBC"/......
  • springboot+vue展位设计模型库网站的java开发与设计
    目录系统实现截图详细技术介绍本课题软硬件环境核心代码部分展示其他springboot项目推荐详细视频演示源码获取系统实现截图详细技术介绍系统采用了基于SpringBoot、Vue和MySQL的三层结构体系。前端部分通过Vue框架构建用户界面,实现页面展示和交互功能,后端则利......
  • JAVA开源项目 基于Vue和SpringBoot购物商城网站
    本文项目编号T032,文末自助获取源码\color{red}{T032,文末自助获取源码}......
  • JAVA开源项目 基于Vue和SpringBoot高校心理教育辅导系统
    本文项目编号T031,文末自助获取源码\color{red}{T031,文末自助获取源码}......
  • 基于Springboot企业人事管理系统【附源码+文档】
    ......