原创:转载需注明原创地址 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;
} }

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

EasyExcel小试牛刀的更多相关文章

  1. Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用(后续)

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]里面提到了Microsoft 身份认证,其实这也是一大块需要注意的地方,特作为后续补充这些知识点.上章是使用了Microsof ...

  2. 小试牛刀C#作为脚本语言执行解密

    背景 我们知道Unity3d是通过C#脚本语言的形式来实现游戏的逻辑代码编写,同样SCOTT服务器也设置了通过C#脚本来实现游戏逻辑,但是本文并不是想真正分析解密他们的运行机制,只是想通过自己的一个需 ...

  3. 20145225唐振远 《Java程序设计》第1周学习总结——小试牛刀

    20145225唐振远<Java程序设计>第1周学习总结——小试牛刀 教材学习内容总结 1.java语言概述:一门高级编程语言. 2.java语言的三种技术构架:java SE.java ...

  4. (linux shell)第一章--小试牛刀(上)

    来源:(linux shell)第一章--小试牛刀(上) 从今天開始,我们一起来学习<linux shell脚本攻略>这本书. 1.1简单介绍 shell脚本一般是一个以#!起始的文本文件 ...

  5. 正则表达式小试牛刀--匹配我的csdn博文标题

    正则表达式小试牛刀--匹配我的博文标题 作者:vpoet 邮箱:vpoet_sir@163.com 正则匹配,我以我的博客页面的博客标题为例:http://blog.csdn.net/u0130187 ...

  6. 微信小程序基于最新版1.0开发者工具分享-小试牛刀(视频)+发布流程

    第一章:小程序初级入门教程 小试牛刀[含视频] 视频地址:https://v.qq.com/x/page/i0554akzobq.html 这一章节中,我们尝试着写一个最简单的例子,包含 2 个静态页 ...

  7. 阿里巴巴excel工具easyexcel 助你快速简单避免OOM

    Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有 ...

  8. easyExcel导出excel的简单使用

    easyExcel导出excel的简单使用 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定 ...

  9. 阿里 EasyExcel 使用及避坑

    github地址:https://github.com/alibaba/easyexcel 原本在项目中使用EasyPoi读取excel,后来为了统一技术方案,改用阿里的EasyExcel.EasyE ...

随机推荐

  1. 论文翻译:2020_Acoustic Echo Cancellation by Combining Adaptive Digital Filter and Recurrent Neural Network

    论文地址:https://arxiv.53yu.com/abs/2005.09237 自适应数字滤波与循环神经网络相结合的回声消除技术 摘要 回声消除(AEC)在语音交互中起关键作用.由于明确的数学原 ...

  2. Mysql 设计超市经营管理系统,包括员工库存表(stock) 和 仓库表(warehouse)

    互联网技术学院周测机试题(三) 一.需求分析 为进一步完善连锁超市经营管理,提高管理效率,减少管理成本,决定开发一套商品管理系统,用于日常的管理.本系统分为商品管理.员工管理.店铺管理,库存管理等功能 ...

  3. CSS基础-7 盒子模型大小

    在盒子模型当中,有些元素是影响盒子大小的. 首先border就会影响盒子的大小. 其次padding也会影响盒子的大小. 例子: .one { width:100px; height:100px; b ...

  4. 初识python 之 爬虫:使用正则表达式爬取“古诗文”网页数据

    通过requests.re(正则表达式) 爬取"古诗文"网页数据. 详细代码如下: #!/user/bin env python # author:Simple-Sir # tim ...

  5. java 关于 重写、覆写、覆盖、重载 的总结【不想再傻傻分不清了】

    1.前言 有些东西,名称不同,其实就是一个东西,你说是扯淡不? 2.重写 重写,又叫覆写.覆盖 ,注解@Override,词义为推翻 , 用法特点是继承父类后,重写的父类方法名字.参数.返回值必须相同 ...

  6. 利用Spring AOP切面对用户访问进行监控

    开发系统时往往需要考虑记录用户访问系统查询了那些数据.进行了什么操作,尤其是访问重要的数据和执行重要的操作的时候将数记录下来尤显的有意义.有了这些用户行为数据,事后可以以用户为条件对用户在系统的访问和 ...

  7. go包管理速通,一篇文章就够了,再也不用担心因为不会导包被辞退

    前言 最近在看一些go语言相关的书,发现了一个有意思的事情:其中一本书最新印刷的版本是2017年3月,而golang包管理的后起之秀go module伴随go1.11于2018年8月诞生--因此,书里 ...

  8. ASCII、Unicode和UTF-8等常见字符编码格式介绍

    信息存储在计算机中是转换成二进制来存储的,二进制的发明据说是来源于中国阴阳八卦.后德国数理哲学大师莱布尼茨是最早接触中华文化的欧洲人之一,从他的传教士朋友鲍威特寄给他的拉丁文译本<易经>中 ...

  9. 《剑指offer》面试题20. 表示数值的字符串

    问题描述 请实现一个函数用来判断字符串是否表示数值(包括整数和小数).例如,字符串"+100"."5e2"."-123"."3.1 ...

  10. 自从学会了VBA字典,VLOOKUP都不那么香了

    上篇博文中,小爬曾多次为VBA字典带货.鼓励多用字典,可以让我们的VBA脚本工具执行更快.今天小爬来细聊一下VBA字典的具体应用!如果你有一定VBA基础,那么看完你一定会对VBA字典有全新的认识:如果 ...