EasyExcel使用详情

EasyExcel是一个Java库,用于快速、高效地处理大文件Excel读写,避免内存溢出。它支持通过实体类映射数据,处理日期、数字和自定义格式转换,并使用监听器批量存入数据库。此外,还介绍了如何写入Excel和使用模板功能。
摘要由CSDN通过智能技术生成

目录

1. 概述

2. 读excel表信息

2.1 简单读取-创建实体类

 2.2 日期、数字或者自定义格式转换

2.3 监听器

2.4 监听器调用

2.5 向数据库内存入数据

3. 写excel

3.1 DemoData

 3.2 填充excel


1. 概述

官网地址:关于Easyexcel | Easy Excel (alibaba.com)

EasyExcel 是一个基于 Java 的、快速、简洁、解决大文件内存溢出的 Excel 处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成 Excel 的读、写等功能。

导入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>最新版本</version>
</dependency>

2. 读excel表信息

2.1 简单读取-创建实体类

可以使用与excel表头对应的实体类来读取,以下有两种注解可以自由选取。

       

第一种就是使用@Excelproperty中的value值去读取表数据,不过要注意不能出现重复字段。

@Data
public class DemoData {
    /**
     * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据。
     * @ExcelProperty注解的value值是一个数组类型,如果时如图所示这种有多级标题的可以这么写。
     */
    @ExcelProperty({"xxx有限公司","序号"})
    private Integer id;
 
    @ExcelProperty({"xxx有限公司","姓名"})
    private String name;

    @ExcelProperty({"xxx有限公司","年龄"})
    private Integer age;
}

 第二种是采用@ExcelProperty中的index字段,根据表格列号去读数据,index值是从0开始,一般不建议index和value同时使用。

@Data
public class DemoData {
    
    @ExcelProperty(index = 0)
    private Integer id;
 
    @ExcelProperty(index = 1)
    private String name;

    @ExcelProperty(index = 2)
    private Integer age;
}

 2.2 日期、数字或者自定义格式转换

@Getter
@Setter
@EqualsAndHashCode
public class ConverterData {
    /**
     * 我自定义 转换器,不管数据库传过来什么 。我给他加上“自定义:”
     */
    @ExcelProperty(converter = CustomStringStringConverter.class)
    private String string;
    /**
     * 这里用string 去接日期才能格式化。我想接收年月日格式
     */
    @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
    private String date;
    /**
     * 我想接收百分比的数字
     */
    @NumberFormat("#.##%")
    private String doubleData;
}

2.3 监听器

public class DemoDataExcelListener implements ReadListener<VerticalCurveElementExcelData> {
    // 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
    private static final int BATCH_COUNT = 100;
    private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<DemoDataEntity> demoDatatEntityList = new ArrayList();
    private String fileName;

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public DemoDataExcelListener() {
    }

    public List<DemoDataEntity> getDatas() {
        return this.demoDataEntityList;
    }

    /**
     * 在监听器出现异常时会调用此方法
     */
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception.getClass() == ExcelAnalysisStopException.class) {
            System.out.println("解析失败" + exception.getMessage());
            throw exception;
        } else {
            System.out.println("解析失败,但是继续解析下一行:" + exception.getMessage());
            if (exception instanceof ExcelDataConvertException) {
                ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
                System.out.println("第" + excelDataConvertException.getRowIndex() + "行,第" + excelDataConvertException.getColumnIndex() + "列解析异常,数据为:" + excelDataConvertException.getCellData());
            }

        }
    }

    /**
     * 每一条头数据解析都会来调用
     */
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        System.out.println("解析到一条头数据:" + JSON.toJSONString(headMap));
        if (headMap.size() < "你要读取的列数") {
            throw new ExcelAnalysisStopException("读取excel模板不匹配");
        }
    }

    /**
     * 这个每一条数据解析都会来调用
     */
    @Override
    public void invoke(DemoDataExcelData data, AnalysisContext context) {
        this.cachedDataList.add(data);
        if (this.cachedDataList.size() >= BATCH_COUNT) {
            this.transData();
            this.cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }

    }

    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        this.transData();
    }

    private void transData() {
        // ...数据转换的内容
    }
}

2.4 监听器调用

    public static List<DemoDataEntity> readDemoDataData(InputStream inputStream, String fileName) {
        Object listMap = new ArrayList();
        try {
            DemoDataExcelListener listener = new DemoDataExcelListener();
            listener.setFileName(fileName);
            ExcelReader excelReader = EasyExcelFactory.read(inputStream, DemoDataExcelData.class, listener).build();
            excelReader.readAll();
            listMap = listener.getDatas();
            excelReader.finish();
        } catch (Exception var5) {
            var5.printStackTrace();
        }
        return (List)listMap;
    }

2.5 向数据库内存入数据

    @Override
    public List<DemoDataEntity> demoDataExcelRead(@RequestParam("file") MultipartFile file, Integer projectId) throws IOException {
        List<DemoDataEntity> entitys = EeasyExcelUtil.readDemoDataData(file.getInputStream(),file.getOriginalFilename());
        // 储存数据
        savaExcelList(entitys,projectId);
        return entitys;
    }

3. 写excel

3.1 DemoData

 这里有模板的话,可以不使用@ExcelProperty。

@Data
public class DemoData {
    
    private Integer id;
 
    private String name;

    private Integer age;
}

 3.2 填充excel

这里做完excel填充之后,继续将excel表格上传至minIO,如果想详细了解,可参考MinIO的上传和下载

如果需要直接填充完excel响应给页面的话,可以使用EasyExcel.write(response.getOutputStream)

    public void DemoDataUploadMinIo(Object ...) throws IOException {
        // 获取从数据库中查询到并经过处理后可以填充至excel中的DemoData数据,如果要填充多个sheet的话,可以使用Map<String, List<DemoData>>
        Map<String, List<DemoData>> demoDataExcelData = toDemoData(param);
        // 判断是否获取到数据
        boolean flag = false;
        for (String s : demoDataExcelData.keySet()) {
            if (demoDataExcelData.get(s) != null && demoDataExcelData.get(s).size() > 0) {
                flag = true;
                break;
            }
        }
        if (flag) {
            // 获取模板路径
            String dataPath= excelTemplateRealpath + "员工信息表.xlsx";
            InputStream is = new FileInputStream(dataPath);
            is = copySheet(routes, is);
            // 读取模板表
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            // 由于这里获取到数据做的是上传,所以不用response.getOutputStream来获取响应流
            ExcelWriter excelWriter = EasyExcel.write(outputStream).excelType(ExcelTypeEnum.XLSX).withTemplate(is).build();
            // 遍历多个数据,进行填充
            for (String str: demoDataExcelData.keySet()) {
                // 获取不同路线的值
                List<DemoData> value = demoDataExcelData.get(str);
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet名称").build();
                // 使用fill()方法,必须要有模板,不然会报错
                excelWriter.fill(value, writeSheet);
                Map<String, Object> map = MapUtils.newHashMap();
                map.put("company", "EasyExcel");
                map.put("date", "2023-07-14");
                excelWriter.fill(map, writeSheet);
            }
            excelWriter.finish();
            byte[] bytes = outputStream.toByteArray();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            MultipartFile multipartFile = new MockMultipartFile("直线、曲线及转角表" + projectName + ".xlsx", inputStream);
            // 上传文件至minIo并储存文件信息至db
            FileService.insertFile(multipartFile, ...);
            outputStream.close();
            is.close();
        }
    }






    /**
     * 复制sheet,这里是采用POI来复制sheet
     */
    public InputStream copySheet(List<KProjectRouteEntity> routes, InputStream is) throws IOException {
        XSSFWorkbook sheets = new XSSFWorkbook(is);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        for (int i = 0; i < routes.size(); i++) {
            String sheetName = routes.get(i).getRouteName();
            if (i == 0) {
                sheets.setSheetName(i, sheetName);
            } else {
                sheets.cloneSheet(0, sheetName);
            }
        }
        sheets.write(bos);
        byte[] bArray = bos.toByteArray();
        // 不需要调用close()关闭流,在调用ExcelWriter.finish()会被关闭
        return new ByteArrayInputStream(bArray);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
EasyExcel是阿里巴巴开源的一个excel处理框架,使用简单且节省内存。它适合处理大数据量的Excel,不像之前的Excel解析框架将数据一次性加载到内存中,而是从磁盘上逐行读取数据并解析。它重写了poi对07版本Excel的解析,在处理大数据时不容易发生内存溢出。EasyExcel可以用于数据导入、数据导出以及数据传输等场景。在使用EasyExcel时,可以使用注解来自定义表头、选择excel中的顺序、忽略不需要导出的属性、进行日期格式转换,以及设置行宽等。官方文档提供了更详细的使用说明。 在实际应用中,可以使用@ExcelIgnore注解来标记不需要导出的多余属性,这样可以避免导出不需要的字段。另外,可以使用@DateTimeFormat注解来进行日期格式转换,使用@ColumnWidth注解来设置行宽。 总的来说,EasyExcel是一个方便易用的excel处理框架,可以帮助我们简化Excel的处理操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [EasyExcel使用教程](https://blog.csdn.net/tttalk/article/details/123379580)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值