使用EasyExcel实现模板Sheet复制与填充

2023年 10月 7日 120.9k 0

当在后端开发中处理Excel业务时,EasyExcel是一个非常有用的工具,它提供了强大的模板填充功能,可以轻松解决各种业务需求。在本文中,我将首先简要介绍EasyExcel模板填充功能的基本用法,然后提供一种根据业务需要执行多份复制与填充的实用方案。

EasyExcel模板填充功能的基本用法

使用EasyExcel的[模板填充功能]与[简单写]相比,可以diy工作表(sheet)的样式,让生成的excel更加美观且不必花费更多的开发时间。

使用简单写完成一个Excel报表

  • 创建Java类,方便构建数据映射到Excel中;在类中使用注解配置单元格格式和标题

    @ExcelProperty: 设置excel中标题名称

    @ColumnWidth: 设置单元格的宽度

  • 
    @Builder
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CatDTO {
    
        @ExcelProperty(value = "姓名")
        private String name;
    
        @ExcelProperty(value = "品种")
        @ColumnWidth(15)
        private String breed;
    
        @ExcelProperty(value = "年龄")
        private Double age;
    
        @ExcelProperty(value = "描述")
        @ColumnWidth(30)
        private String desc;
    
    }
    
  • 使用EasyExcel提供的Write API,将数据写入Excel中。
  • @SpringBootTest
    class DemoApplicationTests {
    
        @Test
        void writeTest1() {
            String fileName = "write-" + System.currentTimeMillis() + ".xlsx";
            // 构建数据
            List catWriteData = List.of(
                    CatDTO.builder().name("肥猫").breed("银渐层").age(1.2).desc("每天吃吃睡睡睡睡睡").build(),
                    CatDTO.builder().name("虎妞").breed("德文卷毛猫").age(0.6).desc("活泼好动无敌可爱爱粘人").build()
            );
    
            EasyExcel.write(fileName, CatDTO.class).sheet().doWrite(catWriteData);
    
        }
    }
    
  • 生成效果
  • 使用模板填充完成一个Excel报表

  • 创建Java类
  • @Builder
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CatFillDTO {
    
        private String name;
    
        private String breed;
    
        private Double age;
    
        private String desc;
    
    }
    
  • 构建模板,在数据填充所在列上,填上与之对应的实体类属性名;
  • 使用EasyExcel提供的Fill API,获取模板文件,写入数据。
  • @SpringBootTest
    class DemoApplicationTests {
    
        @Test
        void fillTest1() {
            String fileName = "fill-" + System.currentTimeMillis() + ".xlsx";
            // 构建数据
            List catFillData = List.of(
                    CatFillDTO.builder().name("肥猫").breed("银渐层").age(1.2).desc("每天吃吃睡睡睡睡睡").build(),
                    CatFillDTO.builder().name("虎妞").breed("德文卷毛猫").age(0.6).desc("活泼好动无敌可爱爱粘人").build()
            );
    
    
            FileUtil.touch(fileName);
            // 加载模板
            InputStream resourceAsStream = ResourceUtil.getStreamSafe("temp/cat-template.xlsx");
            // 生成工作簿对象
            ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(resourceAsStream).build();
            // 生成工作表对象
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            // 多组数据填充需要另起一行时 forceNewRow(true)
            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
            // 多组数据填充 List 对象
            excelWriter.fill(catFillData, fillConfig, writeSheet);
            // 关闭excelWriter
            excelWriter.finish();
        }
    }
    
  • 生成效果
  • 可以看出,使用模板填充可以省去在代码中配置字段名称、单元格大小等配置,在实现复杂的Excel样式或美观修饰上更有优势;

    根据业务需要执行多份复制与填充的方案

    在处理Excel时,你或许会遇到这样的问题。使用指定模板填充数据,数据根据某个特征进行划分,分别填进不同的工作表(sheet)中,这样,我们需要根据业务的需求,
    来生成相应的模板表数量,再分别填充上数据。

    实现思路

  • 使用POI API加载模板文件为Workbook对象
  • 使用POI中的cloneSheet API复制相应数量的模板工作表
  • 将复制好数量的工作簿文件转换成输入流,以便在EasyExcel withTemplate API中使用
  • 使用EasyExcel fill API填充数据。
  • (直接上业务代码,实现的功能为模板表1不执行复制,只进行填充,模板表2进行复制并填充)

    @Service
    @Slf4j
    @RequiredArgsConstructor
    public class SpeakerServiceImpl implements ISpeakerService {
    
       /**
        * 填充模板文件
        *
        * @param sheet1Data sheet1数据
        * @param promptMap  提示地图
        * @return {@code File}
        */
       public File fillTemplateFile(
               CustomSpeakerDemandExcelDTO sheet1Data, Map promptMap) {
    
          try {
             // 构建模板
             byte[] asInputStream = this.buildTemplateFile(promptMap);
             // 创建临时导出文件
             File temporaryFile = Files.createTempFile("speaker_task_", ".xlsx").toFile();
             // easyExcel API 根据is作为模板填充数据,并写入临时文件temporaryFile
             ExcelWriter excelWriter = EasyExcel.write(temporaryFile)
                     .withTemplate(new ByteArrayInputStream(asInputStream))
                     .build();
             // 填充模板1的sheet
             WriteSheet writeSheet1 = EasyExcel.writerSheet(0).build();
             excelWriter.fill(sheet1Data, writeSheet1);
    
             // 填充模板2的多个sheet
             int sheetIndex = 1;
             for (String key : promptMap.keySet()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex).build();
                // 写入数据到当前sheet
                List prompt = promptMap.get(key);
                excelWriter.fill(prompt, writeSheet);
                sheetIndex++;
             }
             excelWriter.finish();
             return temporaryFile;
          } catch (IOException e) {
             throw new RuntimeException(e);
          }
       }
    
       /**
        * 构建模板文件
        *
        * @param promptMap 提示地图
        * @return {@code byte[]}
        * @throws IOException ioexception
        */
       public byte[] buildTemplateFile(Map promptMap) throws IOException {
          // 加载模板文件
          InputStream templateStream = ResourceUtil.getStreamSafe("temp/speaker-task-template.xlsx");
          Workbook workbook = WorkbookFactory.create(templateStream);
          // 设置模板sheet数量, 需要复制promptMap.size()-1 次工作表2
          boolean first = true;
          for (String key : promptMap.keySet()) {
             if (first) {
                // 第一组数据可以直接使用当前模板,不需要进行复制
                workbook.setSheetName(1, key);
             } else {
                // 复制模板到新工作表,并设置表名
                Sheet newSheet = workbook.cloneSheet(1);
                workbook.setSheetName(workbook.getSheetIndex(newSheet), key);
             }
             first = false;
          }
          ByteArrayOutputStream ops = new ByteArrayOutputStream();
          workbook.write(ops);
          byte[] byteArray = ops.toByteArray();
          // 原文件流后续已不使用,此处关闭
          templateStream.close();
          ops.close();
          return byteArray;
       }
    }
    
    

    酸奶小肥阳原创,欢迎阅读点赞加收藏,关注我随时与我技术交流吧😄

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论