Java实操 -> 基于注解、反射实现Excel导出动态合并
Java资料站
共 10412字,需浏览 21分钟
· 2021-10-01
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
一、效果演示及相关说明
由于项目信息不能泄露,这里采用测试数据,下面的测试数据是手动输入的,仅用来辅助说明下面的解释
测试数据原始效果
合并后的效果
二、首先创建注解类。
作用:加载导出字段上,order 表示分组次数。0表示一次分组,1表示二次分组,依次类推
isflag 表示分组策略,如果为true,则用来这个字段作为当前合并的依据,所以和该字段order相同的字段都会合并
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author hhb
* @date :2021/9/16 13:58
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MergeFlag {
int order() default 0;
boolean isflag() default false;
}
三、自定义合并策略
这里使用的是alibabaEasyExcel的Excel处理框架,相关导出、导入实现如果不懂请查看官方文档
https://www.yuque.com/easyexcel/doc/easyexcel
根据官方提供的单次合并策略OnceAbsoluteMergeStrategy可知,实现合并的核心代码如下
CellRangeAddress cellRangeAddress = new CellRangeAddress(this.firstRowIndex, this.lastRowIndex, this.firstColumnIndex, this.lastColumnIndex);
writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
所以我们接下来需要想办法先知道那些数据是需要合并的,所以我们要预处理导出的数据.
然后根据数据上面的注解解析出一个合并map,map的key是 order,value是一个对象,包含通过反射得到的Field[]数组的index索引、合并标识。
详细见代码
/**
* 生成合并策略Map
* @param dataList
* @return
*/
private void generateMergeMap(List dataList,Class<?> type){
//解析分组依据
List<MergeFlagDTO> mergeFlagDTOList = this.analyzeData(type);
Object preObj=null;
for (int i=0;i<dataList.size();i++){
//获取合并表示
Object currObj=dataList.get(i);
if (null!=preObj){
//处理数据
try {
this.handData(0,mergeFlagDTOList,currObj,preObj,i);
} catch (IllegalAccessException e) {
throw new BadRequestAlertException("导出时发生解析错误!");
}
}
preObj=currObj;
}
}
/**
* 解析数据
* @param type
* @return
*/
private List<MergeFlagDTO> analyzeData(Class<?> type) {
Map<Integer, MergeFlagDTO> mergeOrderMap=new HashMap<>();
Field[] fields = type.getDeclaredFields();
//获取注解列表
for (int i=0;i<fields.length;i++){
MergeFlag mergeFlag = fields[i].getAnnotation(MergeFlag.class);
if (null!=mergeFlag){
//加入索引
MergeFlagDTO dto =mergeOrderMap.get(mergeFlag.order())==null?new MergeFlagDTO():mergeOrderMap.get(mergeFlag.order());
dto.getMergeIndexs().add(i);
dto.setOrder(mergeFlag.order());
if (mergeFlag.isflag()){
dto.setField(fields[i]);
}
mergeOrderMap.put(mergeFlag.order(),dto);
}
}
return new ArrayList<>(mergeOrderMap.values()).stream().filter(item -> null != item.getField()).sorted(Comparator.comparing(MergeFlagDTO::getOrder)).collect(Collectors.toList());
}
/**
* 处理数据
* @param start
* @param mergeFlagDTOList
* @param currObj
* @param preObj
* @param index
* @throws IllegalAccessException
*/
private void handData(int start, List<MergeFlagDTO> mergeFlagDTOList, Object currObj, Object preObj, int index) throws IllegalAccessException {
if (start<mergeFlagDTOList.size()){
MergeFlagDTO dto = mergeFlagDTOList.get(start);
Field field = dto.getField();
field.setAccessible(true);
Object currValue = field.get(currObj);
Object preValue = field.get(preObj);
if (currValue.equals(preValue)) {
this.fillMergeMap(dto.getMergeIndexs(),index);
//继续递归
this.handData(start+1,mergeFlagDTOList,currObj,preObj,index);
}
}
}
/**
* 填充合并map
* @param key
* @param index
*/
private void fillMergeMap(Integer key, Integer index){
List<RowRangeDTO> rangeDTOS = mergeMap.get(key)==null?new ArrayList<>():mergeMap.get(key);
//判断是否需要新加
boolean needAdd=true;
//遍历
for (RowRangeDTO rangeDTO:rangeDTOS){
if (rangeDTO.getEndIndex().equals(index)){
rangeDTO.setEndIndex(index+1);
needAdd=false;
}
}
//如果没有匹配上的就说明需要
if (needAdd){
rangeDTOS.add(new RowRangeDTO(index,index+1));
}
mergeMap.put(key,rangeDTOS);
}
最后根据合并map对数据进行合并操作
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer integer){
//每一个cell只合并一次
if (cell.getRowIndex()==1&&cell.getColumnIndex()==0){
mergeMap.keySet().forEach(key-> mergeMap.get(key).forEach(rowRangeDTO -> sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRangeDTO.getStartIndex(),rowRangeDTO.getEndIndex(),key,key))));
}
}
作者 | 樱岛麻衣Ss
来源 | cnblogs.com/ydmysm/p/merge_excel.html
加锋哥微信: java3459 围观锋哥朋友圈,每天推送Java干货!
评论
豆瓣9.7,这部Java神作第3版重磅上市!
文末赠书Java 程序员们开年就有重磅好消息,《Effective Java 中文版(原书第 3 版)》要上市啦!该书的第1版出版于 2001 年,当时就在业界流传开来,受到广泛赞誉。时至今日,已热销近20年,本书第 3 版已是 Java 程序员的必读神书,被誉为“Java 四大名著之一”,甚至连
编码之外
0
多人同时导出 Excel 干崩服务器!新来的阿里大佬给出的解决方案太优雅了!
点击关注公众号,Java 干货及时推送↓推荐阅读:面试辅导,我们出大成果了!来源:juejin.cn/post/7259249904777838629前言 业务诉求:考虑到数据库数据日渐增多,导出会有全量数据的导出,多人同时导出可以会对服务性能造成影响,导出涉及到mysql查询的io操作,
Java技术栈
1
15种时间序列预测方法总结(包含多种方法代码实现)
向AI转型的程序员都关注了这个号👇👇👇在这篇文章中,我们将深入探讨时间序列预测的基本概念和方法。我们将首先介绍单元预测和多元预测的概念,然后详细介绍各种深度学习和传统机器学习方法如何应用于时间序列预测,包括循环神经网络(RNN)、一维卷积神经网络(1D-CNN)、Transformer、自回归模型(
机器学习AI算法工程
0
SpringBoot 实现图片防盗链功能
程序员的成长之路互联网/程序员/技术/资料共享 关注阅读本文大概需要 4 分钟。来自:blog.csdn.net/weixin_46157208/article/details/138051737前言出于安全考虑,我们需要后端返回的图片只允许在某个网站内展示,不想被爬虫拿到图片地
程序员的成长之路
0
大量 Java 开源项目停更...
点击关注公众号,Java 干货及时推送↓推荐阅读:投了 100 多份简历后…出品 | OSC开源社区(ID:oschina2013)Sonatype 发布了最新的一份《软件供应链状况》报告,深入探讨了如何在充满选择的世界中定义更好的软件,并探讨人工智能 (AI) 对软件开发的深远
Java技术栈
0
一站式解决方案:基于 Arthas 实现服务发现和权限控制
来源:juejin.cn/post/7281849496983994383👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书福利全栈前后端分离博客项目 2.0 版本完结啦, 演示链接
小哈学Java
0
Java 神作,必读!
Java 程序员们开年就有重磅好消息,《Effective Java 中文版(原书第 3 版)》要上市啦!该书的第1版出版于 2001 年,当时就在业界流传开来,受到广泛赞誉。时至今日,已热销近20年,本书第 3 版已是 Java 程序员的必读神书,被誉为“Java 四大名著之一”,甚至连 Java
小哈学Java
0
用 Shader 实现旗帜飘扬动画效果
我觉得对于刚入门 3D 编程的朋友来说,如果能够完成代码创建模型数据->创建材质->编写Shader动画这一系列,想必会有满满的成就感。今天就用 Cocos Creator 的 utils.MeshUtils.createMesh 接口,带大家感受一下这个流程。这个流程不仅可以用于新手学
COCOS
2