Spring boot easyexcel 实现复合数据导出、按模块导出

这篇具有很好参考价值的文章主要介绍了Spring boot easyexcel 实现复合数据导出、按模块导出。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

场景:

  • 导出数据为1对多的复合数据
  • 一个模块是一条数据,直接填充数据无法实现

如图:

  • 红框内为一条数据(1对多),下方箭头指向为第二条数据
  • 如果直接填充,只能填充第一条,第二条就没办法了。
  • 由于多行都包含许多,固定表头,只能走填充路线,怎么实现呢

Spring boot easyexcel 实现复合数据导出、按模块导出,excel,spring boot,java,后端

实现思路流程:

准备一个导出基础填充模板,默认填充key

Spring boot easyexcel 实现复合数据导出、按模块导出,excel,spring boot,java,后端

计算,复制起始行、复制结束行、复制行数;用poi的 复制行方式生成新模块,也就是一条新的 1对多数据。
sheet.copyRows(startRows.get(i), endRows.get(i), copyStartRows.get(i), policy);
Spring boot easyexcel 实现复合数据导出、按模块导出,excel,spring boot,java,后端

  • 复制后

Spring boot easyexcel 实现复合数据导出、按模块导出,excel,spring boot,java,后端

根据填充fillKey 规律,生成填充key集合;然后进行填充key替换

Spring boot easyexcel 实现复合数据导出、按模块导出,excel,spring boot,java,后端

并返回待填充的 fillKeys,与数据对齐,进行数据填充。

如果数据过大,经测试一般一个 sheet 最好 100个复合数据,多的再进行sheet复制
xssfWorkbook.cloneSheet(0,"sheet" + (i+1));

参考代码:

    @ApiOperation(value = "数据-excel导出",notes = "首次调用会返回一个processId标识,查询进度携带标识")
    @GetMapping("/export")
    public ResultData exportHtMeta(String processId){
        HtMetaExcelProcessVo htMetaExcelProcessVo;
        if (!StringUtils.hasLength(processId)){
            try {
                htMetaExcelProcessVo=htMetaInfoService.exportHtMetaCopyModule(processId);
            } catch (Exception e) {
                throw new ExcelHandlerException("导入失败:"+e.getMessage());
            }
        }else {
            Cache cache = cacheManager.getCache(HtMetaConstants.EXPORT_PREFIX);
            htMetaExcelProcessVo=cache.get(processId,HtMetaExcelProcessVo.class);
            if (htMetaExcelProcessVo==null){
                return new ResultData(ErrorCodeEnum.NOT_FOUND_DATA.getCode(),"该导入uid,没有对应数据");
            }
            if (htMetaExcelProcessVo.getCurProcess().equals(htMetaExcelProcessVo.getTotalProcess())){
                htMetaExcelProcessVo.setImportStatus(HtMetaConstants.EXCEL_PROCESS_SUCCESS);
                htMetaExcelProcessVo.setMsg("导出成功");
            }
        }
        return new ResultData(htMetaExcelProcessVo);
    }
/**
     * 导出批次大小,每个sheet导出模块大小
     */
    private static final Integer SPLIT_SIZE=100;

    @Override
    public HtMetaExcelProcessVo exportHtMetaCopyModule(String exportKey) throws Exception{
        HtMetaExcelProcessVo excelProcessVo;
        Cache cache = cacheManager.getCache(HtMetaConstants.EXPORT_PREFIX);
        if (cache==null){
            throw new ExcelHandlerException("ehcahe 缓存配置异常");
        }
        if (StringUtils.hasLength(exportKey)){
            //检查是否存在已导出
            if (cache.get(exportKey)!=null){
                return cache.get(exportKey,HtMetaExcelProcessVo.class);
            }
        }else {
            exportKey = UUID.randomUUID().toString().replace("-", "");
        }
        ClassPathResource resource = new ClassPathResource("excel-template/导入模板.xlsx");
        String exportPath = new File("").getAbsolutePath() + File.separator + "ht-meta-export";
        if (!new File(exportPath).exists()){
            boolean mkdir = new File(exportPath).mkdir();
            log.info("导出目录创建:{}",mkdir);
        }
        File exportFile = new File(exportPath+File.separator+exportKey+".xlsx");
        log.info("华泰-元数据,导出文件:{}",exportFile.getAbsolutePath());
        //按数据生成-临时导入模板
        File tmpExportTemplate = null;
        ExcelWriter excelWriter =null;
        try {
            tmpExportTemplate = File.createTempFile("temp", ".xlsx");
            List<HtMetaClusterInfoVo> list = htMetaClusterInfoMapper.clusterList(new HtMetaClusterQo());
            log.info("导出数据条数:{}",list.size());
            int sheetSize = (list.size() / SPLIT_SIZE);
            if (sheetSize==1){
                excelProcessVo = new HtMetaExcelProcessVo(HtMetaConstants.EXCEL_PROCESS_ING, 0, 4, "正在导出");
            }else {
                excelProcessVo = new HtMetaExcelProcessVo(HtMetaConstants.EXCEL_PROCESS_ING, 0, 4+sheetSize, "正在导出");
            }
            excelProcessVo.setProcessId(exportKey);
            cache.put(exportKey,excelProcessVo);
            //阶段1
            refreshProcess(cache,exportKey);
            //单条导出
            if (list.size()==1){
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                excelWriter = EasyExcel.write(exportFile).withTemplate(resource.getInputStream()).build();
                WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
                HtMetaClusterInfoVo e = list.get(0);
                excelWriter.fill(new FillWrapper("data0", Collections.singletonList(e)), fillConfig, writeSheet);
                List<HtMetaNodeInfoVo> nodeInfoVos = e.getNodeInfoVos();
                List<HtMetaBsInfoVo> bsInfoVos = e.getBsInfoVos();
                excelWriter.fill(new FillWrapper("data1", nodeInfoVos), fillConfig, writeSheet);
                excelWriter.fill(new FillWrapper("data2", bsInfoVos), fillConfig, writeSheet);
                excelWriter.finish();
                excelProcessVo = new HtMetaExcelProcessVo(HtMetaConstants.EXCEL_PROCESS_SUCCESS, 4, 4, "导出成功");
                excelProcessVo.setProcessId(exportKey);
                cache.put(exportKey,excelProcessVo);
                return excelProcessVo;
            }
            int overSize;
            if (sheetSize>1){
                //剩余数量
                overSize = list.size() - (sheetSize * SPLIT_SIZE);
                log.info("剩余数据条数:{}",overSize);
            } else {
                overSize = 0;
            }
            log.info("开始生成数据导出模板");
            List<List<String>> fillKeys = HtMetaExcelUtil.copyMultiRow(6, 17,
                    12,list.size() - 1,
                    resource.getInputStream(), tmpExportTemplate);
            log.info("生成结束");
            //阶段2
            refreshProcess(cache,exportKey);
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter = EasyExcel.write(exportFile).withTemplate(tmpExportTemplate).build();
            //阶段3
            refreshProcess(cache,exportKey);
            String finalExportKey = exportKey;
            ExcelWriter finalExcelWriter = excelWriter;
            File finalTmpExportTemplate = tmpExportTemplate;
            CompletableFuture.runAsync(()->{
                try {
                    fiilTemplateExcel(finalExportKey, cache, finalExcelWriter, list, sheetSize, overSize, fillKeys, fillConfig);
                    log.info("填充结束");
                }finally {
                    if (finalExcelWriter!=null){
                        finalExcelWriter.finish();
                    }
                    boolean delete = finalTmpExportTemplate.delete();
                    log.info("临时导入模板删除: {}",delete);
                }
            });
        } catch (IOException e) {
            log.info("导出失败");
            throw e;
        }
        return excelProcessVo;
    }

HtMetaExcelUtil文章来源地址https://www.toymoban.com/news/detail-731993.html

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * @author xiaoshu
 * @description
 * @date 2023年09月01日 23:34
 */
@Slf4j
public class HtMetaExcelUtil {


    /**
     * 导出批次大小,每个sheet导出模块大小
     */
    private static final Integer SPLIT_SIZE=100;
    /**
     * poi对excel进行 多行模块复制,并替换 Fill填充前缀
     *
     * @param startRowIndex    模块-起始行index,excel标记行号-1
     * @param endRowIndex      模块-结束行
     * @param moduleRowSize    模块行数
     * @param copyCount        复制次数
     * @param sourceFileStream 源文件流
     * @param outFile          输出文件
     * @return List<List<String>> 填充fillKey列表
     */
    public static List<List<String>> copyMultiRow(int startRowIndex, int endRowIndex,
                                             int moduleRowSize, int copyCount,
                                             InputStream sourceFileStream,
                                             File outFile
    ) {
        File tempFile =null;
        int sheetSize=0;
        if (copyCount>SPLIT_SIZE){
            sheetSize= (copyCount + 1) / SPLIT_SIZE;
            log.info("复制sheet数量:{}",sheetSize);
            copyCount=SPLIT_SIZE-1;
        }
        //填充key列表
        List<List<String>> fillKeys = new LinkedList<>();
        //添加填充模板,默认key
        fillKeys.add(Arrays.asList("data0","data0","data1","data2"));
        //复制起始行
        int startRow = startRowIndex;
        //复制结束行
        int endRow = endRowIndex;
        //目标起始行
        int targetRow = endRow + 1;
        List<Integer> startRows = new LinkedList<>();
        startRows.add(startRow);
        List<Integer> endRows = new LinkedList<>();
        endRows.add(endRow);
        List<Integer> copyStartRows = new LinkedList<>();
        copyStartRows.add(targetRow);
        XSSFWorkbook workbook = null;
        XSSFWorkbook xssfWorkbook = null;
        try {
            workbook = new XSSFWorkbook(sourceFileStream);
            for (int i = 1; i < copyCount; i++) {
                startRow = startRow + moduleRowSize;
                startRows.add(startRow);
                endRow = endRow + moduleRowSize;
                endRows.add(endRow);
                targetRow = endRow + 1;
                copyStartRows.add(targetRow);
            }
            XSSFSheet sheet = workbook.getSheetAt(0);
            CellCopyPolicy policy = new CellCopyPolicy();
            policy.setCopyCellFormula(false);
            policy.setMergeHyperlink(false);
            policy.setMergeHyperlink(false);
            for (int i = 0; i < copyCount; i++) {
                sheet.copyRows(startRows.get(i), endRows.get(i), copyStartRows.get(i), policy);
                setRowsBorder(workbook,sheet,copyStartRows.get(i)+5,copyStartRows.get(i)+7);
                setRowsBorder(workbook,sheet,copyStartRows.get(i)+9,copyStartRows.get(i)+12);
            }
            //生成临时模板文件
            tempFile = File.createTempFile("temp", ".xlsx");
            //写入复制模块后的文件
            workbook.write(Files.newOutputStream(tempFile.toPath()));
            //移除模板本身索引
            startRows.remove(0);
            //添加最后一列索引
            if (copyCount!=1){
                Integer lastRow = startRows.get(startRows.size() - 1);
                startRows.add(lastRow + moduleRowSize);
            }
            //替换填充前缀
            xssfWorkbook = new XSSFWorkbook(tempFile);
            XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);
            int initIndex = 3;
            if (copyCount!=1){
                for (Integer row : startRows) {
                    //每行对应填充key
                    List<String> fillKey = new LinkedList<>();
                    XSSFRow row1 = xssfSheet.getRow(row);
                    replaceRowValue(row1, "data0", "data" + initIndex);
                    fillKey.add("data" + initIndex);
                    XSSFRow row2 = xssfSheet.getRow(row + 2);
                    replaceRowValue(row2, "data0", "data" + initIndex);
                    fillKey.add("data" + initIndex);
                    XSSFRow row3 = xssfSheet.getRow(row + 4);
                    replaceRowValue(row3, "data1", "data" + (initIndex + 1));
                    fillKey.add("data" + (initIndex + 1));
                    XSSFRow row4 = xssfSheet.getRow(row + 8);
                    replaceRowValue(row4, "data2", "data" + (initIndex + 2));
                    fillKey.add("data" + (initIndex + 2));
                    initIndex = initIndex + 3;
                    fillKeys.add(fillKey);
                }
            }else {
                //每行对应填充key
                List<String> fillKey = new LinkedList<>();
                int row=endRowIndex+1;
                XSSFRow row1 = xssfSheet.getRow(row);
                replaceRowValue(row1, "data0", "data" + initIndex);
                fillKey.add("data" + initIndex);
                XSSFRow row2 = xssfSheet.getRow(row + 2);
                replaceRowValue(row2, "data0", "data" + initIndex);
                fillKey.add("data" + initIndex);
                XSSFRow row3 = xssfSheet.getRow(row + 4);
                replaceRowValue(row3, "data1", "data" + (initIndex + 1));
                fillKey.add("data" + (initIndex + 1));
                XSSFRow row4 = xssfSheet.getRow(row + 8);
                replaceRowValue(row4, "data2", "data" + (initIndex + 2));
                fillKey.add("data" + (initIndex + 2));
                fillKeys.add(fillKey);
            }
            if (sheetSize>=1){
                for (int i = 0; i < sheetSize; i++) {
                    xssfWorkbook.cloneSheet(0,"sheet" + (i+1));
                }
            }
            //替换填充前缀->输出文件
            xssfWorkbook.write(Files.newOutputStream(outFile.toPath()));
            return fillKeys;
        } catch (IOException | InvalidFormatException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (xssfWorkbook != null) {
                    xssfWorkbook.close();
                }
                if (workbook != null) {
                    workbook.close();
                }
                if (sourceFileStream != null) {
                    sourceFileStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (tempFile!=null){
                boolean delete = tempFile.delete();
                log.info("临时模板删除: {}",delete);
            }
        }
    }

    //添加边框
    public static void setRowsBorder(XSSFWorkbook xssfWorkbook,XSSFSheet sheet
            ,int startRow,int endRow){
        // 创建单元格样式
        XSSFCellStyle style = xssfWorkbook.createCellStyle();
        //上下左右边框
        // 设置边框样式为实线
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        // 设置边框颜色为黑色
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        for (int i = startRow; i < endRow; i++) {
            XSSFRow row = sheet.getRow(i);
            row.setRowStyle(style);
        }
    }

    /**
     * 行值替换
     * @param row      替换行
     * @param oldValue 过去值
     * @param newValue 替换值
     */
    public static void replaceRowValue(XSSFRow row, String oldValue, String newValue) {
        Iterator<Cell> cellIterator = row.cellIterator();
        cellIterator.forEachRemaining(e -> {
            if (StringUtils.hasLength(e.getStringCellValue())) {
                String cellValue = e.getStringCellValue();
                cellValue = cellValue.replace(oldValue, newValue);
                e.setCellValue(cellValue);
            }
        });
    }

    /**
     * 获取导出文件
     * @param processId 进度id
     * @return String - 文件路径
     */
    public static String getHtExportFile(String processId) {
        File file = new File("");
        return  file.getAbsolutePath() + File.separator + "ht-meta-export" + File.separator + processId + ".xlsx";
    }

    /**
     * 浏览器文件下载
     * @param targetFile  目标文件
     * @param response    response
     */
    public static void browserDownLoad(File targetFile, String downLoadName, HttpServletResponse response){
        OutputStream out = null;
        InputStream in = null;
        try {
            response.reset();
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downLoadName, "UTF-8"));
            response.addHeader("Content-Length", "" + targetFile.length());
            response.setContentType("application/vnd.ms-excel");
            out = new BufferedOutputStream(response.getOutputStream());
            in = new BufferedInputStream(new FileInputStream(targetFile));
            IOUtils.copy(in, out);
            out.flush();
        } catch (Exception e) {

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }
    
}

到了这里,关于Spring boot easyexcel 实现复合数据导出、按模块导出的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 引入 easyexcel 最新版本 3.3.2,实现读写 Excel

    EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能 在 Spring Boot 环境中使用 easyexcel,需要完成以下几个步骤 pom.xml中引入easyexcel的依赖,此处版本号3.3.2 建立一个实体

    2024年02月11日
    浏览(35)
  • 使用EasyExcel实现excel导出,支持百万大数据量导出-----超简单

    通过设置sheet数量,完成分批导出,每个sheet存100万数据,每次查询插入20万数据,避免超时,内存溢出等问题,可以根据服务器配置调整参数设置。 1.引入依赖 2.创建对应的实体类 @ExcelProperty设置的就是导出的列名,还可以设置排序等等 3.核心导出代码 4.配置类 至此就完成导

    2024年02月11日
    浏览(62)
  • SpringBoot整合Easyexcel实现将数据导出为Excel表格的功能

    本文主要介绍基于SpringBoot +MyBatis-Plus+Easyexcel+Vue实现缺陷跟踪系统中导出缺陷数据的功能,实现效果如下图: EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。 本文

    2024年02月14日
    浏览(43)
  • Springboot基于easyexcel实现一个excel文件包含多个sheet表格的数据导出

    EasyExcel 是一款基于Java的开源Excel操作工具,它提供了简单且强大的 API,使开发人员可以轻松地读写、操作和生成Excel文件。 EasyExcel 支持 Excel 文件的导入和导出,可以处理大量数据,具有高性能和低内存占用。它可以读取 Excel 文件中的数据,并将数据转换为 Java 对象,也可

    2024年02月03日
    浏览(59)
  • 使用Spring Boot和EasyExcel的导入导出

    在当今信息化社会,数据的导入和导出在各种业务场景中变得越来越重要。为了满足复杂的导入导出需求,结合Java编程语言、Spring Boot框架以及EasyExcel库,我们可以轻松地构建出强大而灵活的数据处理系统。本文将引导您通过一个案例学习如何使用这些工具,实现一个复杂的

    2024年02月14日
    浏览(38)
  • 使用EasyExcel实现Excel的导入导出

    在真实的开发者场景中,经常会使用excel作为数据的载体,进行数据导入和导出的操作,使用excel的导入和导出有很多种解决方案,本篇记录一下EasyExcel的使用。 EasyExcel是一个开源的项目,是阿里开发的。EasyExcel可以简化Excel表格的导入和导出操作,使用起来简单快捷,易上手

    2023年04月15日
    浏览(51)
  • EasyExcel实现Excel文件导入导出功能

    Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。 EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。

    2024年02月02日
    浏览(68)
  • 使用EasyExcel实现Excel表格的导入导出

    Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。 easyexcel重

    2024年02月12日
    浏览(46)
  • 使用easyexcel填充模板数据,并导出excel

    导出excel功能非常场景,本片文章记录如何使用模板填充数据后再导出。因直接导出excel数据样式不符合要求,所以做了模板填充然后再导出excel。 效果如下: 注意:列表数据变量名前面要写点{.id},如果单条数据可以不写。 使用表单提交: 实体代码: controller代码: 只对je

    2024年03月11日
    浏览(53)
  • java实现excel的导出之使用easyExcel

    在我们的项目需求中,经常会遇到导出的需求,其中excel的导出最为常见。生成Excel比较有名的框架有Apache poi,jxl等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc. EasyExcel是阿里巴巴

    2024年02月15日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包