• EasyExcel 导入导出Excel文件


    写在前面

    EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
    github文档: https://github.com/alibaba/easyexcel

    1、maven依赖

    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>easyexcelartifactId>
        <version>2.2.3version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、导入Excel文件

    常用如下两种读取方式

    EasyExcel.read(文件名/文件流,数据实体类.class,监听器).sheet().doRead();
    EasyExcel.read(文件名/文件流,数据实体类.class,监听器).build();
    
    • 1
    • 2

    2.1、读取表格文件

    实例1:
    (这里假设已有实体类User)

    public void test1() {
        EasyExcel.read("D:\\file\\1.xlsx", User.class, new AnalysisEventListener<User>() {
            // 每解析一行数据,该方法会被调用一次
            @Override
            public void invoke(User user, AnalysisContext analysisContext) {
                System.out.println("解析数据为:" + user.toString());
            }
            
            // 全部解析完成被调用
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("解析完成...");
                // 保存到数据库
            }
        }).sheet().doRead();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实例2:spring项目中导入一个excel文件
    (这里假设已有实体类User)

    // springboot 接口
    @PostMapping("/importUser")
    public void importUser(@RequestParam("file") MultipartFile file) 
        ExcelReader excelReader = EasyExcel.read(file.getInputStream(), User.class, new AnalysisEventListener<DemoData>() {
            @Override
            public void invoke(User user, AnalysisContext analysisContext) {
                System.out.println("解析数据为:" + user.toString());
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("解析完成...");
                // 保存到数据库
            }
        }).build();
        
        ReadSheet sheet = EasyExcel.readSheet(0).build();    // 创建sheet对象,读取Excel的第一个sheet, 也可以根据sheet名称获取
        excelReader.read(sheet);                             // 读取sheet表格数据,可以读取多个sheet
        excelReader.finish();                                // 这里必须手动关闭
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.2、如果有多个sheet表格

    读取多个sheet表格

    // 方式1
    EasyExcel.read(...)
    //         .sheet(0).doRead();
               .doReadAll(); // 读取全部sheet
    
    
    // 方式2
    ExcelReader excelReader = EasyExcel.read(...) .build();
    ReadSheet sheet = EasyExcel.readSheet(0).build();
    //excelReader.read(sheet);
    excelReader.readAll(); // 读所有sheet
    excelReader.finish();
    
    
    // 读指定的多个sheet
    ExcelReader excelReader = EasyExcel.read(...) .build();
    ReadSheet sheet = EasyExcel.readSheet(0).build();
    // 读取sheet,有几个就构建几个sheet进行读取
    excelReader.read(sheet0);
    excelReader.finish();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.3、监听器封装(也可不封装)

    每次调用 EasyExcel.read() 都需要 new 一个 AnalysisEventListener 对象,我们可以将AnalysisEventListener封装为一个对象,方便重复调用

    public class EasyExcelUtils<T> {
    
        /**
         * 获取读取Excel的监听器对象
         * @param consumer 处理解析数据的函数, 一般可以是数据入库逻辑的函数
         * @param threshold 阈值,达到阈值就处理一次存储的数据
         * @param  数据模型泛型
         * @return 返回监听器
         */
        public static <T> AnalysisEventListener<T> getReadListener(Consumer<List<T>> consumer, int threshold) {
    
            return new AnalysisEventListener<T>() {
            
               // ArrayList 查询更快
               // List dataList = new ArrayList<>(threshold);
               // LinkedList 插入和删除更快
                List<T> dataList = new LinkedList<>(); 
    
                /**
                 * 每解析一行调用, 订阅者1
                 * @param data 解析的每行数据
                 * @param context
                 */
                @Override
                public void invoke(T data, AnalysisContext context) {
                    dataList.add(data);
                    // 达到阈值就处理一次存储的数据
                    if (dataList.size() >= threshold) {
                        consumer.accept(dataList);
                        dataList.clear();
                    }
                }
    
                /**
                 * excel文件解析完成后,事件调度中心会通知到该方法, 订阅者2
                 * @param context
                 */
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // 最后阈值外的数据做处理
                    if (dataList.size() > 0) {
                        consumer.accept(dataList);
                    }
                }
            };
    
        }
    
        /**
         * 获取读取Excel的监听器对象, 不指定阈值, 默认阈值为 2000
         */
        public static <T> AnalysisEventListener<T> getReadListener(Consumer<List<T>> consumer) {
            return getReadListener(consumer, 2000);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    使用示例

    // 读取excel文件
    public void test() {
        EasyExcel.read("user.xlsx", User.class,EasyExcelUtils.getReadListener(dataProcess())).doReadAll();
    }
    
    // 处理数据
    public Consumer<List<User>> dataProcess() {
        return users -> users.forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.4、读取数据格式化(实体类中添加注解)

    在实体类中加入注解可以格式化数据,
    与lombok结合使用。

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Builder
    public class User {
    
        @ExcelProperty(value = "字符串标题", index = 0)
        private String name;
        
        @ExcelProperty(value = "日期标题", index = 1)
        @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒")  // 格式化日期类型数据
        private Date hireDate;
        
        @ExcelProperty(value = "数字标题", index = 2)
        @NumberFormat(value = "###.#")  // 格式化数字类型数据,保留一位小数,@NumberFormat不能用在Double类型中
        private String salary;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、导出Excel文件

    // 1、根据实体对象导出文件
    EasyExcel.write(response.getOutputStream(), 实体.class).sheet().doWrite(list<实体>);
    
    // 2、根据List>导出文件
    EasyExcel.write(response.getOutputStream()).head(表头list对象).sheet().doWrite(数据list对象);
    
    // 3、根据模板文件
    ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(new ClassPathResource("模板.xlsx").getInputStream()).build();
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
    excelWriter.fill(list实体对象, writeSheet);  // 填充数据1
    excelWriter.fill(map对象, writeSheet);       // 填充数据2
    excelWriter.finish();                        // 关闭流
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实例:spring项目中导出excel文件

    @PostMapping("/getExcel")
    public void getExcel(HttpServletResponse response) 
    	try{
    		String fileName = "表格文件名.xlsx";
    		List<数据实体类> data = new ArrayList<>();
    		fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
    		response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
    		EasyExcelFactory.write(response.getOutputStream(), 数据实体类.class)
    			.sheet("这是一张表名")
    			.doWrite(data);
    		response.getOutputStream().flush();
    	}finally {
    		response.getOutputStream().close();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.1、导出表格格式(实体类中添加注解)

    在实体类中定义

    @Data
    @NoArgsConstructor
    //@ContentRowHeight(50)//内容单元格高度
    //@HeadRowHeight(50)//表头单元格高度
    //@ColumnWidth(50)//单元格宽度
    public class User {
    	
        @ExcelProperty(value = {"导出台账","序号"})
        private Integer no;
        
        @ExcelProperty(value = {"导出台账","编号"})
        private  String  code;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.2、添加表头样式

    EasyExcelFactory.write(...).sheet("表名").registerWriteHandler(new 表头样式对象());
    
    • 1

    表头样式类型必须继承自CellWriteHandler

    public class MyCellWriteHandler implements CellWriteHandler {...}
    
    • 1

    4、注意事项

    4.1、实体类字段set方法,不能返回this

    实体类字段set方法,不能返回this,否者读表格时,无法写入数据到实体类。
    也意味着实体类不能添加链式相关注解,例如:lombok的@Accessors(chain = true)

    4.2、EasyExcel 和 EasyExcelFactory 的区别

    EasyExcel.read(…) 和 EasyExcelFactory.read(…) 有区别吗?
    没区别。

    下面是EasyExcel的源码

    package com.alibaba.excel;
    
    public class EasyExcel extends EasyExcelFactory {
        public EasyExcel() {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    你没有看错,EasyExcel.java的源码就这么点

    4.3、HSSFWorkbook、XSSFWorkbook、Workbook

    Workbook 是 HSSFWorkbook、XSSFWorkbook的基类

    HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls

    XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx

  • 相关阅读:
    ByteHouse实时导入技术演进
    kubernetes集群yaml文件与kubectl工具
    Centos7.9 安装 rabbitMq
    vue:生命周期函数总结
    priority_queue的介绍和使用
    【licode】srtp链接问题
    windows虚拟机迁移到新机器连不上网络
    【分享】如何让压缩包里的文件“限制编辑”?
    QT 发布文章遇到问题解决方案
    如何选择适合你的隧道爬虫ip?
  • 原文地址:https://blog.csdn.net/a__int__/article/details/126826552