springboot中使用poi-tl导出word(包含表格合并单元格)实例

一、背景

        在业务开发过程中,遇到有需要生成包含表格的word文档,且一部分表格需要动态生成,且需要根据数据来合并单元格,最后呈现的方式如下图:

 一开始想到的解决方案是通过freemarker来生成,但是需要转xml生成模板,过程比较复杂,因此,在查阅一些资料后,最终选择了poi-tl来实现。相比于freemarker,poi-tl导出word的好处在于可以直接使用word模板,比较直观,且比较好调整格式。

二、实现

1、引入jar包

<!-- word导出 -->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.7.3</version>
</dependency>
<!--  上面需要的依赖-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>

2、构造word模板

        1)简单包含属性的表格模板

        

姓名{{name}}年龄{{age}}
身份证号{{idCardNo}}家庭住址{{addr}}
联系电话{{tel}}学历{{education}}
是否党员{{isPartyMember}}毕业院校{{school}}
紧急联系人{{contactPer}}紧急联系方式{{contactTel}}
邮箱{{email}}

        2)需要循环list填充的表格模板

{{userList}} 姓名性别年龄
[name][sex][age]

        3)需要动态合并单元格的表格模板

{{userList}}班级小组姓名学号

        合并单元格操作需要在代码实现

3、代码实现合并单元格

public void export(HttpServletResponse response, SysDefineMethod sysDefineMethod) {
       
        Map<String, Object> dataMap = new HashMap<>();
        //企业基本信息
        dataMap.put("baseInfo", baseInfo);
        //机组信息
        dataMap.put("unitList", unitList);
        //人员信息
        dataMap.put("userList", userList);
        ClassPathResource classPathResource = new ClassPathResource("templates/template.docx");
        String resource = classPathResource.getUrl().getPath();
        //给需要单独处理的表格绑定处理策略
        Configure config = Configure.newBuilder()
                .bind("unitList", new DefineMethodPolicy())
                .build();
        XWPFTemplate template = XWPFTemplate.compile(resource, config).render(dataMap);
        // 生成的word格式
        String formatSuffix = ".docx";
        // 拼接后的文件名
        String fileName = "GreenHouseGas" + System.currentTimeMillis() + formatSuffix;//文件名
        try {
            //=================生成word到设置浏览默认下载地址=================
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 设置文件名
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            OutputStream out = response.getOutputStream();
            template.write(out);
            out.flush();
            out.close();
            template.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

机组信息合并单元格策略类

package com.carbon.system.policy;

import com.alibaba.fastjson.JSON;
import com.carbon.system.domain.SysDefineMethod;
import com.carbon.system.domain.vo.ElectricityInfoVo;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author admin
 */
public class DefineMethodPolicy extends DynamicTableRenderPolicy {
    // 填充数据所在行数
    int listsStartRow = 2;

    @Override
    public void render(XWPFTable table, Object data) {
        if (null == data) {
            return;
        }
        List<SysDefineMethod> defineMethodList = JSON.parseArray(JSON.toJSONString(data), SysDefineMethod.class);
        Map<Integer, List<SysDefineMethod>> unitDefineMethodMap = defineMethodList.stream().collect(Collectors.groupingBy(SysDefineMethod::getUnitId));
        Map<String, List<SysDefineMethod>> unitParamMap = defineMethodList.stream().collect(Collectors.groupingBy(defineMethod->defineMethod.getUnitId()+"-"+defineMethod.getParamType()));
        if (!CollectionUtils.isEmpty(defineMethodList)) {
            table.removeRow(listsStartRow);
            List<RowRenderData> dataList = new ArrayList<>();
            for (SysDefineMethod tmp : defineMethodList) {
                String paramType = tmp.getParamType();
                switch (paramType){
                    case "0":
                        tmp.setParamType("测试参数1");
                        break;
                    case "1":
                        tmp.setParamType("测试参数2");
                }
                RowRenderData renderData = RowRenderData.build(tmp.getUnitName(),tmp.getParamType(),tmp.getParamMonth().toString(),
                        tmp.getEquipmentModel()==null?"":tmp.getEquipmentModel(),tmp.getCheckFrequency()==null?"":tmp.getCheckFrequency(),
                        tmp.getCheckFrequencyRule()==null?"":tmp.getCheckFrequencyRule(),tmp.getCheckMethodStandard()==null?"":tmp.getCheckMethodStandard(),
                        tmp.getEntrustOrgName()==null?"":tmp.getEntrustOrgName(),tmp.getCheckReportNo()==null?"":tmp.getCheckReportNo(),
                        tmp.getCheckDate()==null?"":tmp.getCheckDate().toString(),tmp.getMethodStandardEntrust()==null?"":tmp.getMethodStandardEntrust(),
                        tmp.getDefaultValue()==null?"":tmp.getDefaultValue());
                dataList.add(renderData);
            }
            // 循环插入行
            for (int i = dataList.size() - 1; i >= 0; i--) {
                XWPFTableRow insertNewTableRow = table.insertNewTableRow(listsStartRow);
                for (int j = 0; j < 12; j++) {
                    insertNewTableRow.createCell();
                }
                // 渲染单行机组数据
                MiniTableRenderPolicy.Helper.renderRow(table, listsStartRow, dataList.get(i));
            }
            List<Integer> unitList = JSON.parseArray(JSON.toJSONString(unitDefineMethodMap.keySet()), Integer.class);
            List<String> paramList = JSON.parseArray(JSON.toJSONString(unitParamMap.keySet()), String.class);
            //处理合并
            for (int i = 0; i < dataList.size(); i++) {
                //处理第一列机组合并
                Object v = dataList.get(i).getCells().get(0).getCellText();
                String unit_name = String.valueOf(v);
                for (int j = 0; j < unitList.size(); j++) {
                    Integer unitId = unitList.get(j);
                    String unitName = unitDefineMethodMap.get(unitId).get(0).getUnitName();
                    List<SysDefineMethod> tmpList = unitDefineMethodMap.get(unitId);
                    if (unit_name.equals(unitName)) {
                        // 合并第0列的第i+2行到第i+unitSize行的单元格
                        TableTools.mergeCellsVertically(table, 0, i + 2, i + tmpList.size()+1);
                        //处理垂直居中
                        for (int y = 0; y < 12; y++) {
                            XWPFTableCell cell = table.getRow(i + 2).getCell(y);
                            cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中
                        }
                        unitList.remove(j);
                        break;
                    }
                }
                //处理第二列参数类型合并
                Object v1 = dataList.get(i).getCells().get(1).getCellText();
                String paramType = v+"-"+v1;
                for (int j = 0; j < paramList.size(); j++) {
                    String key = paramList.get(j);
                    List<SysDefineMethod> tmpList = unitParamMap.get(key);
                    String paramName=tmpList.get(0).getUnitName()+"-"+tmpList.get(0).getParamType();
                    if (paramType.equals(paramName)) {
                        // 合并第1列的第i+1行到第i+unitSize行的单元格
                        TableTools.mergeCellsVertically(table, 1, i+2, i + tmpList.size()+1);
                        //处理垂直居中
                        for (int y = 0; y < 12; y++) {
                            XWPFTableCell cell = table.getRow(i + 2).getCell(y);
                            cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中
                        }
                        paramList.remove(j);
                        break;
                    }
                }
            }
        }
    }
}

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在Spring Boot使用poi-tl库来导出带有合并列的Word表格并下载,您可以按照以下步骤操作: 1. 首先,确保您的Spring Boot项目已经添加了poi-tl的依赖。您可以在pom.xml文件添加以下依赖: ```xml <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.6.0</version> </dependency> ``` 2. 创建一个Controller来处理导出请求。例如,创建一个名为WordExportController的类,并添加一个处理导出请求的方法。 ```java import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.*; import com.deepoove.poi.util.BytePictureUtils; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @Controller public class WordExportController { @GetMapping("/export") public ResponseEntity<InputStreamResource> exportWord() throws IOException { // 创建一个数据模型 List<List<String>> tableData = new ArrayList<>(); tableData.add(createRow("Merged Cells", "Cell 3")); tableData.add(createRow("Cell 4", "Cell 6")); // 使用poi-tl的XWPFTemplate来生成Word文档 XWPFTemplate template = XWPFTemplate.compile("templates/template.docx").render( new DataTable(tableData) .setHeader(createRow("Header 1", "Header 2")) .setCellWidth(2000) // 设置单元格宽度 .setHeaderCellStyle(new CellStyle().setBold(true).setColor("FFFFFF").setBgColor("336699")) .setOddRowCellStyle(new CellStyle().setColor("FFFFFF").setBgColor("99CCFF")) .setEvenRowCellStyle(new CellStyle().setColor("FFFFFF").setBgColor("CCEEFF")) ); // 将生成的Word文档转换为字节数组 ByteArrayOutputStream out = new ByteArrayOutputStream(); template.write(out); byte[] documentBytes = out.toByteArray(); // 设置下载响应的头信息 HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", "merged_table.docx"); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 创建一个包含Word文档字节数组的InputStreamResource InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(documentBytes)); // 返回响应实体 return ResponseEntity.ok() .headers(headers) .body(resource); } private List<String> createRow(String cell1, String cell2) { List<String> row = new ArrayList<>(); row.add(cell1); row.add(cell2); return row; } } ``` 3. 在resources目录下创建一个名为template.docx的Word模板文件。在模板文件,您可以根据自己的需求设置表格样式和内容。 4. 启动您的Spring Boot应用程序,并访问导出请求的URL(例如:http://localhost:8080/export)。将会自动下载名为merged_table.docx的Word文档,其包含合并列的表格。 请确保按照您的需求修改代码,并根据模板文件的位置进相应的调整。 希望对您有所帮助!如果您有任何其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值