poi-tl导出word复杂表格(单元格合并)_poi-tl 合并单元格-程序员宅基地

技术标签: word  

poi-tl 是基于 Apache POI ,使用时请注意poi的版本依赖冲突问题

 添加依赖

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

    <dependency>
      <groupId>com.deepoove</groupId>
      <artifactId>poi-tl</artifactId>
      <version>1.10.3</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.11.0</version>
    </dependency>

模板文件内容(我这里用的是下面那个模板内容)

代码

import com.deepoove.poi.data.RowRenderData;

import java.util.List;
import java.util.Map;

public class ServerTableData {

    /**
     *  携带表格中真实数据
     */
    private List<RowRenderData> serverDataList;

    /**
     * 携带要分组的信息
     */
    private List<Map<String, Object>> groupDataList;

    /**
     * 需要合并的列,从0开始
     */
    private Integer mergeColumn;

    public List<RowRenderData> getServerDataList() {
        return serverDataList;
    }

    public void setServerDataList(List<RowRenderData> serverDataList) {
        this.serverDataList = serverDataList;
    }

    public List<Map<String, Object>> getGroupDataList() {
        return groupDataList;
    }

    public void setGroupDataList(List<Map<String, Object>> groupDataList) {
        this.groupDataList = groupDataList;
    }

    public Integer getMergeColumn() {
        return mergeColumn;
    }

    public void setMergeColumn(Integer mergeColumn) {
        this.mergeColumn = mergeColumn;
    }
}

import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.TableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;

import java.util.List;
import java.util.Map;

public class ServerTablePolicy extends DynamicTableRenderPolicy {
    @Override
    public void render(XWPFTable xwpfTable, Object tableData) throws Exception {
        if (null == tableData) {
            return;
        }

        // 参数数据声明
        ServerTableData serverTableData = (ServerTableData) tableData;
        List<RowRenderData> serverDataList = serverTableData.getServerDataList();
        List<Map<String, Object>> groupDataList = serverTableData.getGroupDataList();
        Integer mergeColumn = serverTableData.getMergeColumn();

        if (CollectionUtils.isNotEmpty(serverDataList)) {
            // 先删除一行, demo中第一行是为了调整 三线表 样式
//            xwpfTable.removeRow(1);//如果表单里面只有一行表头信息的话,这里设置成1
            xwpfTable.removeRow(2);//如果表单里面有两行数据,则设置成2

            // 行从中间插入, 因此采用倒序渲染数据
            for (int i = serverDataList.size() - 1; i >= 0; i--) {
//                XWPFTableRow newRow = xwpfTable.insertNewTableRow(1);//从表单的哪行开始插入数据,一般表单有一个标题,所以这里设置1;
                XWPFTableRow newRow = xwpfTable.insertNewTableRow(2);//从表单的哪行开始插入数据,如果表单里面有两行,这是设置成2
//                newRow.setHeight(400);
                for (int j = 0; j < 3; j++) {//因为我的表单是3列,所以这里是3
                    newRow.createCell();
                }
                // 渲染一行数据
                TableRenderPolicy.Helper.renderRow(newRow, serverDataList.get(i));
            }

            // 处理合并
            for (int i = 0; i < serverDataList.size(); i++) {
                // 获取要合并的名称那一列数据 mergeColumn代表要合并的列,从0开始
                String typeNameData = serverDataList.get(i).getCells().get(mergeColumn).getParagraphs().get(0).getContents().get(0).toString();
                for (int j = 0; j < groupDataList.size(); j++) {
                    String typeNameTemplate = String.valueOf(groupDataList.get(j).get("typeName"));
                    int listSize = Integer.parseInt(String.valueOf(groupDataList.get(j).get("listSize")));
                    if(listSize == 1){
                        continue;
                    }
                    // 若匹配上 就直接合并
                    if (typeNameTemplate.equals(typeNameData)) {
//                        TableTools.mergeCellsVertically(xwpfTable, 0, i + 1, i + listSize);//如果表单里面只有一行表头信息的话,用这个语句
                        TableTools.mergeCellsVertically(xwpfTable, 0, i + 2, i + 1 + listSize);//如果表单里面有两行数据,则用这个语句
                        groupDataList.remove(j);
                        break;
                    }
                }
            }
        }
    }
}
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.util.PoitlIOUtils;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.*;
import java.util.*;

public class PreTestExport {

    public static void main(String[] args) throws Exception{
        // 获取模板文件流
//        InputStream resourceAsStream = new FileInputStream(new File("E:/word/poi-tl-pre-old2.docx"));
        InputStream resourceAsStream = new FileInputStream(new File("E:/word/poiaa.docx"));
        //poi-tl 配置
        ConfigureBuilder builder = Configure.builder();
        builder.useSpringEL(false);

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

        // 伪造一个表格数据
        //单个表格
        ServerTableData oneTable = getServerTableData();
        map.put("oneTable",oneTable);
        map.put("title", "2023");
        builder.bind("oneTable",new ServerTablePolicy());


        XWPFTemplate template = XWPFTemplate.compile(Objects.requireNonNull(resourceAsStream), builder.build()).render(map);
        // 获取表格对象
        XWPFTable table = template.getXWPFDocument().getTableArray(0);

        // 设置表格边框样式为黑色实线
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        CTTblBorders tblBorders = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders();
        CTBorder border = tblBorders.addNewTop();
        border.setVal(STBorder.SINGLE);
        border.setColor("000000");

        // HttpServletResponse response
        OutputStream out = new FileOutputStream(new File("E:/word/poi-tl-降水new.docx"));
        BufferedOutputStream bos = new BufferedOutputStream(out);
        template.write(bos);
        bos.flush();
        out.flush();
        PoitlIOUtils.closeQuietlyMulti(template, bos, out);

    }

    private static ServerTableData getServerTableData() {
        ServerTableData serverTableData = new ServerTableData();
        List<RowRenderData> serverDataList = new ArrayList<RowRenderData>();
        RowRenderData serverData1 = Rows.of("广州", "天河", "0.3").textFontSize(14).center().create();
        RowRenderData serverData2 = Rows.of("广州", "白云", "0.2").textFontSize(14).center().create();
        RowRenderData serverData3 = Rows.of("广州", "东山", "0.1").textFontSize(14).center().create();
        serverDataList.add(serverData1);
        serverDataList.add(serverData2);
        serverDataList.add(serverData3);

        RowRenderData fs = Rows.of("佛山", "禅城", "0.3").textFontSize(14).center().create();
        serverDataList.add(fs);

        RowRenderData sz1 = Rows.of("深圳", "南山", "0.3").textFontSize(14).center().create();
        RowRenderData sz2 = Rows.of("深圳", "福田", "0.3").textFontSize(14).center().create();
        serverDataList.add(sz1);
        serverDataList.add(sz2);

        List<Map<String, Object>> groupDataList = new ArrayList<Map<String, Object>>();
        Map<String, Object> groupData1 = new HashMap<String, Object>();
        groupData1.put("typeName", "广州");
        groupData1.put("listSize", "3");
        Map<String, Object> groupData2 = new HashMap<String, Object>();
        groupData2.put("typeName", "深圳");
        groupData2.put("listSize", "2");

        Map<String, Object> groupData3 = new HashMap<String, Object>();
        groupData3.put("typeName", "佛山");
        groupData3.put("listSize", "1");

        groupDataList.add(groupData1);
        groupDataList.add(groupData2);
        groupDataList.add(groupData3);

        serverTableData.setServerDataList(serverDataList);
        serverTableData.setGroupDataList(groupDataList);
        serverTableData.setMergeColumn(0);
        return serverTableData;
    }

}

结果

 

参考文档

https://blog.csdn.net/yuanay/article/details/127772831poi-tl导出表格,单元格合并https://blog.csdn.net/yuanay/article/details/127772831

poi-tl的使用(最全详解)_JavaSupeMan的博客-程序员宅基地官网地址poi-tl,简单的说,就是通过一些标记,如{ {text}},{ {@image}}等,放到你指定的word模板里,然后去读取替换这些值,再输出填充数据后的word,可以做生成报表的功能注意apache.poi版本要对应二、准备工作在D盘,自己创建两个文件夹,一个是用来存储模板文件,另一个是用来存储生成的文件我这里是在D盘D:\data\template 存放模板D:\data\word 存放生成的文件注意,{ {}}是官方指定的格式,可以查看官网,当然也可以自定义,这个后面来讲https://blog.csdn.net/JavaSupeMan/article/details/125654484

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_21526409/article/details/131150664

智能推荐

如何解决Invalid bound statement (not found):问题_invalid bound statement (not found): com.szkingdom-程序员宅基地

文章浏览阅读600次。在写ssm junit测试的时候一直报这个错, 配置文件以及包名都检查过了,一直没解决。各位大神帮帮忙org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.zking.ssm.mapper.LogininfoMapper.getUserByNameAndPwd at org.a..._invalid bound statement (not found): com.szkingdom.sfixp.parti.dao.partidao.

中心化傅里叶变换_傅里叶频谱中心化-程序员宅基地

文章浏览阅读6.8k次,点赞9次,收藏43次。参考文章:数字图像频谱中心化研究数字图像有时需要变换到频率做处理,比如滤波等。但直接对数字图像进行二维DFT变换得到的频谱图是高频在中间,低频在四角。为了把能量(在低频)集中起来便于使用滤波器,可以利用二维DFT的平移性质对频谱进行中心化。频谱图比较亮的地方就是低频,因为图像的能量一般都是集中在低频部分。所以推导出来的结论是:对数字图像的每个像素点的取值直接乘以(-1)^(x+y),x和y是像素坐标。这之后再做傅里叶变换,最后即为中心化后的傅里叶变换。代码:# 未中心化的傅里叶变_傅里叶频谱中心化

读《Boost程序库完全开发指南》_boost::适配器链-程序员宅基地

文章浏览阅读833次。读《Boost程序库完全开发指南》 2011-05-18 20:47:19| 分类: 读书|举报|字号 订阅 C++确实很复杂,神一样的0x不知道能否使C++变得纯粹和干爽? boost很复杂,感觉某些地方有过度设计和太过于就事论事的嫌疑,对实际开发工作的考虑太过于理想化。学习boost本身就是一个复杂度,有魄力在_boost::适配器链

css实例 css中id/class 详解样式表(外部样式表 内部样式表 内联样式 7种基础选择器 多重样式优先级 错误理解)[第一天]_css class-程序员宅基地

文章浏览阅读6.6k次,点赞4次,收藏18次。css实例css中的idcss中的class样式表外部样式表内部样式表内联样式7种基础选择器5种组合选择器后代选择和子代选择注意多重样式优先级选择器错误理解_css class

Acwing第72场周赛+Leetcode第314场周赛_acwing 第72场周赛4625. 压缩文件-程序员宅基地

文章浏览阅读309次。Acwing第72场周赛+Leetcode第314场周赛_acwing 第72场周赛4625. 压缩文件

计算机就业方向-程序员宅基地

文章浏览阅读6.8k次,点赞5次,收藏12次。希望看到这篇文章的学计算机、软件的同学可以互相转载,让大家都知道我们以后的道路是怎样的。有了方向,干什么都有动力,不是吗?(有点长,希望大家先分享,以后慢慢看,有用没用,我说了不算,你看看就知道了!)计算机专业就业方向一、 关于企业计算方向企业计算(Enterprise Computing)是稍时髦较好听的名词,主要是 指企业信息系统,如ERP软件(企业资源规划)、CRM软件(客户关系_计算机就业

随便推点

基于MATLAB的高斯白噪声和频率选择性衰落信道下的OFDM OTFS 16QAM QPSK LDPC Turbo调制解调误比特率性能仿真(附带代码和仿真说明)_ofdm系统在不同衰落信道下的误比特率性能分析-程序员宅基地

文章浏览阅读653次,点赞21次,收藏15次。同时,还对添加保护间隔、信道均衡等关键技术进行了详细讲解,并附带了仿真说明,使读者可以轻松理解和应用。通过本文的研究和分析,我们对OFDM和OTFS在高斯白噪声、频率选择性衰落信道下的误比特率性能有了更深入的理解。我们采用了16QAM和QPSK的调制方式、LDPC和Turbo的编码方式,并对添加保护间隔、信道均衡等关键技术进行了研究。Turbo编码也是一种常用的前向纠错码,它通过串并组合两个编码器的输出,并引入交织技术,在信道传输过程中提高了错误纠正能力。2.1 16QAM调制。OFDM调制解调技术。_ofdm系统在不同衰落信道下的误比特率性能分析

Android.mk 分析android buid工程需要的makefile知识点总结_android 解析android.mk工程-程序员宅基地

文章浏览阅读502次。1.0 make -C /home/wangxiancan/android -f build/core/main.mk all_modules -C 表示进入到某目录 执行(解析)其中的makefile -f 表示将后面的文件当做makefile文件解析 (make命令默认只识别如Makefile命名的文件,不过你会发现-C后面目录下已经有一个makefile了,并且这个m..._android 解析android.mk工程

UE5连接SQL数据库_ue5连接数据库-程序员宅基地

文章浏览阅读2.8k次。UE5连接SQL服务器_ue5连接数据库

spring boot 2.x整合dubbo-xml的方式_springboot 2.x 通过xml集成dubbo-程序员宅基地

文章浏览阅读514次。spring boot 2.x整合dubbo-xml的方式传统的项目都是基于xml配置文件的方式集成的dubbo,现在假如要升级框架到spring boot但是还是想用原来的方式整合dubbo,那么这篇文章对你应该有帮助项目结构生产者[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFRGvMHz-1575526058549)(C:\Users\bhh\..._springboot 2.x 通过xml集成dubbo

Vue.js npm错误:transpileDependencies.map不是一个函数_transpiledependencies.map is not a function-程序员宅基地

文章浏览阅读483次。这个错误通常是由于npm版本不兼容导致的。在旧版本的npm中,transpileDependencies是一个字符串数组,我们可以直接配置需要编译的依赖库。而在较新版本的npm中,transpileDependencies被改成了一个对象,并且需要使用map()方法来处理。因此,如果我们在较新版本的npm中使用了旧版本的配置方式,就会导致transpileDependencies.map不是一个函数的错误。_transpiledependencies.map is not a function

关于EXT JS 的所有组件_ext.js 组件-程序员宅基地

文章浏览阅读2.3k次。EXTJS的组件体系中有进40种组件,而这些组件又可以大致分成三大类,即基本组件、工具栏组件、表单及元素组件。 基本组件是构成Web UI的主体组件,因为这些组件在其他开发体系中也都有部分存在。这些组件丰富了传统Web UI 的表现,是EXTJS改善Web UI 的重要体现。 EXIJS的基本组件:xtype Class _ext.js 组件

推荐文章

热门文章

相关标签