首页 > 其他分享 >springBoot 整合 poi 导出带有复杂表格(合并表格)的word文件

springBoot 整合 poi 导出带有复杂表格(合并表格)的word文件

时间:2023-08-24 10:47:41浏览次数:38  
标签:word springBoot 表格 List workReportDetailVO import table document col

1.Maven依赖见上一篇文章

直接贴源码如下:

package com.mingx.pms.web.system.file;

import cn.hutool.core.date.DateUtil;
import com.mingx.pms.constant.SystemInfo;
import com.mingx.pms.entities.workplan.plan.vo.WorkPlanDetailExportVO;
import com.mingx.pms.entities.workplan.plan.vo.WorkPlanDetailQueryRO;
import com.mingx.pms.entities.workplan.plan.vo.WorkPlanDetailVO;
import com.mingx.pms.entities.workplan.report.constant.ReportTypeDict;
import com.mingx.pms.entities.workplan.report.vo.*;
import com.mingx.pms.entity.PageResult;
import com.mingx.pms.entity.Paginator;
import com.mingx.pms.exception.CustomException;
import com.mingx.pms.tools.BillCodeUtil;
import com.mingx.pms.workplan.service.plan.IWorkPlanDetailService;
import com.mingx.pms.workplan.service.report.IWorkReportService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.xwpf.usermodel.*;
import org.camunda.feel.syntaxtree.In;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @Description: 生产计划报告模块导出
 * @Author: gch
 * @Date: 2023/8/18 10:34
 */
@Api(value = "WorkPlanReportExportProvider", tags = "导出-生产计划报告模块")
@Controller
public class WorkPlanReportExportProvider extends BaseExportProvider{

    @Resource
    private IWorkReportService workReportService;

    @PostMapping("/workPlanReport/export")
    @ApiOperation(value = "导出生产计划报告Word", notes = "导出生产计划报告Word", produces = "application/octet-stream")
    public void exportWord(@RequestBody GenerateDetailRO generateDetailRO, HttpServletResponse response) throws IOException {
        String reportTypeDesc;
        String descByType;
        if (ReportTypeDict.MONTH.getCode().equals(generateDetailRO.getReportType())) {
            reportTypeDesc = ReportTypeDict.MONTH.getDesc();
            descByType = "本月";
        } else if (ReportTypeDict.WEEK.getCode().equals(generateDetailRO.getReportType())) {
            reportTypeDesc = ReportTypeDict.WEEK.getDesc();
            descByType = "本周";
        } else {
            throw new CustomException("报告类型错误", WorkPlanReportExportProvider.class.toString());
        }
        if (Objects.isNull(generateDetailRO.getReportId())) {
            throw new CustomException("报告id必填", WorkPlanReportExportProvider.class.toString());
        }
        WorkReportDetailVO workReportDetailVO = workReportService.generateDetailInfo(generateDetailRO);
        // 创建一个新的Word文档
        XWPFDocument document = new XWPFDocument();
        String formatStart = DateUtil.format(workReportDetailVO.getReportStartTime(), SystemInfo.DATE_CHINESE);
        String formatEnd = DateUtil.format(workReportDetailVO.getReportEndTime(), SystemInfo.DAY_CHINESE);
        String title = workReportDetailVO.getProjectDepartName() +
                "生产作业" + reportTypeDesc + "(" + formatStart + "-" + formatEnd + " )";
        addParagraphCenter(document, title);
        // 添加段落
        addParagraph(document, "一、电网运行总体情况:");
        addContent(document,"1、电网安全情况:");
        if (workReportDetailVO.getSafeSituationTextList().isEmpty()) {
            addContent(document, "");
        } else {
            for (String content : workReportDetailVO.getSafeSituationTextList()) {
                addContent(document, content);
            }
        }

        addContent(document,"2、电网运行情况:");
        if (workReportDetailVO.getRunSituationTextList().isEmpty()) {
            addContent(document, "");
        } else {
            for (String content : workReportDetailVO.getRunSituationTextList()) {
                addContent(document, content);
            }
        }
        addParagraph(document, "二、违章情况");
        addContent(document, "1、本周发生恶性违章" + workReportDetailVO.getMalignancyBreakRuleNum() + "条,严重违章 " +
                workReportDetailVO.getSeriousBreakRuleNum() + " 条,一般违章 " + workReportDetailVO.getNormalBreakRuleNum() + " 条。");
        addParagraph(document, "三、作业计划执行情况");
        addContent(document, "1、月作业计划中本周(本月)应完成 " + workReportDetailVO.getShouldFinish() + " 条,实际完成 " +
                workReportDetailVO.getRealFinish() + " 条");
        // 添加表格
        List<String> headers = Arrays.asList("序号", "作业计划内容", "时间", "未执行原因");
        // 对象集合 转换为表格识别的 列表类型
        List<List<String>> data = new ArrayList<>();
        Integer order = 1;
        for (WorkPlanStatisticTableVO unExecutePlan : workReportDetailVO.getUnExecutePlans()) {
            List<String> attributeValues = getAttributeValues(unExecutePlan);
            // 在列表最前面添加序号
            attributeValues.add(0, order.toString());
            order++;
            data.add(attributeValues);
        }
        addTable(document, headers, data);

        addContent(document, "2、" + descByType + "新增其他作业计划 " + workReportDetailVO.getAddWorkPlanNum() + " 条(月计划中未计划的)");
        // 添加表格
        List<String> headers2 = Arrays.asList("序号", "作业计划内容", "时间");
        List<List<String>> data2 = new ArrayList<>();
        Integer order2 = 1;
        for (WorkPlanStatisticTableVO vo : workReportDetailVO.getAddPlans()) {
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, order2.toString());
            order2++;
            data.add(attributeValues);
        }
        addTable(document, headers2, data2);

        if (ReportTypeDict.WEEK.getCode().equals(generateDetailRO.getReportType())) {
            addContent(document, "3、下周新增其他作业计划 " + workReportDetailVO.getNextWeekAddWorkPlanNum() + " 条(月计划中未计划的)");
            // 添加表格
            List<String> headers3 = Arrays.asList("序号", "作业计划内容", "时间");
            List<List<String>> data3 = new ArrayList<>();
            Integer order3 = 1;
            for (WorkPlanStatisticTableVO vo : workReportDetailVO.getNextWeekAddPlans()) {
                List<String> attributeValues = getAttributeValues(vo);
                attributeValues.add(0, order3.toString());
                order3++;
                data.add(attributeValues);
            }
            addTable(document, headers3, data3);
        }

        addParagraph(document, "四、停电情况");
        addContent(document, "1、" + descByType + "主网停电 " + workReportDetailVO.getMainNetPowerCutNum() + " 次。");
        addContent(document, "2、" + descByType + "公司计划停电应执行 " + workReportDetailVO.getCompanyPlanNum() + " 次,实际执行 " +
                workReportDetailVO.getRealExecutePowerCutNum() + " 次,临时停电" + workReportDetailVO.getTempPowerCutNum()
                + "次,故障停电 " + workReportDetailVO.getBreakdownPowerCutNum() + " 次。重复停电 " + workReportDetailVO.getRepeatPowerCutNum() + " 次");
        addContent(document,descByType + "公司计划停电未执行情况");
        // 添加表格
        List<String> headers4 = Arrays.asList("序号", "项目部", "变电站/线路名称", "计划停电时间", "未执行原因");
        List<List<String>> data4 = new ArrayList<>();
        Integer order4 = 1;
        for (PowerCutUnExecuteStatisticTableVO vo : workReportDetailVO.getPowerCutUnExecuteInfos()) {
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, order4.toString());
            order4++;
            data.add(attributeValues);
        }
        addTable(document, headers4, data4);

        addContent(document, descByType + "临时停电情况");
        // 添加表格
        List<String> headers5 = Arrays.asList("序号", "项目部", "变电站/线路名称", "停电时间", "送电时间", "停电时长(h)", "损失电量(kWh)", "停电具体原因", "处理经过");
        List<List<String>> data5 = new ArrayList<>();
        Integer order5 = 1;
        for (PowerCutStatisticTableVO vo : workReportDetailVO.getTempPowerCutInfos()) {
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, order5.toString());
            order5++;
            data.add(attributeValues);
        }
        addTable(document, headers5, data5);

        addContent(document, descByType + "故障停电情况");
        // 添加表格
        List<String> headers6 = Arrays.asList("序号", "项目部", "变电站/线路名称", "停电时间", "送电时间", "停电时长(h)", "损失电量(kWh)", "停电具体原因", "处理经过");
        List<List<String>> data6 = new ArrayList<>();
        Integer order6 = 1;
        for (PowerCutStatisticTableVO vo : workReportDetailVO.getBreakdownPowerCutInfos()) {
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, order6.toString());
            order6++;
            data.add(attributeValues);
        }
        addTable(document, headers6, data6);

        addParagraph(document, "五、隐患及缺陷消除情况");
        // 添加表格
        List<List<String>> data7 = new ArrayList<>();
        Integer order7 = 1;
        for (DefectHandleStatisticTableVO vo : workReportDetailVO.getDefectHandleInfos()) {
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, order7.toString());
            order7++;
            data.add(attributeValues);
        }
        addMergeTable(document, data7);
        addContent(document,"严重及以上缺陷未消除情况说明:");
        if (workReportDetailVO.getSeriousDefectUneliminatedTextList().isEmpty()) {
            addContent(document, "");
        } else {
            for (String content : workReportDetailVO.getRunSituationTextList()) {
                addContent(document, content);
            }
        }
        // 这里是动态标题和内容
        for (OtherDetailVO otherDetailVO : workReportDetailVO.getOtherDetailInfoList()) {
            addParagraph(document, otherDetailVO.getTitle());
            for (String content : otherDetailVO.getContents()) {
                addContent(document, content);
            }
        }

        // 设置响应头信息
        response.setHeader("Content-Disposition", "attachment; filename=" + title + ".docx");
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        // 将文档写入输出流
        document.write(response.getOutputStream());
        document.close();
    }

    /**
     * @author: gch
     * @Description: 添加基础文本内容
     * @Date: 2023/8/19 12:12
     * @Param:
     * @return:
     */
    private void addContent(XWPFDocument document, String content) {
        document.createParagraph().createRun().setText(content);
    }

    /**
     * @author: gch
     * @Description: 添加段落
     * @Date: 2023/8/19 12:11
     * @Param:
     * @return:
     */
    private void addParagraph(XWPFDocument document, String s) {
        XWPFParagraph paragraph1 = document.createParagraph();
        paragraph1.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun run1 = paragraph1.createRun();
        run1.setBold(true);
        run1.setFontSize(16); // 设置标题字体大小
        run1.setText(s);
    }

    /**
     * @author: gch
     * @Description: 添加段落 居中
     * @Date: 2023/8/19 12:11
     * @Param:
     * @return:
     */
    private void addParagraphCenter(XWPFDocument document, String s) {
        XWPFParagraph paragraph1 = document.createParagraph();
        paragraph1.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun run1 = paragraph1.createRun();
        run1.setBold(true);
        run1.setFontSize(16); // 设置标题字体大小
        run1.setText(s);
    }

    /**
     * @author: gch
     * @Description: 添加动态表格
     * @Date: 2023/8/19 12:11
     * @Param:
     * @return:
     */
    private void addTable(XWPFDocument document, List<String> headers, List<List<String>> data) {
        Integer rowNum = 2;
        if (!Objects.isNull(data) && !data.isEmpty()) {
            rowNum = data.size() + 1;
        }
        // 添加表格
        XWPFTable table = document.createTable(rowNum, headers.size()); // 创建一个3行3列的表格

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1000");
                addCellCenterStyle(cell);
            }
        }

        // 设置表头
        for (int col = 0; col < headers.size(); col++) {
            XWPFTableCell cell = table.getRow(0).getCell(col);
            cell.setText(headers.get(col));
        }
        // 设置示例数据
        for (int row = 0; row < data.size(); row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row + 1).getCell(col);
                cell.setText(data.get(row).get(col));
            }
        }
    }

    /**
     * @author: gch
     * @Description: 添加动态表格
     * @Date: 2023/8/19 12:11
     * @Param:
     * @return:
     */
    private void addMergeTable(XWPFDocument document, List<List<String>> data) {
        Integer rowNum = 4;
        if (!Objects.isNull(data) && !data.isEmpty()) {
            rowNum = data.size() + 3;
        }
        // 添加表格
        XWPFTable table = document.createTable(rowNum, 10);

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < 10; col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1000");
                addCellCenterStyle(cell);
            }
        }

        mergeCellsHorizontal(table, 0, 1, 6);
        mergeCellsHorizontal(table, 0, 7, 9);
        mergeCellsHorizontal(table, 1, 1, 2);
        mergeCellsHorizontal(table, 1, 3, 4);
        mergeCellsHorizontal(table, 1, 5, 6);

        mergeCellsVertically(table, 0, 0, 2);
        mergeCellsVertically(table, 7, 1, 2);
        mergeCellsVertically(table, 8, 1, 2);
        mergeCellsVertically(table, 9, 1, 2);
        //手动设置表头
        addTableContext(table, 0, 0, "项目部");
        addTableContext(table, 0, 1, "本周发现及处理情况");
        addTableContext(table, 0, 7, "累计未消除缺陷");

        addTableContext(table, 1, 1, "危急缺陷");
        addTableContext(table, 1, 3, "重大缺陷");
        addTableContext(table, 1, 5, "一般缺陷");

        addTableContext(table, 1, 7, "危急缺陷");
        addTableContext(table, 1, 8, "重大缺陷");
        addTableContext(table, 1, 9, "一般缺陷");

        addTableContext(table, 2, 1, "发现");
        addTableContext(table, 2, 2, "消除");
        addTableContext(table, 2, 3, "发现");
        addTableContext(table, 2, 4, "消除");
        addTableContext(table, 2, 5, "发现");
        addTableContext(table, 2, 6, "消除");

        // 设置示例数据
        for (int row = 0; row < data.size(); row++) {
            for (int col = 0; col < 10; col++) {
                XWPFTableCell cell = table.getRow(row + 3).getCell(col);
                cell.setText(data.get(row).get(col));
            }
        }
    }

    private static void addTableContext(XWPFTable table, int row, int col, String text) {
        XWPFTableCell cell = table.getRow(row).getCell(col);
        cell.setText(text);
    }

    /**
     * @author: gch
     * @Description: 添加水平居中韩国样式
     * @Date: 2023/8/19 12:11
     * @Param:
     * @return:
     */
    private void addCellCenterStyle(XWPFTableCell cell) {
        CTTc ctTc = cell.getCTTc();
        //获取 CTP
        CTP ctP = (ctTc.sizeOfPArray() == 0) ?
                ctTc.addNewP() : ctTc.getPArray(0);
        //获取段落
        XWPFParagraph par = cell.getParagraph(ctP);
        //设置水平居中
        par.setAlignment(ParagraphAlignment.CENTER);
        // 垂直居中
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);

    }

    /**
     * @Description: 跨列合并
     * table要合并单元格的表格
     * row要合并哪一行的单元格
     * fromCell开始合并的单元格
     * toCell合并到哪一个单元格
     */
    public static  void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if ( cellIndex == fromCell ) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * @Description: 跨行合并
     * table要合并单元格的表格
     * col要合并哪一列的单元格
     * fromRow从哪一行开始合并单元格
     * toRow合并到哪一个行
     */
    public  void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            if ( rowIndex == fromRow ) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * @Description: 获取对象属性值并转换成字符串列表
     * @Author: gch
     * @Date: 2023/8/23 10:54
     */
    public static List<String> getAttributeValues(Object obj) {
        Class<?> objClass = obj.getClass();
        List<String> valuesList = new ArrayList<>();
        // 获取对象定义的所有属性
        Field[] fields = objClass.getDeclaredFields();
        // 遍历属性并获取属性值
        for (Field field : fields) {
            field.setAccessible(true); // 设置私有属性可访问
            try {
                Object value = field.get(obj);
                String valueStr = (value != null) ? value.toString() : "";
                valuesList.add(valueStr);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return valuesList;
    }

}

运行结果如下:

 

 

标签:word,springBoot,表格,List,workReportDetailVO,import,table,document,col
From: https://www.cnblogs.com/guanxiaohe/p/17653539.html

相关文章

  • SpringBoot 测试实践 - 3:@MockBean、@SpyBean 、提升测试运行速度、Testcontainer
    编写测试的时候,我们必须保证外部依赖行为一致,也需要模拟一些边界条件,所以我们需要使用Mock来模拟对象的行为。SpringBoot提供了@MockBean和@SpyBean注解,可以方便地将模拟对象与Spring测试相结合,简化测试代码的编写@MockBean@MockBean是SpringBootTest提供的注解,用......
  • spring和springboot笔试题
    springboot选择题、判断题_西凉辰的博客-CSDN博客Java常见的spring笔试选择题_spring选择题_学亮编程手记的博客-CSDN博客 ......
  • 如何用 ONLYOFFICE 宏隐藏电子表格的行与列
    管理大规模数据库可能会非常耗时,这时就能体会到ONLYOFFICE宏的好处,它可以自动执行任务并挖掘电子表格的潜力。在这篇文章中,我们会展示如何创建一个用户友好的宏来隐藏或展开特定的行和列。此外,虽然我们文件中的宏示例部分中有一个类似的宏,但是这个宏更加用户友好。什么是ONLYO......
  • springboot之RedisTemplate的访问单机,哨兵,集群模式
    springboot2默认已经使用了lettuce-core,没有使用jedis和Redisson,springboot1使用的是jedis。我使用的springboot版本是2.6.14。(对应的lettuce版本为6.1.10.RELEASE,对应jedis版本为3.7.1)<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactI......
  • vue eslint 报错 error “Component name “*****“ should always be multi-word”,该
    出现的问题: 在 vue-cli 创建的项目中,创建文件并命名后,会报  “Componentname"*****"shouldalwaysbemulti-word”  报错;报错截图示例如下:Componentname"******"shouldalwaysbemulti-word.eslintvue/multi-word-component-names报错的原因: 在组件命......
  • SpringBoot集成liquibase
    Liquibase是一个用于跟踪、管理和应用数据库变化的开源的数据库重构工具。它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制。前置准备创建一个SpringBoot项目开发环境SpringBoot-2.7.14�Java(jdk8)Mysql-8.0.27开始集成引入坐标mysql-conne......
  • 如何复制word的图文到百度编辑器中自动上传
    ​ 这种方法是servlet,编写好在web.xml里配置servlet-class和servlet-mapping即可使用后台(服务端)java服务代码:(上传至ROOT/lqxcPics文件夹下)<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%@     page contentType="text/html;cha......
  • word在线预览1.直接预览-格式问题(效果差)2.使用微软接口或第三方收费接口(必须是外网,可
    1.先介绍第一种方案(纯前端)npminstall以下依赖--save"@vue-office/docx":"^1.3.0", "@vue/composition-api":"^1.3.0","vue-demi":"^0.14.5",<template><divclass="app-container"......
  • 如何复制word的图文到CKEditor中自动上传
    ​ 在之前在工作中遇到在富文本编辑器中粘贴图片不能展示的问题,于是各种网上扒拉,终于找到解决方案,在这里感谢一下知乎中众大神以及TheViper。通过知乎提供的思路找到粘贴的原理,通过TheViper找到粘贴图片的方法。其原理为一下步骤:监听粘贴事件;【用于插入图片】获取光标位置;【......
  • WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'
    我的selenium的版本是4.11.2selenium4.10中已经不支持desired_capabilities参数如果要传这个参数的话建议用selenium==4.9.1参考《Appium新版本引发的一个问题》......