Alibaba EasyExcel初体验

简介

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。相对于Apache POI来说,EasyExcel是从磁盘上一行行的读取数据,然后逐个解析,避免将大量数据加载到内存从而导致OOM。

相关依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version></dependency><!-- 可选 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency>

Excel导入

需要导入的数据:

Model类:

@Datapublic class SchoolData {    @ExcelProperty(value = "地址")    private String address;    @ExcelProperty(value = "学校名称")    private String schoolName;    @ExcelProperty(value = "邮政编码")    private String postcode;    @ExcelProperty(value = "收集时间")    private Date collectDate;}

使用@ExcelProperty注解时,可以使用两种方式将数据列和属性进行绑定:

  1. 通过value指定名称,将名称对应的excel列的数据绑定到属性。
  2. 通过index指定下标,将下标对应的excel列的数据绑定到属性。

在不使用@ExcelProperty注解时,默认Model类属性和excel列数据按照先后顺序进行绑定的。

监听器:

import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import java.util.ArrayList;import java.util.List;import java.util.Map;public class SchoolDataListener extends AnalysisEventListener<SchoolData> {    List<SchoolData> schoolDataList = new ArrayList<>();    //需要传参时,通过构造方法传进来    public SchoolDataListener() {    }    /**     * 每解析一行数据都会进行调用     */    @Override    public void invoke(SchoolData data, AnalysisContext context) {        //一般数据量大的时候应该分批处理,防止数据全部加载到内存,导致OOM。        schoolDataList.add(data);    }    /**     * 数据全部解析完成时调用     */    @Override    public void doAfterAllAnalysed(AnalysisContext context) {        System.out.println("数据读取完毕:");        schoolDataList.stream().forEach(System.out::println);    }    /**     * 每解析一行表头都会进行调用     */    @Override    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {        System.out.println("表头:");        headMap.forEach((k, v) -> System.out.println(v));        System.out.println();    }}

导入测试:

导入有以下两种写法,一般使用简写的方式就行,当需要实现复杂的功能时可能会需要另外一种复杂的写法。

@Testpublic void importExcel() {ExcelReader excelReader = null;try {excelReader = EasyExcel.read("F:\\测试数据.xlsx", SchoolData.class, new SchoolDataListener()).build();ReadSheet readSheet = EasyExcel.readSheet(0).build();excelReader.read(readSheet);} finally {if (excelReader != null) {// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的excelReader.finish();}}}@Testpublic void importExcelSimple() {//sheet() 默认读取第一个sheetEasyExcel.read("F:\\测试数据.xlsx", SchoolData.class, new SchoolDataListener()).sheet().doRead();}

输出结果:

表头:学校名称地址邮政编码收集时间数据读取完毕:SchoolData(address=晋宁县古城镇旧寨村  , schoolName=晋宁县古城镇古城中学, postcode=650604, collectDate=Sun Jan 05 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县二街乡老高村  , schoolName=晋宁县二街中学, postcode=650608, collectDate=Mon Jan 06 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县晋城镇寺林街  , schoolName=晋宁县晋城中学, postcode=650605, collectDate=Tue Jan 07 00:00:00 CST 2020)SchoolData(address=云南省晋宁县六街乡中学  , schoolName=晋宁县六街中学, postcode=650609, collectDate=Wed Jan 08 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县新街乡文河村  , schoolName=晋宁县新街中学, postcode=650606, collectDate=Thu Jan 09 00:00:00 CST 2020)SchoolData(address=晋宁县中和乡普照路  , schoolName=晋宁县中和中学, postcode=650600, collectDate=Fri Jan 10 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县上蒜乡上蒜中学  , schoolName=晋宁县上蒜乡上蒜中学, postcode=650607, collectDate=Sat Jan 11 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县化乐乡化乐村  , schoolName=晋宁县化乐乡中学, postcode=650611, collectDate=Sun Jan 12 00:00:00 CST 2020)SchoolData(address=晋宁县夕阳乡夕阳街夕阳民族中学  , schoolName=晋宁县夕阳民族中学, postcode=650603, collectDate=Mon Jan 13 00:00:00 CST 2020)SchoolData(address=云南省昆明市晋宁县宝峰镇古城村委会小古城村  , schoolName=晋宁县宝峰镇宝峰中学, postcode=650601, collectDate=Tue Jan 14 00:00:00 CST 2020)SchoolData(address=晋宁县双河乡椿树营  , schoolName=晋宁县双河民族中学, postcode=650602, collectDate=Wed Jan 15 00:00:00 CST 2020)SchoolData(address=昆明市富民县永定镇环城南路7号永定中学  , schoolName=富民县永定中学, postcode=650400, collectDate=Thu Jan 16 00:00:00 CST 2020)SchoolData(address=富民县永定镇大西山村  , schoolName=富民县勤劳中学, postcode=650400, collectDate=Fri Jan 17 00:00:00 CST 2020)SchoolData(address=富民县大营镇大营街16号  , schoolName=富民县大营中学, postcode=650400, collectDate=Sat Jan 18 00:00:00 CST 2020)SchoolData(address=云南省昆明市罗免乡者北村委会者北街  , schoolName=富民县第二中学, postcode=650401, collectDate=Sun Jan 19 00:00:00 CST 2020)

Excel导出

模拟生成数据:

public class DataGenerate {    /**     * 数据生成     */    public static List<SchoolData> data() {        List<SchoolData> schoolDataList = new ArrayList<>();        SchoolData schoolData;        for (int i = 0; i < 15; i++) {            schoolData = new SchoolData();            schoolData.setSchoolName("第" + i + "XXX中学");            schoolData.setAddress("云南省昆明市XXXXX");            schoolData.setPostcode("123456");            schoolData.setCollectDate(new Date());            schoolDataList.add(schoolData);        }        return schoolDataList;    }}

测试导出:

同导入,导出也有以下两种写法。LongestMatchColumnWidthStyleStrategy用来设置自动列宽,如果需要设置列宽、行高等属性,可以在Model类上添加对应注解进行设置,如@ColumnWidth、@ContentRowHeight、@HeadRowHeight等等。

@Testpublic void exportExcel() {ExcelWriter excelWriter = null;try {excelWriter = EasyExcel.write("F:\\测试数据_副本.xlsx", SchoolData.class).build();WriteSheet writeSheet = EasyExcel.writerSheet("学校数据").registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();excelWriter.write(DataGenerate.data(), writeSheet);} finally {// 千万别忘记finish 会帮忙关闭流if (excelWriter != null) {excelWriter.finish();}}}@Testpublic void exportExcelSimple() {EasyExcel.write("F:\\测试数据_副本.xlsx", SchoolData.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("学校数据").doWrite(DataGenerate.data());}

导出结果:

基于Excel模板的填充

模板:

{} 代表普通变量 {.} 代表是list的变量。

模板填充测试:

@Testpublic void excelTemplateFill() {ExcelWriter excelWriter = EasyExcel.write("F:\\测试数据_副本3.xlsx").withTemplate("F:\\模板.xlsx").build();WriteSheet writeSheet = EasyExcel.writerSheet().build();FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();//填充列表数据excelWriter.fill(DataGenerate.data(), fillConfig, writeSheet);//填充普通数据Map<String, Object> map = new HashMap<String, Object>();map.put("name", "狗子");map.put("date", "2021-02-19");excelWriter.fill(map, writeSheet);excelWriter.finish();}

填充结果:

Web中的导入和导出

import com.alibaba.excel.EasyExcel;import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.net.URLEncoder;@RestControllerpublic class SchoolDataController {    /**     * 导入Excel     */    @PostMapping("/import")    public String importExcel(MultipartFile file) throws IOException {        EasyExcel.read(file.getInputStream(), SchoolData.class, new SchoolDataListener()).sheet().doRead();        return "success";    }    /**     * 导出Excel     */    @GetMapping("/export")    public void exportExcel(HttpServletResponse response) throws IOException {        response.setContentType("application/vnd.ms-excel");        response.setCharacterEncoding("utf-8");        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");        // 这里需要设置不关闭流        EasyExcel.write(response.getOutputStream(), SchoolData.class).autoCloseStream(Boolean.FALSE).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("学校数据").doWrite(DataGenerate.data());    }}

参考:官方文档

(0)

相关推荐

  • python 操作Excle

    import xlwt,xlrd import openpyxl import xlrd import pymysql import xlrd import pymysql fname = " ...

  • EasyExcel,让 excel 导入导出更加简单

    做积极的人,而不是积极废人! 来源:jianshu.com/p/8f3defdc76d4 EasyExcel GitHub上的官方说明 快速开始 maven仓库地址 导入 导出 总结 EasyExce ...

  • 得明亲子春令营初体验

    孩子身体的毛病,年龄越大,越难以根除,在无意识中影响他一生的发展,为解决这样的问题,得明健身在五一期间,特推出为期四天的,亲子春令营,锻炼.经络体检(建档并跟踪追访),给孩子一个健康光明的未来!!! ...

  • 【广东】夏雪晴《厨房初体验——凉拌海带丝》指导老师:林燕玲

    厨房初体验--凉拌海带丝 东华小学东城校区二年级 夏雪晴 一个风和日丽的早上,我开开心心地和外婆.妈妈一起去菜市场买菜,因为我今天要亲自尝试制作一道我最喜欢吃的美味菜肴--凉拌海带丝. 在制作之前,外 ...

  • 3千元贵在了哪?——贝纳利Tornado302赛道初体验

    前两天贝纳利正式发布了新款的飓风302,并以Tornado302的全新命名正式回归品牌,当然售价也回到了起初的29800元,在这个国产品牌降价的大潮,就有人质疑贝纳利是不是飘了? 品牌回归 29800 ...

  • 草堂小学之开学初体验

    成都学区房已获授权 本文是模仿另一篇热门文章<五朵金花小学的入读初体验-成师附小>,强行蹭热度. 开学已经2个多月了,草堂小学给我的总体感觉是那么好,放弃成外本部名额不亏. (请参考挨骂之 ...

  • 五朵金花之入读初体验——成师附小

    成都学区房已获授权 溜爸前言 这位家长是:跨城市搬到成都来读书的那种,之前还在东部一个沿海城市居住,现在已然来到成都,开始小学生活. 关于为什么要来成都,可查看这篇:上学是一件举家搬迁的事情,总要折腾 ...

  • 开塞露の初体验o(╥﹏╥)o

    姐不在江湖,但江湖却有姐的传说...... 我身体有一个鸡肋的生理本能,去到一个新的地方,开始的几天都很难排便. 刚上高中那阵子,要再学校住宿,周末才能回家. 这就让我那个神奇的生理特质兴奋过了头. ...

  • 雪落无声伴课来——网络教学初体验

    清晨,拉开窗帘,见天灰蒙蒙的,像笼着一层薄烟. 细细地观看,哦!是下雪了! 这雪,轻,柔,细,像柳絮一般,从空中缓缓地飘落下来,袅袅婷婷,轻柔曼妙. 低头,俯瞰楼下的路,路面已经被罩上了一层薄薄的雪, ...

  • 试驾初体验 女司机全方位感受范爷同款科雷嘉

    点击上方 e汽车 关注我们 文 | 饭冰冰 微信号 | eautocar 写在前面的话 这里没有高大上的试驾图,也没有专业的测评词汇,有的只是一个女司机的真实试驾初体验-- 试驾车辆:东风雷诺科雷嘉 ...

  • 新登镇小 郎翊臻 || 老板初体验

    郁达夫少年文学院会员优秀习作 老板初体验 新登镇小 五年级 郎翊臻 这几天,新天地非常热闹,来了好多摆地摊的人,也包括我们,他们卖的商品五花八门,各式各样,还特别便宜. 而我们的摊位是这一条夜市的打卡 ...