zoukankan      html  css  js  c++  java
  • EasyExcel小试牛刀

    转自:https://www.cnblogs.com/fanerwei222/p/12029411.html

    某种偶然的机会遇到了这个插件, 听说很牛X, 我之前也不知道, 不过还是耍了一下子, 遂记录下来.

    官方的demo官网都有,传送门 : https://alibaba-easyexcel.github.io/index.html

    当然, 官网的demo只是简单的演示, 如果你要实现的表格内容比较复杂, 那么需要自己去定义你的数据类, 并且自己去实现, 遂记录下我实现的一个不简单也不复杂的表格.

    首先看实现的效果图: 比较粗糙, 不过一般的操作都有

    由于我没有设置样式, 所以看起来还是比较丑的, 不过没关系, 功能实现了, 页面后面再说嘛.

    直接上pom配置:

    复制代码
    <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.0.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
        <scope>provided</scope>
    </dependency>
    复制代码

    这两个是必须要的, lombok主要是方便, 我用的EasyExcel版本是2.0.5, 应该可以换成其他的也没事.

    两个数数据类和一个主类直接贴出来看代码吧.

    复制代码
    package com.domaven.orange.easyExcel;
    
    import com.alibaba.excel.annotation.ExcelIgnore;
    import com.alibaba.excel.annotation.ExcelProperty;
    import com.alibaba.excel.annotation.write.style.ColumnWidth;
    import com.alibaba.excel.annotation.write.style.ContentRowHeight;
    import com.alibaba.excel.annotation.write.style.HeadRowHeight;
    import lombok.Data;
    
    import java.util.Date;
    import java.util.List;
    
    /**
     * TODO
     * 示范数据实体
     * {} 括起来的代表着层级标题
     */
    @Data
    @ContentRowHeight(20)
    @HeadRowHeight(20)
    @ColumnWidth(25)
    public class DemoData {
    
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "序号"})
        private String order;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "企业名称"})
        private String tenantName;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "项目名称"})
        private String projectName;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "幢号"})
        private Integer houseOrder;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "层数"})
        private Integer flowsNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "规划用途"})
        private String regularUse;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "住宅", "住宅套数"})
        private Integer houseNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "住宅", "住宅面积"})
        private Integer houseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "非住宅", "非住宅套数"})
        private Integer noHouseNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "非住宅", "非住宅面积"})
        private Integer noHouseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "总建筑面积"})
        private Integer totalHouseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "许可证号"})
        private Integer admitNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "发证日期"})
        private Date subIdDate;
        /**
         * 小计
         */
        @ExcelIgnore
        private List<TotalData> minTotal;
        /**
         * 总计
         */
        @ExcelIgnore
        private List<TotalData> allTotal;
    }
    复制代码
    复制代码
    package com.domaven.orange.easyExcel;
    
    import com.alibaba.excel.annotation.ExcelIgnore;
    import com.alibaba.excel.annotation.ExcelProperty;
    import lombok.Data;
    
    import java.util.Date;
    
    /**
     * TODO
     * 统计数据实体
     */
    @Data
    public class TotalData {
    
        @ExcelIgnore
        private String order;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "企业名称"})
        private String tenantName;
    
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "幢号"})
        private Integer houseOrder;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "层数"})
        private Integer flowsNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "规划用途"})
        private String regularUse;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "住宅", "住宅套数"})
        private Integer houseNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "住宅", "住宅面积"})
        private Integer houseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "非住宅", "非住宅套数"})
        private Integer noHouseNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "非住宅", "非住宅面积"})
        private Integer noHouseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "总建筑面积"})
        private Integer totalHouseArea;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "许可证号"})
        private Integer admitNums;
        @ExcelProperty({"2019年商品房预售许可证发证统计报表", "发证日期"})
        private Date subIdDate;
    
        public TotalData setTenantName(String tenantName) {
            this.tenantName = tenantName;
            return this;
        }
    
        public TotalData setOrder(String order) {
            this.order = order;
            return this;
        }
    }
    复制代码
    复制代码
    package com.domaven.orange.easyExcel;
    
    import com.alibaba.excel.EasyExcel;
    import com.alibaba.excel.ExcelWriter;
    import com.alibaba.excel.write.builder.ExcelWriterBuilder;
    import com.alibaba.excel.write.merge.LoopMergeStrategy;
    import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
    import com.alibaba.excel.write.metadata.WriteSheet;
    import com.alibaba.excel.write.metadata.style.WriteCellStyle;
    import com.alibaba.excel.write.metadata.style.WriteFont;
    import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
    import org.apache.poi.ss.usermodel.FillPatternType;
    import org.apache.poi.ss.usermodel.IndexedColors;
    import org.springframework.beans.BeanUtils;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    /**
     * TODO
     * 使用EasyExcel按照自己想要的数据格式生成excel
     */
    public class MainEasyExcel {
    
        /**
         * 分批写入数据
         * @param args
         */
        public static void main(String[] args) {
            /**
             * 文件保存地址
             */
            String fileName = "d://tmp/good.xlsx";
    
            /**
             * 弄一个写建造器
             */
            ExcelWriterBuilder builder = EasyExcel.write(fileName, DemoData.class);
            /**
             * 装点数据
             */
            List<DemoData> list = data();
            /**
             * 将数据按企业名称进行分组
             */
            Map<String, List<DemoData>> map = list.stream().collect(Collectors.groupingBy(DemoData::getTenantName));
    
            /**
             * 给除了"小计""总计"等行外的所有有效数据标序号
             */
            final int[] mapOrder = {1};
            map.values().forEach(
                    value ->
                        value.forEach(
                                v -> {
                                    v.setOrder(String.valueOf(mapOrder[0]));
                                    mapOrder[0]++;
                                }
                        )
            );
            List<TotalData> allTotalDataList = new ArrayList<>();
            /**
             * 是否处理总计行标记
             */
            boolean isDepressAllTotal = false;
            /**
             * 从第四行开始合并(下标为3)
             */
            int mergeStartWithRow = 3;
            /**
             * 从第二列开始合并(下标为1)
             */
            int mergeStartWithColumn = 1;
            /**
             * 合并单元格需要用到的参数分别如下
             * firstRowIndex : 起始行索引
             * lastRowIndex : 结束行索引
             * firstColumnIndex : 起始列索引
             * lastColumnIndex : 结束列索引
             */
            int firstRowIndex = 0, lastRowIndex = 0, firstColumnIndex = 0, lastColumnIndex = 0;
            /**
             * 填充数据数量计数器
             */
            int count = 0;
            for (Map.Entry entry : map.entrySet()) {
                /**
                 * 设置要合并的单元格的位置
                 */
                firstRowIndex = mergeStartWithRow + count;
                lastRowIndex = ((List<DemoData>) entry.getValue()).size() + firstRowIndex - 1;
                firstColumnIndex = mergeStartWithColumn;
                lastColumnIndex = mergeStartWithColumn;
                /**
                 * 合并公司名称行
                 */
                builder.registerWriteHandler(getOnceMerge(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex));
                /**
                 * 合并小计行
                 */
                builder.registerWriteHandler(getOnceMerge(lastRowIndex + 1, lastRowIndex + 1, 0, 1));
                count = count + ((List<DemoData>) entry.getValue()).size() + 1;
            }
    
            /**
             * 合并总计行
             * 加1是小计那一行
             * 加2是总计那一行
             */
            builder.registerWriteHandler(getOnceMerge(lastRowIndex + 2, lastRowIndex + 2, 0, 1));
            /**
             * 写器
             */
            ExcelWriter writer = builder.build();
            /**
             * sheet页
             */
            WriteSheet sheet = EasyExcel.writerSheet("测试").build();
            for (Map.Entry entry : map.entrySet()) {
                /**
                 * 分批写入数据
                 */
                writer.write((List<DemoData>) entry.getValue(), sheet);
                /**
                 * 写入小计行数据
                 */
                List<TotalData> totalDataList = new ArrayList<>();
                totalDataList.add(((List<DemoData>) (entry.getValue())).get(0).getMinTotal().get(0).setTenantName("小计").setOrder("小计"));
                writer.write(totalDataList, sheet);
    
                /**
                 * 设置总计行数据
                 */
                if (!isDepressAllTotal) {
                    allTotalDataList.add(((List<DemoData>) (entry.getValue())).get(0).getAllTotal().get(0).setTenantName("总计").setOrder("总计"));
                    isDepressAllTotal = true;
                }
            }
            /**
             * 写入总计行数据
             */
            writer.write(allTotalDataList, sheet);
            writer.finish();
    
        }
    
        /**
         * 测试方法, 直接写入方式
         * @param args
         */
        public static void mainDirect(String[] args) {
            String fileName = "d://tmp/good.xlsx";
            List<DemoData> list = data();
            Map<String, List<DemoData>> map = list.stream().collect(Collectors.groupingBy(DemoData::getTenantName));
            EasyExcel.write(fileName, DemoData.class).sheet("数据模板").doWrite(data());
        }
    
        /**
         * 按照需要的数据格式构建数据
         * @return
         */
        private static List<DemoData> data() {
            List<DemoData> list = new ArrayList<DemoData>();
    
            for (int i = 0; i < 10; i++) {
                DemoData data = new DemoData();
                data.setOrder(String.valueOf(i));
                if (i % 2 == 0) {
                    data.setTenantName("北京科技");
                } else if (i % 3 == 0) {
                    data.setTenantName("南京公司");
                } else {
                    data.setTenantName("天津包子铺");
                }
                data.setProjectName("打铁项目");
                data.setHouseOrder(123);
                data.setFlowsNums(8);
                data.setRegularUse("没用");
                data.setHouseNums(2);
                data.setHouseArea(120);
                data.setNoHouseNums(4);
                data.setNoHouseArea(400);
                data.setTotalHouseArea(900);
                data.setAdmitNums(8888888);
                data.setAdmitNums(10);
                data.setSubIdDate(new Date());
                /**
                 * 特殊的小计和总计数据
                 */
                List<TotalData> totalDataList = new ArrayList<>();
                TotalData totalData = new TotalData();
                BeanUtils.copyProperties(data, totalData);
                totalDataList.add(totalData);
                data.setMinTotal(totalDataList);
                data.setAllTotal(totalDataList);
                list.add(data);
            }
            return list;
        }
    
        /**
         * 获取样式策略
         * 阿里官方模板
         * @return
         */
        public static HorizontalCellStyleStrategy getStyle() {
            /**
             * 头的策略
             */
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            /**
             * 背景设置为红色
             */
            headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 20);
            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;
            /**
             * 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
             * EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板").doWrite(data());
             */
        }
    
        /**
         * 获取合并策略
         * 固定的合并策略,官方模板
         * @return
         */
        public static LoopMergeStrategy getLoopMergeStrategy() {
            /**
             * 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写
             */
            LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 1);
            return loopMergeStrategy;
        }
    
        /**
         * 合并单元格
         * 根据需要指定位置的单元格进行合并
         * @param firstRowIndex 起始行索引
         * @param lastRowIndex 结束行索引
         * @param firstColumnIndex 起始列索引
         * @param lastColumnIndex 结束列索引
         * @return
         */
        public static OnceAbsoluteMergeStrategy getOnceMerge(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
            OnceAbsoluteMergeStrategy once = new OnceAbsoluteMergeStrategy(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex);
            return once;
        }
    
    }
    复制代码

    代码注释也是十分详尽的, 可以直接看代码了.

  • 相关阅读:
    在新浪爱问上看到的有趣名字都记下来
    FastReports_4.14.1 _Cliff手动安装
    计算机算法对做事效率的启发(既要高强度猛攻,也要细水长流)
    有趣的数组
    listView 分页加载数据
    如何隐藏Cognos Viewer
    使用DBUnit实现对数据库的测试
    通过Jasmine和Guard自动测试JavaScript
    for惠普2013实习生
    栈的顺序存储,所谓的顺序栈
  • 原文地址:https://www.cnblogs.com/sharpest/p/13714044.html
Copyright © 2011-2022 走看看