【EasyExcel】Java使用EasyExcel操作Excel文档

引言

本文将要说明通过Alibaba的easyExcel技术实现对Excel文档存取的操作,在此之前,同学应该接触过POI技术,是比较早的实现了读写Excel的技术之一,但是有个很大的问题就是很占内存。我在项目中遇到一个问题就是导出客户订单,通常有数十万条记录,采用POI发现内存压力太大,甚至有可能出现内存溢出、服务器宕机的风险,这在线上是不允许存在的,所以想到了采用easyExcel技术,通过实践证明,easyExcel响应快而且相对于POI确实节省了大量的内存。在此,笔者强烈安利这门技术。

快速上手

导包

首先导入需要的jar包,一如既往的采用maven管理jar,导入easyExcel及lombok:

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
    </dependencies>

写入Excel

首先定义数据模型,本文采用多行复杂的格式:
程序清单1:数据模型

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 12:08
 * @description 数据模型
 */
@ContentRowHeight(18)
@HeadRowHeight(25)
@ColumnWidth(25)
public class DataModel {
    /**
     * 复杂标题 将整合为一个单元格效果如下:
     * —————————————————————————
     * |          天猫        |
     * —————————————————————————
     * |旗舰店名称|日期|营收|
     * —————————————————————————
     */
    /* 旗舰店名称 */
    @ExcelProperty({"天猫", "旗舰店名称"})
    private String shopName;
    /* 日期 */
    @ExcelProperty({"天猫", "日期"})
    private Date date;
    /* 营收数据(小数型) */
    @ExcelProperty({"天猫", "营收"})
    private Double profit;

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Double getProfit() {
        return profit;
    }

    public void setProfit(Double profit) {
        this.profit = profit;
    }
}

其次定义对象格式转换:
程序清单2:对象转换

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 12:21
 * @description 基础数据类.这里的排序和excel里面的排序一致
 */
public class ConverterData {
    /**
     * 我想所有的 字符串起前面加上"格式化:"三个字
     */
    @ExcelProperty(value = "店铺名称", converter = CustomStringStringConverter.class)
    private String shopName;
    /**
     * 我想写到excel 用年月日时分秒的格式
     */
    @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
    @ExcelProperty("日期")
    private Date date;
    /**
     * 我想写到excel 用小数表示
     */
    @NumberFormat("#.##")
    @ExcelProperty(value = "营收")
    private Double profit;

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Double getProfit() {
        return profit;
    }

    public void setProfit(Double profit) {
        this.profit = profit;
    }
}

然后是自定义转换器:
程序清单3:自定义转换器

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 12:24
 * @description
 */
public class CustomStringStringConverter implements Converter<String> {
    public Class supportJavaTypeKey() {
        return String.class;
    }

    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里是读的时候会调用 不用管
     *
     * @param cellData            NotNull
     * @param contentProperty     Nullable
     * @param globalConfiguration NotNull
     * @return
     */
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                    GlobalConfiguration globalConfiguration) {
        return cellData.getStringValue();
    }

    /**
     * 这里是写的时候会调用 不用管
     *
     * @param value               NotNull
     * @param contentProperty     Nullable
     * @param globalConfiguration NotNull
     * @return
     */
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
                                       GlobalConfiguration globalConfiguration) {
        return new CellData("格式化:" + value);
    }
}

最后给出写入Excel的工具类:
程序清单4:写入Excel工具类

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 12:33
 * @description
 */
public class WriteUtil {
    public static void main(String[] args) {
        try {
            new WriteUtil().simpleWrite();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void simpleWrite() throws Exception {
        // 写法1
        String fileName = "demo1.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DataModel.class).sheet("店铺每天营收数据").doWrite(dataGenerator());

        // 写法2,方法二需要手动关闭流
        fileName = "demo2.xlsx";
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = EasyExcel.write(fileName, DataModel.class).build();
        WriteSheet writeSheet = EasyExcel.writerSheet("店铺每天营收数据").build();
        excelWriter.write(dataGenerator(), writeSheet);
        /// 千万别忘记finish 会帮忙关闭流
        excelWriter.finish();
    }

    /**
     * @description 手动生成数据写入Excel
     * @params []
     * @returns java.util.List<com.pers.common.DataModel>
     */
    private List<DataModel> dataGenerator() {
        Date curTime = new Date();
        List<DataModel> list = new ArrayList<DataModel>();
        for (int i = 0; i < 12; i++) {
            DataModel dataModel = new DataModel();
            dataModel.setShopName("店铺名称" + i);
            dataModel.setDate(curTime);
            dataModel.setProfit(i * 66.6);
            list.add(dataModel);
        }
        return list;
    }
}

下图是结果图:
在这里插入图片描述

读取Excel

读取Excel的时候需要定义监听器:
程序清单5:监听器

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 13:18
 * @description
 */
public class DataListenerModel extends AnalysisEventListener<DataModel> {

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

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public DataListenerModel() {
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data
     * @param context
     */
    @Override
    public void invoke(DataModel data, AnalysisContext context) {
        System.out.printf("解析到一条数据:{%s}", JSON.toJSONString(data));
        System.out.println();
        list.add(data);
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        System.out.println(JSON.toJSONString(list));
    }
}

程序清单6:读取Excel工具类

/**
 * @author Carson Chu
 * @email [email protected]
 * @date 2020/1/29 13:20
 * @description
 */
public class ReadUtil {
    public static void main(String[] args) {
        new ReadUtil().simpleRead();
    }

    public void simpleRead() {
        // 写法1:
        String fileName = "demo1.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, DataModel.class, new DataListenerModel()).sheet().doRead();

        // 写法2:
        fileName = "demo2.xlsx";
        ExcelReader excelReader = EasyExcel.read(fileName, DataModel.class, new DataListenerModel()).build();
        ReadSheet readSheet = EasyExcel.readSheet(0).build();
        excelReader.read(readSheet);
        // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
        excelReader.finish();
    }
}

源码速传

所有相关源码已经上传到我的GitHub上了,欢迎学习交流,附跳转路径:
easyExcel操作Excel的源码

发布了31 篇原创文章 · 获赞 12 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/Carson_Chu/article/details/104105152