Use code to manipulate Excel files (easyExcel)


EasyExcel documentation: https://www.yuque.com/easyexcel/doc/easyexcel

1.Maven imports the easyExcel package

<dependencies>
        <!--easyExcel-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
        </dependency>
        <!--日期格式化工具-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.1</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2.easyExcel for basic writing

1. Create the corresponding entity class

package com.domain;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * @author: libo
 * @date: 2020/10/12  11:36
 * @motto: 即使再小的帆也能远航
 */
@Data
public class DemoData {
    
    

    /*@ExcelProperty value = 标题(字段) index = 列数(可以直接选择第几列)*/
    @ExcelProperty(value = "字符串标题", index = 0)
    private String stringName;

    @ExcelProperty(value = "日期标题", index = 1)
    private Date dateName;

    @ExcelProperty(value = "数字标题", index = 3)
    private Double doubleName;

    /*@ExcelIgnore在操作时忽略此字段*/
    @ExcelIgnore
    private int money;
}

2. The listener used by easyExcel (the following code is copied from the official one)

package com.utils;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.dao.DemoDAO;
import com.domain.DemoData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: libo
 * @date: 2020/10/12  16:13
 * @motto: 即使再小的帆也能远航
 */
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class DemoDataListener extends AnalysisEventListener<DemoData> {
    
    
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 5;
    List<DemoData> list = new ArrayList<DemoData>();
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoDAO demoDAO;

    public DemoDataListener() {
    
    
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    /*如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     * @param demoDAO*/
    public DemoDataListener(DemoDAO demoDAO) {
    
    
        this.demoDAO = demoDAO;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */


    /*读取数据会执行 invoke 方法
    * DemoData 数据的Beanl类
    * AnalysisContext 分析上下文*/
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
    
    

        /*输出到控制台*/
        System.out.println(JSON.toJSONString(data));

        LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
    
    
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    /*所有数据解析完成了 都会来调用
     * @param context*/
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
    
    
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        LOGGER.info("所有数据解析完成!");
    }

    /*加上存储数据库*/
    private void saveData() {
    
    
        LOGGER.info("{}条数据,开始存储数据库!", list.size());
        demoDAO.save(list);
        LOGGER.info("存储数据库成功!");
    }
}

If it needs to be stored in the database (add Dao class and method), the listener will call

public class DemoDAO {
    
    
    public void save(List<DemoData> list) {
    
    
        // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
    }

3. Writing code: reading and writing

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.domain.DemoData;
import com.utils.DemoDataListener;
import org.junit.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author: libo
 * @date: 2020/10/12  11:31
 * @motto: 即使再小的帆也能远航
 */
public class easyTest {
    
    

    final String PATH = "D:\\IntelliJ IDEA 2019.1_File\\POIandEasyExcel\\easyExcel\\";

    /*模拟数据来源*/
    public List<DemoData> data() {
    
    

        List<DemoData> list = new ArrayList<DemoData>();

        /*循环10次,在Excel中就是10行数据*/
        for (int x = 1; x < 11; x++) {
    
    
            DemoData data = new DemoData();
            /*字符串标题*/
            data.setStringName("字符串" + x);
            /*日期标题*/
            data.setDateName(new Date());
            /*数字标题*/
            data.setDoubleName((double) x);
            /*查看被忽略字段(标题)是否会被写入*/
            data.setMoney(x);

            /*添加进集合*/
            list.add(data);
        }
        return list;
    }


    /*easyExcel写入数据*/
    @Test
    public void easyExcelWrite() {
    
    

        /*写出文件路径*/
        String fileName = PATH + "easyExcelTest.xlsx";

        // 写法1(只需一行代码搞定)
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可

        /* 几个方法的参数解释:
            write(1.路径,2.格式类)
            sheet(Excel中的模板名称)
            doWrite(数据)*/
        EasyExcel.write(fileName, DemoData.class).sheet("easyExcel模板").doWrite(data());


        // 写法2
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = null;
        try {
    
    
            excelWriter = EasyExcel.write(fileName, DemoData.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("easyExcel模板").build();
            excelWriter.write(data(), writeSheet);
        } finally {
    
    
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
    
    
                excelWriter.finish();
            }
        }
    }


    /*easyExcel读取数据*/
    @Test
    public void easyExcelRead() {
    
    

        /*写出文件路径*/
        String fileName = PATH + "easyExcelTest.xlsx";

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        // 写法1:
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
//        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();


        // 写法2:
        ExcelReader excelReader = null;
        try {
    
    
            excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
            ReadSheet readSheet = EasyExcel.readSheet(0).build();
            excelReader.read(readSheet);
        } finally {
    
    
            if (excelReader != null) {
    
    
                // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
                excelReader.finish();
            }
        }
    }
}

I won’t introduce too much about easyExcel, because the documentation is very clear and a demo has already been written. Compared with POI, easyExcel is simpler to operate and requires less code.
EasyExcel still uses POI internally.

Things that seem beautiful often hide traps.

Guess you like

Origin blog.csdn.net/weixin_45377770/article/details/109031930