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

  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,如果您要使用poi-tl导出Word文档并合并单元格,可以按照以下步骤进行操作: 1. 首先,准备一个Word模板文件,其中包含需要合并单元格表格。可以使用MS Word或其他工具创建模板文件。在模板文件中,使用`${}`占位符来标识需要填充数据的位置,使用`#for`和`#end`标记来循环生成多行数据。示例模板文件如下: ``` 姓名\t性别\t年龄\t住址 #for(user in users) ${user.name}\t${user.gender}\t${user.age}\t${user.address} #end ``` 2. 在Java代码中,使用poi-tl的模板引擎来加载模板文件,并将数据绑定到模板中。在模板中,使用`#merge`标记来指定需要合并单元格区域。示例代码如下: ```java // 加载模板文件 InputStream is = new FileInputStream("template.docx"); XWPFTemplate template = XWPFTemplate.compile(is).render(new HashMap<String, Object>() {{ // 绑定数据 List<User> users = Arrays.asList( new User("张三", "男", 20, "北京"), new User("李四", "女", 22, "上海"), new User("王五", "男", 25, "广州") ); put("users", users); }}); // 获取表格合并单元格 IBody body = template.getDocument().getBody(); List<XWPFTable> tables = body.getTables(); XWPFTable table = tables.get(0); // 假设第一个表格需要合并单元格 table.getRow(0).getCell(0).setText("姓名"); table.getRow(0).getCell(1).setText("性别"); table.getRow(0).getCell(2).setText("年龄"); table.getRow(0).getCell(3).setText("住址"); for (int i = 1; i <= 3; i++) { table.getRow(i).getCell(0).setText("#{" + "users[" + (i - 1) + "].name}"); table.getRow(i).getCell(1).setText("#{" + "users[" + (i - 1) + "].gender}"); table.getRow(i).getCell(2).setText("#{" + "users[" + (i - 1) + "].age}"); table.getRow(i).getCell(3).setText("#{" + "users[" + (i - 1) + "].address}"); } table.mergeCells(1, 1, 2, 2); // 合并单元格 // 导出文档 template.write(new FileOutputStream("output.docx")); template.close(); ``` 在模板中,使用`${}`占位符来引用数据对象的字段,使用`#merge`标记来指定需要合并单元格区域。在Java代码中,使用`table.mergeCells()`方法来合并单元格,其中参数分别为起始行、起始列、结束行、结束列。在本例中,我们将第2行第2列到第3行第3列的单元格进行了合并。 希望这些信息能够对您有所帮助!如果您还有其他问题,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值