EasyExcel复杂表头导出(一对多)
前言
之前,写了 EasyExcel复杂表头导入(一对多)的博客,效果不错,好多网友留言让我再写一个导入的。盛情难却,就写了一个,发现问题很多。
关于EasyPoi 框架的问题,在此不再赘述,参考我的另一篇博客,地址如下:
EasyExcel复杂表头导入(一对多)_的博客-CSDN博客_easyexcel复杂表头
实际上,官方文档和网上都没有详细的导出教程,需要自己参考官方去实现。我搞了半天只弄成功了一个半桶水的,十分惭愧,在此记录一下,方便回溯。
说明:EasyExcel无法处理List里面嵌套List的情况,我采用的方案是通过表格合并的来实现。
下面,先给出具体实现,然后再谈谈问题。
EasyExcel一对多导出的实现
Entity 对象
/**
* 客户信息导出类,指明导出模板样式等。是真正和EasyPoi交互的类
*/
@Data
@EqualsAndHashCode
@HeadRowHeight(30)
@ContentRowHeight(20)
@ColumnWidth(20)
@HeadStyle(fillForegroundColor = 44)
@NoArgsConstructor
class Customer extends BaseRowModel implements Serializable {
@ExcelProperty({"客户编号"})
private String userCode;
@ExcelProperty({"客户名称"})
private String userName;
@ColumnWidth(25)
@ExcelProperty({"客户所在地址"})
private String address;
@ExcelProperty({"联系人信息", "联系人姓名"})
private String personName;
@ExcelProperty({"联系人信息", "联系电话"})
private String telephone;
public Customer(CustomerInfo customerInfo) {
this.userCode = customerInfo.getUserCode();
this.userName = customerInfo.getUserName();
this.address = customerInfo.getAddress();
this.personName = customerInfo.getPersonList().get(0).getPersonName();
this.telephone = customerInfo.getPersonList().get(0).getTelephone();
}
public Customer(CustomerInfo.Person person) {
this.personName = person.getPersonName();
this.telephone = person.getTelephone();
}
}
/**
* 客户基本信息类,类比程序从service层拿到的信息
* 实际上,EasyPoi只能读取简单String、boolean、integer、float byte[] 等简单数据类型。无法处理List、Map等数据类型。
* 当前,你也可以只定义类型转换器Converter,具体见文章末尾的参考连接。
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
class CustomerInfo {
private String userCode;
private String userName;
private String address;
private List<Person> personList;
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Person {
private String personName;
private String telephone;
}
}
Controller 层
@IgnoreUserToken
@GetMapping("/exportExcel")
@ApiOperation("导出Excel")
public void exportExcel(HttpServletResponse response) throws Exception {
// 获取导出数据,模拟从service层拿到list数据。
List<CustomerInfo> list = getData();
// 获取所有客户信息中,联系人最多的数量。并以此数量作为行合并的依据
int maxColNum = 1;
for (CustomerInfo ele : list) {
if (ele.getPersonList().size() > maxColNum) {
maxColNum = ele.getPersonList().size();
}
}
// 整理,讲List包含List的数据格式,改成List的格式
final int finalMaxColNum = maxColNum;
List<Customer> result = list.stream()
.flatMap(ele -> {
List<Customer> temp = new ArrayList<>();
// 获取当前客户联系人的数量
int len = ele.getPersonList().size();
// 先添加一条完整的客户信息
temp.add(new Customer(ele));
for (int i = 1; i < finalMaxColNum; i++) {
if (i >= len) {
// 达不到maxColNum的,补null占位。
temp.add(new Customer());
} else {
// 只添加联系人信息
temp.add(new Customer(ele.getPersonList().get(i)));
}
}
return temp.stream();
}).collect(Collectors.toList());
// 设置excel表头样式
WriteSheet sheet = EasyExcel.writerSheet("客户信息").head(Customer.class).sheetNo(1).build();
// 设置excel表格样式
ExcelWriter writer = EasyExcel.write(response.getOutputStream()).needHead(true).excelType(ExcelTypeEnum.XLSX)
.registerWriteHandler(new LoopMergeStrategy(maxColNum, 0)) // 设置第一列每maxColNum行合并
.registerWriteHandler(new LoopMergeStrategy(maxColNum, 1)) // 设置第二列每maxColNum行合并
.registerWriteHandler(new LoopMergeStrategy(maxColNum, 2)) // 设置第三列每maxColNum行合并
.build();
// 写入excel数据
writer.write(result, sheet);
// 通知浏览器以附件的形式下载处理,设置返回头要注意文件名有中文
response.setHeader("Content-disposition", "attachment;filename=" + new String("客户信息列表".getBytes("gb2312"), "ISO8859-1") + ".xlsx");
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
writer.finish();
}
getDate方法(用于模拟service层拿到的数据)
public static List<CustomerInfo> getData() {
List<CustomerInfo> data = new ArrayList<>();
CustomerInfo customer = new CustomerInfo();
customer.setUserCode("CT_jx001");
customer.setUserName("江西电信公司");
customer.setAddress("江西省南昌市青山湖区");
CustomerInfo.Person person1 = new CustomerInfo.Person("张三", "12345678910");
CustomerInfo.Person person2 = new CustomerInfo.Person("李四", "10987654321");
List<CustomerInfo.Person> personList = new ArrayList<>();
personList.add(person1);
personList.add(person2);
customer.setPersonList(personList);
data.add(customer);
CustomerInfo customer2 = new CustomerInfo();
customer2.setUserCode("CT_jx002");
customer2.setUserName("广东电信公司");
customer2.setAddress("广东省广州市花都区");
CustomerInfo.Person person12 = new CustomerInfo.Person("小明", "12345678910");
CustomerInfo.Person person22 = new CustomerInfo.Person("小红", "10987654321");
CustomerInfo.Person person23 = new CustomerInfo.Person("小王", "12345678910");
List<CustomerInfo.Person> personList2 = new ArrayList<>();
personList2.add(person12);
personList2.add(person22);
personList2.add(person23);
customer2.setPersonList(personList2);
data.add(customer2);
return data;
}
效果
接口是get类型的,浏览器直接访问,即可下载文件,效果如下。
顺便给出debug效果,方便理解。
debug效果
问题及展望
从实现效果即可看出本方法的问题,就是会出现空行。
但是,这个空行避免不了,因为多行合并,只能按照最大值给,且不能动态调整。
这种方式,虽然可以实现复杂表头的导出,但显示不是令人满意的,主要是因为存在空行的问题。
我实在是找不出更好的解决方案,在此仅提供如下思路。
也你能通过EasyPoi的自定义拦截器、数据格式转换器、模板写入、合并单元格、重复多次写入等功能实现。
参考链接
除官网地址外,参考如下文章。
Can not find ‘Converter‘ support class List问题解决_我取这个昵称总没被使用吧?的博客-CSDN博客问题描述com.alibaba.excel.exception.ExcelDataConvertException: Can not find ‘Converter’ support class List.问题解释EasyExcel开源框架中Converter接口的convertToExcelData只实现了转换BigDecimal、Bolean、Byte[]、btye[]、Byte、Date、Double、File、Float、InputStream、Integer、Long、Short、URL这些[这里是图片006]https://blog.csdn.net/qq_41049371/article/details/120156305EasyExcel ExcelDataConvertException:Can not find ‘Converter‘ support class ArrayList问题解决_旭东怪的博客-CSDN博客问题描述:com.alibaba.excel.exception.ExcelDataConvertException:Cannotfind’Converter’supportclassArrayList.问题分析:1、查看doWrite(List data)的源码时发现Converter接口的convertToExcelData只实现了转换BigDecimal、Bolean、Byte[]、btye[]、Byte、Date、Double、File、Float、InputStream、…[这里是图片007]https://blog.csdn.net/qq_38974638/article/details/116609844
相关文章
- 直接在代码里面对list集合进行分页
- .NET Framework 4.5新特性详解
- 大数据的简要介绍
- 大数据的由来
- 高斯混合模型的自然梯度变量推理
- timing-wheel 仿Kafka实现的时间轮算法
- 使用Navicat软件连接自建数据库(Linux系统)
- 那一天,我被Redis主从架构支配的恐惧
- Redis 深入了解键的过期时间
- C#使用委托调用实现用户端等待闪屏
- 基于流计算 Oceanus 和 Elasticsearch Service 构建百亿级实时监控系统
- GRAND | 转录调控网络预测数据库
- JFreeChart API中文文档
- 临床相关突变查询数据库
- TIGER | 人类胰岛基因变化查询数据库
- 视频边缘计算网关EasyNVR在视频整体监控解决方案中的应用分析
- Apache Arrow - 大数据在数据湖后的下一个风向标
- 常见的电商数据指标体系
- AKShare-艺人数据-艺人流量价值
- MySQL中多表联合查询与子查询的这些区别,你可能不知道!