EasyExcel的基本操作使用(读操作Excel导入,写操作Excel导出)

一、EasyExcel的了解:

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
文档说明地址:阿里EasyExcel

特点:简单,节省内存。
(1)Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
(2)EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析
(3)EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

前提准备工作:导包坐标

		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>

二、EasyExcel的写操作:

  1. 首先,需要有一个实体类,来设置表头和数据字段。
    在这里插入图片描述
public class DemoData {
    //设置表头名称
    @ExcelProperty("学生编号")
    private int sno;
    
	//设置表头名称
    @ExcelProperty("学生姓名")
    private String sname;
	
	//getter和setter方法省略
  1. 生成数据集合,可以是从数据库里查询出来的集合。这里简单演示,所以编写一个方法用于数据生成。
	//生成一个数据集合
	private static List<Student> data() {
        List<Student> list = new ArrayList<Student>();
        for (int i = 0; i < 10; i++) {
            Student student = new Student();
            student.setSno(i);
            student.setSname("张三"+i);
            list.add(student);
        }
        return list;
    }
  1. 对数据集合进行写入Excel操作。
	//要导出的Excel文件名,也可自定义规则。
	//如:String fileName=System.currentTimeMillis() + ".xlsx";
 	String fileName="E:\\11.xlsx";
    EasyExcel.write(fileName,Student.class).sheet("学生数据").doWrite(data());

注:使用EasyExcel类的write方法,传入文件名,及实体类(表头名称及数据字段),sheet方法传入字符串,指定工作表名称,最后doWrite方法,传入数据集合进行写入。

  1. 扩展写法
    在这里插入图片描述

三、EasyExcel的读操作:

  1. 创建实体类,用于存数据和设置表头索引。
public class Student2 {
    @ExcelProperty(index = 0)
    private int sid;

    @ExcelProperty(index = 1)
    private String sname;
    
	//getter和setter方法省略
}
  1. 创建监听器

(1)继承AnalysisEventListener<实体类>
(2)创建一个集合,用于封装数据。
(3)执行invoke方法读取excel内容

public class ExcelListener extends AnalysisEventListener<Student2> {
    List<Student2> list=new ArrayList<>();
    //一行一行去读取excle内容
    @Override
    public void invoke(Student2 data, AnalysisContext context) {
        System.out.println("***"+data);
        list.add(data);
    }
    //读取表头信息
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息:"+headMap);
    }
    //读取后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {

    }
}

注意:
(1)可以让其每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收。(如下代码)
(2)有个很重要的点Listener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去。如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来。(后面讲具体案例会解释)

		//设置常量用于判断
		private static final int BATCH_COUNT = 5;
		...
		...
		//如果集合大小等于5时,存入数据到数据库,并清空集合。
		if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
  1. 读取文件:与写操作差不多。

(1) read方法传入文件,实体类,及一个监听器实例。由于上面说到的注意项,每次读取都要new一个监听器,所以这里传入new 监听器类。
(2)sheet方法指:读取第一个工作表。
(3)doRead方法:执行读操作。

		//指定传入的文件,也可根据上传的文件进行读取
 		String fileName="E:\\11.xlsx";
        EasyExcel.read(fileName, Student2.class,new ExcelListener()).sheet().doRead();
  1. 扩展写法:
    在这里插入图片描述

  2. 执行:
    在这里插入图片描述

四、具体案例:

此时,有这样一个需求,要求通过Excel导入课程类别。一级分类,二级分类为表头,读取课程类别并存入数据库。

在这里插入图片描述

数据库表:一级标题parent_id为0,二级标题的parent_id为一级标题的id。如后端开发id:1178214681118568449。那么它的二级标题:(后端)Java的parent_id为:1178214681118568449。

在这里插入图片描述
流程步骤:

  1. 数据实体类:
public class SubjectData {
    @ExcelProperty(index = 0)
    private String oneSubjectName;
    @ExcelProperty(index = 1)
    private String twoSubjectName;
    //getter和setter方法省略
}
  1. 创建监听器

(1)注入待会儿需要的插入到数据库的service。通过构造方法进行传入。(回到上面创建监听器时的注意事项)
(2)读取。如果为null,抛出异常。如果一级不为空且不重复,则添加到数据库,获取一级id,为添加二级的父id做设置准备。

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
    public EduSubjectService eduSubjectService;
    public SubjectExcelListener(EduSubjectService eduSubjectService) {
        this.eduSubjectService = eduSubjectService;
    }
    public SubjectExcelListener() {
    }


    @Override
    //一行一行读取,第一个值一级分类,第二个值二级分类
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if(subjectData==null){
            throw new GuliException(20001,"文件数据为空!");
        }
        EduSubject eduOneSubject = this.existOneSubject(subjectData.getOneSubjectName(), eduSubjectService);
        if(eduOneSubject==null){
            eduOneSubject=new EduSubject();
            eduOneSubject.setTitle(subjectData.getOneSubjectName());
            eduOneSubject.setParentId("0");
            eduSubjectService.save(eduOneSubject);
        }
        String pid = eduOneSubject.getId();
        //二级分类
        EduSubject eduTwoSubject = this.existTwoSubject(subjectData.getTwoSubjectName(), eduSubjectService, pid);
        if(eduTwoSubject==null){
            eduTwoSubject=new EduSubject();
            eduTwoSubject.setTitle(subjectData.getTwoSubjectName());
            eduTwoSubject.setParentId(pid);
            eduSubjectService.save(eduTwoSubject);
        }

    }
    //判断一级分类不能重复添加的方法
    private EduSubject existOneSubject(String name,EduSubjectService eduSubjectService){
    }
    //判断二级分类不能重复添加的方法
    private EduSubject existTwoSubject(String name,EduSubjectService eduSubjectService,String pid){  
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}
  1. 读取文件

(1)Controller层

	@ApiOperation(value = "Excel批量导入")
    @PostMapping("addSubject")
    public R addSubject(MultipartFile file){
        eduSubjectService.saveSubject(file,eduSubjectService);
        return R.ok();
    }

(2)Service层:

public void saveSubject(MultipartFile file, EduSubjectService eduSubjectService) {
        //获取文件
        try {
            //文件输入流
            InputStream excelFile = file.getInputStream();
            EasyExcel.read(excelFile, SubjectData.class, new SubjectExcelListener(eduSubjectService)).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

五、总结

(1)EasyExcel读取文件时对Excel是一行一行进行读取,而非其他整个文件进行读取,所以占用的内存小。
(2)写操作:实体类->文件路径->doWrite()
(3)读操作:实体类->监听器->文件路径->doRead()

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT学习小镇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值