文档章节

Java操作Excel的一个小工具

FEINIK
 FEINIK
发布于 07/14 15:13
字数 1437
阅读 294
收藏 6

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

1 概述

    想必大家在平常的项目开发过程中经常会涉及到Excel文件的导出功能,一般都会选择Apache poi组件来完成,但是通常需要写大量代码,无疑增加了复杂度,且存在一个严重的问题就是非常的耗内存,容易导致OOM,幸运的是阿里开源了easyexcel,它是基于Apache poi而开发的一个组件,easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,但在实际使用过程中发现easyexcel操作具体每个cell还不是很便捷,所以我重写了一个组件easyexcel-util,本项目基于阿里easyexcel,在此基础上做了更进一步的封装,使其写入数据更加便捷,通过抽离出的ExcelDataHandler接口更容易处理每个cell的字体与样式,下面将介绍如何使用easyexcel-util。

项目地址:https://github.com/AIFEINIK/easyexcel-util

2 easyexcel-util组件使用

2.1 Maven包引入

<dependency>
    <groupId>com.github.aifeinik</groupId>
    <artifactId>easyexcel-util</artifactId>
    <version>1.0</version>
</dependency>

2.2 Excel数据写入

2.2.1 小数据量一次性写入单个sheet,使用默认样式

public class ExcelTest {

    CampaignModel m1 = new CampaignModel("2019-01-01", "10000000", "campaign1", "12.21", "100", "0.11");
    CampaignModel m2 = new CampaignModel("2019-01-02", "12000010", "campaign2", "13", "99", "0.91");
    CampaignModel m3 = new CampaignModel("2019-01-03", "12001010", "campaign3", "10", "210", "1.13");
    CampaignModel m4 = new CampaignModel("2019-01-04", "15005010", "campaign4", "21.9", "150", "0.15");

    ArrayList<CampaignModel> data1 = Lists.newArrayList(m1, m2);
    ArrayList<CampaignModel> data2 = Lists.newArrayList(m3, m4);

    @Test
    public void writeExcelWithOneSheet() throws Exception {
        ExcelUtil.writeExcelWithOneSheet(new File("G:/tmp/campaign.xlsx"),
                "campaign",
                data1);
    }
}

写入效果如下:

2.2.2 小数据量一次性写入单个sheet,使用自定义样式

    @Test
    public void writeExcelWithOneSheet2() throws Exception {
        ExcelUtil.writeExcelWithOneSheet(new File("G:/tmp/campaign.xlsx"),
                "campaign",
                data1,
                new CampaignDataHandler());
    }

写入效果如下:

2.2.3 小数据量一次性写入多个sheet,默认样式

    @Test
    public void writeExcelWithMultiSheet() throws Exception {
        Map<String, List<? extends BaseRowModel>> map = new HashMap<>();
        map.put("sheet1", data1);
        map.put("sheet2", data2);

        ExcelUtil.writeExcelWithMultiSheet(new File("G:/tmp/campaign.xlsx"), map);
    }

写入效果如下:

2.2.4 小数据量一次性写入多个sheet,使用自定义样式

    @Test
    public void writeExcelWithMultiSheet2() throws Exception {
        Map<String, List<? extends BaseRowModel>> map = new HashMap<>();
        map.put("sheet1", data1);
        map.put("sheet2", data2);

        ExcelUtil.writeExcelWithMultiSheet(new File("G:/tmp/campaign.xlsx"), map, new CampaignDataHandler());
    }

写入效果如下:

2.2.5 大数据量分批写入单个sheet

    @Test
    public void writeOneSheetWithWrapWriter() {
        ExcelWrapWriter wrapWriter = null;
        try {
            OutputStream os = new FileOutputStream("G:/tmp/campaign.xlsx");
            //默认样式
            //wrapWriter = new ExcelWrapWriter(os, ExcelTypeEnum.XLSX);

            //自定义excel样式
            wrapWriter = new ExcelWrapWriter(os, ExcelTypeEnum.XLSX, new CampaignDataHandler());

            List<CampaignModel> models1 = Lists.newArrayList(m1, m2);
            List<CampaignModel> models2 = Lists.newArrayList(m3, m4);

            //第一批次写入设置包含head头
            ExcelUtil.writeExcelWithOneSheet(wrapWriter, "sheet1", true, models1);

            //第二批次开始不需要在写入head头
            ExcelUtil.writeExcelWithOneSheet(wrapWriter, "sheet1", false, models2);
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            //close IO
            if (wrapWriter != null) {
                wrapWriter.finish();
            }
        }
    }

数据分批写入excel文件,可通过该方式写入超大数据,而不至于一次写入大数据量导致OOM问题

2.2.6 大数据量分批写入多个sheet

    @Test
    public void writeMultiSheetWithWrapWriter() {
        ExcelWrapWriter wrapWriter = null;
        try {
            //os流不需要单独close,可通过wrapWriter.finish()来关闭
            OutputStream os = new FileOutputStream("G:/tmp/campaign.xlsx");
            //默认样式
            //wrapWriter = new ExcelWrapWriter(os, ExcelTypeEnum.XLSX);

            //自定义excel样式
            wrapWriter = new ExcelWrapWriter(os, ExcelTypeEnum.XLSX, new CampaignDataHandler());
            Map<String, List<? extends BaseRowModel>> batch1 = new HashMap<>();
            List<CampaignModel> models1 = Lists.newArrayList(m1, m2);
            List<CampaignModel> models2 = Lists.newArrayList(m3, m4);
            batch1.put("sheet1", models1);
            batch1.put("sheet2", models2);

            Map<String, List<? extends BaseRowModel>> batch2 = new HashMap<>();
            List<CampaignModel> models3 = Lists.newArrayList(m4, m2);
            List<CampaignModel> models4 = Lists.newArrayList(m3, m1);
            batch2.put("sheet1", models3);
            batch2.put("sheet2", models4);

            //第一批次写入设置包含head头
            ExcelUtil.writeExcelWithMultiSheet(wrapWriter, true, batch1);

            //第二批次开始不需要在写入head头
            ExcelUtil.writeExcelWithMultiSheet(wrapWriter, false, batch2);
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            //close IO
            if (wrapWriter != null) {
                wrapWriter.finish();
            }
        }
    }

2.3 ExcelValueFormat注解介绍

通过该注解更加方便的处理每个数据的具体格式, 内部采用MessageFormat.format进行数据格式化,如下代码,其中cost花费字段注解了@ExcelValueFormat(format = "{0}$") 那么如果cost = 100 则写入Excel后内容为100$

@Data
public class CampaignModel extends BaseRowModel implements Serializable {

    @ExcelProperty(value = "日期", index = 0)
    private String day;

    @ExcelProperty(value = "广告系列 ID", index = 1)
    private String campaignId;

    @ExcelProperty(value = "广告系列", index = 2)
    private String campaignName;

    @ExcelProperty(value = "费用", index = 3)
    @ExcelValueFormat(format = "{0}$")
    private String cost;

    @ExcelProperty(value = "点击次数", index = 4)
    private String clicks;

    @ExcelProperty(value = "点击率", index = 5)
    @ExcelValueFormat(format = "{0}%")
    private String ctr;

}

2.4 通过实现 ExcelDataHandler 接口来设置具体每个cell的样式与字体

public interface ExcelDataHandler {

    /**
     * Excel head头部字体设置
     * @param font
     * @param cellIndex 列索引
     */
    void headFont(Font font, int cellIndex);

    /**
     * Excel head头部样式设置
     * @param style
     * @param cellIndex 列索引
     */
    void headCellStyle(CellStyle style, int cellIndex);

    /**
     * Excel 除head外的内容字体设置
     * @param font
     * @param cellIndex 列索引
     */
    void contentFont(Font font, int cellIndex, Object data);

    /**
     * Excel 除head外的内容样式设置
     * @param style
     * @param cellIndex 列索引
     */
    void contentCellStyle(CellStyle style, int cellIndex);

    /**
     * Excel sheet
     * @param sheetIndex sheet索引
     * @param sheet
     */
    void sheet(int sheetIndex, Sheet sheet);
}

列如实现类如下:

public class CampaignDataHandler implements ExcelDataHandler {

    @Override
    public void headCellStyle(CellStyle style, int cellIndex) {
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
    }

    @Override
    public void headFont(Font font, int cellIndex) {
        font.setColor(IndexedColors.WHITE.getIndex());
    }

    @Override
    public void contentCellStyle(CellStyle style, int cellIndex) {
        style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
    }

    @Override
    public void contentFont(Font font, int cellIndex, Object data) {
        CampaignModel campaign = (CampaignModel) data;
        switch (cellIndex) {
            case 4: //这里的值为Model对象中ExcelProperty注解里的index值
                if (Long.valueOf(campaign.getClicks()) > 100) { //表示将点击次数大于100的第4列也就是点击次数列的cell字体标记为红色
                    font.setColor(IndexedColors.RED.getIndex());
                    font.setFontName("宋体");
                    font.setItalic(true);
                    font.setBold(true);
                }
                break;

        }
    }

    @Override
    public void sheet(int sheetIndex, Sheet sheet) {
        System.out.println("sheetIndex = [" + sheetIndex + "]");
    }
}

3 总结

    本文主要介绍了easyexcel-util组件不同场景的使用方式、通过ExcelValueFormat注解可以方便的处理数据的具体格式,以及通过ExcelDataHandler 接口来灵活设置具体每个cell的样式与字体。

© 著作权归作者所有

FEINIK
粉丝 227
博文 61
码字总数 61705
作品 0
广州
高级程序员
私信 提问
XXL-EXCEL v1.1.1 发布,Java 对象和 Excel 转换工具

v1.1.1 新特性 1、支持设置Field水平位置,如居中、居左; 2、底层API优化,预约多Sheet操作支持; 3、空Cell导入抛错问题修复; 4、Cell数据类型识别优化,全类型支持; 5、导入时支持空Exc...

许雪里
2018/10/24
1K
9
Java Apache POI 操作 Excel 导出

版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82655653 Java Apache POI 操作 Excel 导出 Java 可以通过 Apache POI......

asing1elife
2018/09/12
0
0
Java程序员从笨鸟到菜鸟之(一百零四)java操作office和pdf文件(二)利用POI实现数据导出excel报表

在上一篇博客中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式。不仅仅简单的读取office中的数据.尤其是在生产管理...

长平狐
2012/11/12
1K
0
Java对象和Excel转换工具XXL-EXCEL

《Java对象和Excel转换工具XXL-EXCEL》 ![donate](http://

许雪里
2017/09/13
771
0
PageOffice V4.0 Excel常用的接口对象---Workbook类

Workbook 类代表一个Excel文档,用来动态输出数据到Excel文档并且控制其表格格式及编辑功能。Workbook 对象是PageOffice开发平台定义的Excel数据输出对象,可作为PageOfficeCtrl.SetWriter ...

山里的红杏
2018/09/11
21
0

没有更多内容

加载失败,请刷新页面

加载更多

x005-构造程序逻辑

构造程序逻辑 结合生活例子运用程序语言 百钱百鸡是我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何...

伟大源于勇敢的开始
36分钟前
3
0
问题汇总

最近在补知识面的时候发现有几个问题, 第一个呢是 教程 没有提前准备好。(视频方面的吧 书上面的 都要有) 第二个呢是 ,开发工具太多了,搞不清楚到底用哪个了 和哪个教程相匹配。 第三个...

T型人才追梦者
今天
7
0
OSChina 周三乱弹 —— 我以前超喜欢晒太阳的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @watergood :分享海先生的单曲《东篱》: 《东篱》- 海先生 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :早.先喝几大碗鸡汤 @小小...

小小编辑
今天
18
1
法国电力项目二期正式验收

2019年12月10日, 法国电力项目二期正式验收. 二期实现了一个个人能源的自交易/自管理APP + 管理后台。 并就未来的合作技术方向进行了探讨: 去中心化数据存储/搜索引擎 可信计算/零知识证明...

怎当她临去时秋波那一转
今天
13
0
索引延迟关联

前言 今天在看代码的时候学习到了一种索引的优化,就先在此记录下来。 具体 举个例子,原sql如下: SELECT * FROM TABLE WHERE INDEX = '' LIMIT 10000, 10; 现象 就算INDEX用了查询索引,...

无敌小杰杰
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部