一、说明

最近公司开发一个财务使用的系统,报表比较多。 以前用过POI,JXL,也遇到过OOM问题, 所以学习一下阿里的Excel工具:https://github.com/alibaba/easyexcel

开发中主要用到:

① 简单数据导出,也就是查询实体导出(这里一般会自定义导出某些字段)

②自定义单元格样式,比如高亮显示"小计","总计"行等

③合并单元格

那就先来试试简单数据导出吧

、pom引入

从官方文档上,目前版本2.2.0-beta1,那我们随便选一个2.X的版本,网上资料一般是1.1.1版本的,1.X和2.X版本个人感觉差别是有点大的~~

<!-- 阿里开源EXCEL -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <!-- <version>1.1.1</version>-->
            <version>2.1.6</version>
        </dependency>

三、准备工作

这里准备两个实体,一个是官方文档的实体 DemoData类(带注解),一个是自定义的User类

@Data
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}
@Data
public class User {
    private String uid;
    private String name;
    private Integer age;
    private Date birthday;
}

准备模拟数据

/**
     * 模拟实体数据
     *
     * @return
     */
    private List<DemoData> getDemoDataList() {
        List<DemoData> list = new ArrayList<DemoData>();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            //data.setDate(new Date());
            //设置属性一部分为空值
            if (i % 2 == 0) {
                data.setDoubleData(null);
            } else {
                data.setDate(new Date());
            }
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }


    /**
     * 模拟实体数据
     *
     * @return
     */
    private List<User> getUserList() {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setUid("识别码" + i);
            user.setAge(i * 10);
            //设置属性一部分为空值
            if (i % 2 == 0) {
                user.setBirthday(new Date());
            } else {
                user.setBirthday(null);
            }
            user.setName("用户名" + i);
            list.add(user);
        }
        return list;
    }

 I:\\temp\\writeDemo1.xlsx 和 I:\\temp\\writeDemo2.xlsx

 设置表头和内容的策略,这个是官方文档复制过来的。

/**
     * 获取策略,这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
     *
     * @return
     */
    private HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() {
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为红色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());

        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 10);

        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        //contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景绿色
        //contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
        //WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        //contentWriteFont.setFontHeightInPoints((short)20);
        //contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }

 

四、设置列宽

1.X的版本是通过生成sheet,使用sheet设置宽度,2.X版本后大部分方法已经过期,不推荐使用了,而大部分都是使用EasyExcel类直接构造并实现大部分功能;

根据官方文档的提示只需要注册写入处理器就可以了(WriteHandler),我这里直接复制一份过来修修改改~红色代码部分主要是关键部分

/**
 * 自定义拦截器
 *
 * @author
 */
public class CustomSheetWriteHandler implements SheetWriteHandler {
    //列宽集合
    private List<Integer> columnWidths;
    //构造
    public CustomSheetWriteHandler(List<Integer> columnWidths) {
        this.columnWidths = columnWidths;
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class);

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        LOGGER.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo());

        // 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
       /* CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0);
        DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
        DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"测试1", "测试2"});
        DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
        writeSheetHolder.getSheet().addValidationData(dataValidation);*/
        LOGGER.info("普通策略设置setColumnWidth开始~");
        if(CollectionUtils.isNotEmpty(columnWidths)){
            for (int i = 0; i < columnWidths.size(); i++) {
                writeSheetHolder.getSheet().setColumnWidth(i, columnWidths.get(i));
            }
        }
        LOGGER.info("普通策略设置setColumnWidth结束~");
    }
}

 

五、根据注解导出数据到Excel文件中

/**
     * 写入到固定文件中
     *
     * @throws IOException
     */
    @Test
    public void writeToExcelFile() {
        //写入的文excel文件
        String fileName = "I:\\temp\\writeDemo1.xlsx";
        //获取头和内容的策略
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy();

        //列宽的策略,宽度是小单位
        Integer columnWidthArr[] = {3000, 6000};
        List<Integer> columnWidths = Arrays.asList(columnWidthArr);
        CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths);

        // 根据用户传入字段 假设我们只要导出 string date
        String[] filds = {"string", "date"};

        //获取模拟的实体数据集合
        List<DemoData> demoDataList = getDemoDataList();

        //这里需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, DemoData.class)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .registerWriteHandler(customSheetWriteHandler)
                //这个是导出需要展示的列
                .includeColumnFiledNames(Arrays.asList(filds))
                .sheet("模板")
                .doWrite(demoDataList);
    }

效果:

Android 使用阿里EasyExcel框架 阿里的excel_User

 

 

 

六、自定义导出数据到Excel文件中

/**
     * 写入到固定文件中,这里不使用注解的方式写入列和对应的属性
     *
     * @throws IOException
     */
    @Test
    public void writeToExcelFile2() {
        //写入的文excel文件
        String fileName = "I:\\temp\\writeDemo2.xlsx";
        //获取头和内容的策略
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy();

        //列宽的策略,宽度是小单位
        Integer columnWidthArr[] = {3000, 3000, 2000, 6000};
        List<Integer> columnWidths = Arrays.asList(columnWidthArr);
        CustomSheetWriteHandler customSheetWriteHandler = new CustomSheetWriteHandler(columnWidths);

        // 根据用户传入字段 假设我们只要导出 string date
        String[] filds = {"uid", "name", "age", "birthday"};

        String[] headers = {"唯一识别码", "姓名", "年龄", "生日"};

        List head = getHeadByFilds(headers);

        //获取模拟的实体数据集合
        List<User> userList = getUserList();

        //这里指定头的名字去写入,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName)
                .head(head)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .registerWriteHandler(customSheetWriteHandler)
                .includeColumnFiledNames(Arrays.asList(filds))
                .sheet("模板")
                .doWrite(userList);
    }

效果:

Android 使用阿里EasyExcel框架 阿里的excel_User_02

六、总结 

后面继续实现合并单元格、自定义单元格、web导出和导入等功能~