Java导出Excel并合并单元格

需求:需要在导出excel时合并指定的单元格

 ruoyi excel

项目基于若伊框架二次开发,本着能用现成的就不自己写的原则,先是尝试了@Excel注解中needMerge属性

     /*** 是否需要纵向合并单元格,应对需求:含有list集合单元格)*/public boolean needMerge() default false;

查了一圈别人的使用,大致是需要定义一个List集合,集合元素为对象,对象中的属性标注@Excel注解,并表明name属性

照葫芦画瓢

@Getter
@Setter
@ToString
public class CutterControlVO {/** 主键 */private Long id;/** 工厂编码 */@Excel(name = "工厂编码",needMerge = true)private String factoryCode;/** 产线编码 */@Excel(name = "产线编码",needMerge = true)private String productionLineCode;/** 设备编号 */@Excel(name = "设备编号",needMerge = true)private String deviceNumber;/** 设备名称 */@Excel(name = "设备名称",needMerge = true)private String deviceName;@Excel(name = "检测刀具编码",needMerge = true)private String cutterCode;/** 换刀时间 */@JsonFormat(timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")@Excel(name = "换刀时间",dateFormat = "yyyy-MM-dd HH:mm:ss",needMerge = true)private Date cutterChangeTime;/** 上刀数 */@Excel(name = "上刀数",needMerge = true)private Integer upperKnifeNumber;/** 下刀数 */@Excel(name = "下刀数",needMerge = true)private Integer lowerKnifeNumber;@Excel(name = "更换人员",needMerge = true)private String modifyUser;/** 备注 */@Excel(name = "备注",needMerge = true)private String remark;@Excel(name = "换刀位置")private List<CutterVO> cutterChangePosition;@Excel(name = "累计分切米数")private List<CutterVO> accumulatedCuttingMeters;}
@Getter
@Setter
@ToString
public class CutterVO {@Excel(name = "上刀左")private Integer upperKnifeLeft;@Excel(name = "上刀中")private Integer upperKnifeCenter;@Excel(name = "上刀右")private Integer upperKnifeRight;@Excel(name = "下刀左")private Integer lowerKnifeLeft;@Excel(name = "下刀中")private Integer lowerKnifeCenter;@Excel(name = "下刀右")private Integer lowerKnifeRight;
}
@PostMapping("/export")
public void export(HttpServletResponse response) throws Exception{List<CutterControl> cutterControlList = cutterControlService.getCutterControlList();//设置导出的数据表格式List<CutterControlVO> cutterControlVOList = new ArrayList<>();CutterControlVO cutterControlVO = null;for (CutterControl cutterControl : cutterControlList) {cutterControlVO = new CutterControlVO();CutterVO cutterPosition = new CutterVO();cutterPosition.setUpperKnifeLeft(cutterControl.getCutterChangePositionUpperKnifeLeft());cutterPosition.setUpperKnifeCenter(cutterControl.getCutterChangePositionUpperKnifeCenter());cutterPosition.setUpperKnifeRight(cutterControl.getCutterChangePositionUpperKnifeRight());cutterPosition.setLowerKnifeLeft(cutterControl.getCutterChangePositionLowerKnifeLeft());cutterPosition.setLowerKnifeCenter(cutterControl.getCutterChangePositionLowerKnifeCenter());cutterPosition.setLowerKnifeRight(cutterControl.getCutterChangePositionLowerKnifeRight());CutterVO accumulatedCuttingMeters = new CutterVO();accumulatedCuttingMeters.setUpperKnifeLeft(cutterControl.getAccumulatedCuttingMetersUpperKnifeLeft());accumulatedCuttingMeters.setUpperKnifeCenter(cutterControl.getAccumulatedCuttingMetersUpperKnifeCenter());accumulatedCuttingMeters.setUpperKnifeRight(cutterControl.getAccumulatedCuttingMetersUpperKnifeRight());accumulatedCuttingMeters.setLowerKnifeLeft(cutterControl.getAccumulatedCuttingMetersLowerKnifeLeft());accumulatedCuttingMeters.setLowerKnifeCenter(cutterControl.getAccumulatedCuttingMetersLowerKnifeCenter());accumulatedCuttingMeters.setLowerKnifeRight(cutterControl.getAccumulatedCuttingMetersLowerKnifeRight());BeanUtils.copyProperties(cutterControl,cutterControlVO);cutterControlVO.setCutterChangePosition(Arrays.asList(cutterPosition));cutterControlVO.setAccumulatedCuttingMeters(Arrays.asList(accumulatedCuttingMeters));cutterControlVOList.add(cutterControlVO);}ExcelUtil<CutterControlVO> util = new ExcelUtil<CutterControlVO>(CutterControlVO.class);util.exportExcel(response,cutterControlVOList,"切刀管控台账数据");
}

查看导出效果:

黑人问号脸?

突然想到别人都是采用的是一个List集合,于是我注释了一个List,此时效果如下:

 可以看到,一个List效果是正常显示的,数据获取和显示也是正常的。

若伊使用的Excel导出工具类底层采用apache poi ,只能导出简单的excel表格,涉及复杂excel表格或者需要自定义表格时就比较难操作

使用阿里的easyExcel来实现复杂excel表格的导出

easyExcel

首先引入POM依赖

    <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.7</version></dependency>

1、不合并单元格的写法

实体类

@Getter
@Setter
public class CutterControl {/** 主键 */@ExcelIgnoreprivate Long id;/** 工厂编码 */@ExcelProperty(value = "工厂编码")private String factoryCode;/** 产线编码 */@ExcelProperty(value = "产线编码")private String productionLineCode;/** 设备编号 */@ExcelProperty(value = "设备编号")private String deviceNumber;/** 设备名称 */@ExcelProperty(value = "设备名称")private String deviceName;@ExcelProperty(value = "检测刀具编码")private String cutterCode;@ExcelProperty(value = "上刀左")private Integer cutterChangePositionUpperKnifeLeft;@ExcelProperty(value = "上刀中")private Integer cutterChangePositionUpperKnifeCenter;@ExcelProperty(value = "上刀右")private Integer cutterChangePositionUpperKnifeRight;@ExcelProperty(value = "下刀左")private Integer cutterChangePositionLowerKnifeLeft;@ExcelProperty(value = "下刀中")private Integer cutterChangePositionLowerKnifeCenter;@ExcelProperty(value = "下刀右")private Integer cutterChangePositionLowerKnifeRight;@ExcelProperty(value = "上刀左")private Integer accumulatedCuttingMetersUpperKnifeLeft;@ExcelProperty(value = "上刀中")private Integer accumulatedCuttingMetersUpperKnifeCenter;@ExcelProperty(value = "上刀右")private Integer accumulatedCuttingMetersUpperKnifeRight;@ExcelProperty(value = "下刀左")private Integer accumulatedCuttingMetersLowerKnifeLeft;@ExcelProperty(value = "下刀中")private Integer accumulatedCuttingMetersLowerKnifeCenter;@ExcelProperty(value = "下刀右")private Integer accumulatedCuttingMetersLowerKnifeRight;/** 换刀时间 */@JsonFormat(timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")@ExcelProperty(value = "换刀时间")@ColumnWidth(20)private Date cutterChangeTime;/** 上刀数 */@ExcelProperty(value = "上刀数")private Integer upperKnifeNumber;/** 下刀数 */@ExcelProperty(value = "下刀数")private Integer lowerKnifeNumber;@ExcelProperty(value = "更换人员")private String modifyUser;/** 备注 */@ExcelProperty(value = "备注")private String remark;}

@ExcelIgnore :设置表格忽略该属性

@ColumnWidth(20): 设置列宽

controller代码

  @PostMapping("/export")public void export(HttpServletResponse response) throws Exception{List<CutterControl> cutterControlList = cutterControlService.getCutterControlList();String fileName = System.getProperty("user.dir") + "/" + System.currentTimeMillis() + ".xlsx";// 构建ExcelWriterExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();// 构建sheetWriteSheet writeSheet = EasyExcel.writerSheet("切刀管控台账数据").head(CutterControl.class).build();// 写sheetexcelWriter.write(cutterControlList, writeSheet);excelWriter.finish();}
结果:

2、自定义列合并策略

参考eastExcel文档可知,在实体类上添加属性即可实现我想要的效果

写Excel | Easy Excel

@Getter
@Setter
@EqualsAndHashCode
public class ComplexHeadData {@ExcelProperty({"主标题", "字符串标题"})private String string;@ExcelProperty({"主标题", "日期标题"})private Date date;@ExcelProperty({"主标题", "数字标题"})private Double doubleData;
}

再次照葫芦画瓢

@Getter
@Setter
public class CutterControl {/** 主键 */@ExcelIgnoreprivate Long id;/** 工厂编码 */@ExcelProperty(value = "工厂编码")private String factoryCode;/** 产线编码 */@ExcelProperty(value = "产线编码")private String productionLineCode;/** 设备编号 */@ExcelProperty(value = "设备编号")private String deviceNumber;/** 设备名称 */@ExcelProperty(value = "设备名称")private String deviceName;@ExcelProperty(value = "检测刀具编码")private String cutterCode;@ExcelProperty({"换刀位置", "上刀左"})private Integer cutterChangePositionUpperKnifeLeft;@ExcelProperty({"换刀位置", "上刀中"})private Integer cutterChangePositionUpperKnifeCenter;@ExcelProperty({"换刀位置", "上刀右"})private Integer cutterChangePositionUpperKnifeRight;@ExcelProperty({"换刀位置", "下刀左"})private Integer cutterChangePositionLowerKnifeLeft;@ExcelProperty({"换刀位置", "下刀中"})private Integer cutterChangePositionLowerKnifeCenter;@ExcelProperty({"换刀位置", "下刀右"})private Integer cutterChangePositionLowerKnifeRight;@ExcelProperty({"累计分切米数", "上刀左"})private Integer accumulatedCuttingMetersUpperKnifeLeft;@ExcelProperty({"累计分切米数", "上刀中"})private Integer accumulatedCuttingMetersUpperKnifeCenter;@ExcelProperty({"累计分切米数", "上刀右"})private Integer accumulatedCuttingMetersUpperKnifeRight;@ExcelProperty({"累计分切米数", "下刀左"})private Integer accumulatedCuttingMetersLowerKnifeLeft;@ExcelProperty({"累计分切米数", "下刀中"})private Integer accumulatedCuttingMetersLowerKnifeCenter;@ExcelProperty({"累计分切米数", "下刀右"})private Integer accumulatedCuttingMetersLowerKnifeRight;/** 换刀时间 */@JsonFormat(timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")@ExcelProperty(value = "换刀时间")@ColumnWidth(20)private Date cutterChangeTime;/** 上刀数 */@ExcelProperty(value = "上刀数")private Integer upperKnifeNumber;/** 下刀数 */@ExcelProperty(value = "下刀数")private Integer lowerKnifeNumber;@ExcelProperty(value = "更换人员")private String modifyUser;/** 备注 */@ExcelProperty(value = "备注")private String remark;}

其余不用修改

效果如下:

若需要导出excel在浏览器,修改Controller代码如下:

 @GetMapping("/export")public void export(HttpServletResponse response) throws Exception{List<CutterControl> cutterControlList = cutterControlService.getCutterControlList();String fileName = new String("切刀管控台账数据.xlsx");fileName = URLEncoder.encode(fileName, "UTF-8");response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf8");response.setHeader("Content-disposition", "attachment;filename=" + fileName );EasyExcel.write(response.getOutputStream(),CutterControl.class).sheet("切刀管控台账数据").doWrite(cutterControlList);}

3、自定义行合并策略

具体业务暂时用不到,需要的可参考这个博客

https://www.cnblogs.com/monianxd/p/16359369.html

导入excel并处理同名列

由于实体类中存在excel列名重复的情况,所以如果不进行处理,会出现只有一个有值的情况,最简单的处理方式如下:

同名列添加所在位置的索引,默认从0开始

@Getter
@Setter
public class CutterControl {/** 主键 */@ExcelIgnoreprivate Long id;/** 工厂编码 */@ExcelProperty(value = "工厂编码")private String factoryCode;/** 产线编码 */@ExcelProperty(value = "产线编码")private String productionLineCode;/** 设备编号 */@ExcelProperty(value = "设备编号")private String deviceNumber;/** 设备名称 */@ExcelProperty(value = "设备名称")private String deviceName;@ExcelProperty(value = "检测刀具编码")private String cutterCode;@ExcelProperty(value = {"换刀位置", "上刀左"},index = 5)private Integer cutterChangePositionUpperKnifeLeft;@ExcelProperty(value = {"换刀位置", "上刀中"},index = 6)private Integer cutterChangePositionUpperKnifeCenter;@ExcelProperty(value = {"换刀位置", "上刀右"},index = 7)private Integer cutterChangePositionUpperKnifeRight;@ExcelProperty(value = {"换刀位置", "下刀左"},index = 8)private Integer cutterChangePositionLowerKnifeLeft;@ExcelProperty(value = {"换刀位置", "下刀中"},index = 9)private Integer cutterChangePositionLowerKnifeCenter;@ExcelProperty(value = {"换刀位置", "下刀右"},index = 10)private Integer cutterChangePositionLowerKnifeRight;@ExcelProperty(value = {"累计分切米数", "上刀左"},index = 11)private Integer accumulatedCuttingMetersUpperKnifeLeft;@ExcelProperty(value = {"累计分切米数", "上刀中"},index = 12)private Integer accumulatedCuttingMetersUpperKnifeCenter;@ExcelProperty(value = {"累计分切米数", "上刀右"},index = 13)private Integer accumulatedCuttingMetersUpperKnifeRight;@ExcelProperty(value = {"累计分切米数", "下刀左"},index = 14)private Integer accumulatedCuttingMetersLowerKnifeLeft;@ExcelProperty(value = {"累计分切米数", "下刀中"},index = 15)private Integer accumulatedCuttingMetersLowerKnifeCenter;@ExcelProperty(value = {"累计分切米数", "下刀右"},index = 16)private Integer accumulatedCuttingMetersLowerKnifeRight;/** 换刀时间 */@JsonFormat(timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")@ExcelProperty(value = "换刀时间")@ColumnWidth(20)private Date cutterChangeTime;/** 上刀数 */@ExcelProperty(value = "上刀数")private Integer upperKnifeNumber;/** 下刀数 */@ExcelProperty(value = "下刀数")private Integer lowerKnifeNumber;@ExcelProperty(value = "更换人员")private String modifyUser;/** 备注 */@ExcelProperty(value = "备注")private String remark;}

导入Controller代码

@PostMapping("/import")public R importData(@RequestParam(value = "file") MultipartFile file) throws IOException {String fileName = file.getOriginalFilename();String suffixName = fileName.substring(fileName.lastIndexOf("."));if (!(suffixName.equals(".xlsx"))) {return R.fail("请上传xlsx格式文件");}EasyExcel.read(file.getInputStream(), CutterControl.class, new ReadListener<CutterControl>() {/*** 单次缓存的数据量*/public static final int BATCH_COUNT = 100;/***临时存储*/private List<CutterControl> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);@Overridepublic void invoke(CutterControl data, AnalysisContext context) {cachedDataList.add(data);if (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {saveData();}/*** 加上存储数据库*/private void saveData() {cutterControlService.batchInsertCutterControl(cachedDataList);log.info("{}条数据,开始存储数据库!", cachedDataList.size());log.info("存储数据库成功!");}}).sheet().doRead();return R.ok();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/632728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4人遇难,北京突发火情 富维烟火识别防止悲剧再次发生

在北京一处居民区&#xff0c;一场突如其来的火灾夺走了四条宝贵的生命。火情迅速蔓延&#xff0c;烟雾弥漫&#xff0c;居民们猝不及防。这一悲剧再次提醒我们&#xff0c;火灾预防和早期识别的重要性不容忽视。 在这样的背景下&#xff0c;北京富维图像公司开发的FIS智能图像…

搭建自己的媒体矩阵-关于三微一端的媒体矩阵最简方案

引言 随着互联网的快速发展&#xff0c;媒体矩阵已成为品牌宣传的重要战略。通过搭建自己的媒体矩阵&#xff0c;企业、品牌和个人能够更有效地触达目标受众&#xff0c;传递信息、建立品牌形象&#xff0c;并与用户进行深度互动。本文将深入探讨如何制定一个有效的三微一端媒…

高光谱分类论文解读分享之Grid Network: 基于各向异性视角下特征提取的高光谱影像分类

IEEE GRSL 2023&#xff1a;Grid Network: 基于各向异性视角下特征提取的高光谱影像分类 题目 Grid Network: Feature Extraction in Anisotropic Perspective for Hyperspectral Image Classification 作者 Zhonghao Chen , Student Member, IEEE, Danfeng Hong , Senior …

【H3C】配置AAA认证和Telnet远程登陆,S5130 Series交换机

AAA配置步骤为&#xff1a; 1.开启telent远程登陆服务 2.创建用户&#xff0c;设置用户名、密码、用户的服务类型 3.配置终端登录的数量 4.配置vlan-if的ip地址&#xff0c;用来远程登陆 5.允许对应的vlan通过 1.开启telent远程登陆服务 sys …

【驱动】I2C驱动分析(四)-关键API解析

简介 在Linux内核源代码中的driver目录下包含一个i2c目录 i2c-core.c这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口。   i2c-dev.c实现了I2C适配器设备文件的功能&#xff0c;每一个I2C适配器都被分配一个设备。通过适配器访设备时的主设备号都为89&#xff0c;次设备号…

PBR材质纹理下载

03:10 按照视频里的顺序 我们从第6个网站开始倒数 点击本行文字或下方链接 进入查看 6大网站地址 网址查看链接&#xff1a; http://www.uzing.net/community_show-1962-48-48-35.html 06 Tectures Wood Fence 001 | 3D TEXTURES 简介&#xff1a;最大的纹理网站之一&#x…

机器学习:BootStrapping(Python)

import numpy as np import pandas as pd from sklearn.neighbors import KNeighborsClassifier from sklearn.decomposition import PCA # 主成分分析 from sklearn.preprocessing import LabelEncoder, StandardScaler # 类别标签编码&#xff0c;标准化处理 import matplo…

推荐算法常见的评估指标

推荐算法评估指标比较复杂&#xff0c;可以分为离线和在线两部分。召回、粗排、精排和重排由于定位区别&#xff0c;其评估指标也会有一定区别&#xff0c;下面详细讲解。 1 召回评价体系 召回结果并不是最终推荐结果&#xff0c;其本质是为后续排序层服务的&#xff0c;故核…

中国联通助力吴江元荡生态岸线打造5G+自动驾驶生态长廊

吴江&#xff0c;素有“鱼米之乡”“丝绸之府”的美誉&#xff0c;其地理位置优越&#xff0c;地处太湖之滨。近年来&#xff0c;随着长三角生态绿色一体化发展示范区&#xff08;以下简称“示范区”&#xff09;的建立&#xff0c;元荡更是声名大噪&#xff0c;成为众多游客心…

GNU Radio简介及流程图搭建

文章目录 前言一、GNU Radio 是什么&#xff1f;二、GNU Radio 安装三、搭建第一个流程图1、创建 GRC 文件2、添加块3、运行流程图 前言 欢迎来到无线通信的世界&#xff0c;初步接触 GNU Radio&#xff0c;对其学习进行一个记录。 一、GNU Radio 是什么&#xff1f; GNU Rad…

el-tree获取当前选中节点及其所有父节点的id(包含半选中父节点的id)

如下图,我们现在全勾中的有表格管理及其下的子级,而半勾中的有工作台和任务管理及其子级 现在点击保存按钮后,需要将勾中的节点id及该节点对应的父节点,祖先节点的id(包含半选中父节点的id)也都一并传给后端,那这个例子里就应该共传入9个id,我们可以直接将getCheckedK…

SpringMVC 拦截器

文章目录 1、拦截器的配置2、拦截器的三个抽象方法3、多个拦截器的执行顺序总结 Spring MVC 拦截器是Spring框架中的一种机制&#xff0c;用于在请求到达处理器之前和渲染视图之前拦截请求&#xff0c;并允许开发者在这两个时间点进行自定义的处理逻辑。拦截器与过滤器&#xf…

openlayers [七] 地图控件controls详解

文章目录 controls 简述常见的 controls 控件使用方法fullscreen 全屏mouseposition 鼠标位置控件overviewmap 鹰眼图scaleline 比例尺控件zoomslider 缩放滑块刻度控件 总结 controls 简述 上篇文章我们将了在地图上的交互(interaction)&#xff0c;那些都是一些隐性的需要去…

css3轮播图案例

轮播图案例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>…

数据结构——二叉树的遍历与应用

目录 一.前言 二. 二叉树链式结构的实现 2.1 前置说明 2.2 二叉树的遍历 2.2.1 前序、中序以及后序遍历 前序遍历&#xff1a; 中序遍历递归图&#xff1a; 后序遍历&#xff1a; 2.3节点个数 2.4叶子节点个数 2.5第K层的节点个数 2.6 二叉树查找值为x的节点 2.7 …

【计算机网络】子网划分(经典基础练习题)

一、某主机IP地址为110.35.2.68&#xff0c;子网掩码为255.255.255.128&#xff0c;求网络地址&#xff1f; 二、有A类网络18.0.0.0的子网掩码为255.128.0.0&#xff0c;请问可以划分为多少个子网&#xff1f; 并写出每个子网的子网号&#xff1f; 三、将C类网119.181.25.0划分…

.NetCore Flurl.Http 4.0.0 以上管理客户端

参考原文地址&#xff1a;Managing Clients - Flurl 管理客户端 Flurl.Http 构建在堆栈之上System.Net.Http。如果您熟悉HttpClient&#xff0c;那么您可能听说过这个建议&#xff1a;不要为每个请求创建一个新客户端&#xff1b;重复使用它们&#xff0c;否则将面临后…

MySQL篇—性能压测工具mysqlslap介绍

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

Docker 安装 MongoDb4

Docker 安装mongoDb 获取mongodb安装参考 获取mongodb 注意&#xff1a; WARNING: MongoDB 5.0 requires a CPU with AVX support, and your current system does not appear to have that! **hub官网&#xff08;需要梯子&#xff09;&#xff1a;**https://hub.docker.com/_…

WAF攻防相关知识点总结1--信息收集中的WAF触发及解决方案

什么是WAF WAF可以通过对Web应用程序的流量进行过滤和监控&#xff0c;识别并阻止潜在的安全威胁。WAF可以检测Web应用程序中的各种攻击&#xff0c;例如SQL注入、跨站点脚本攻击&#xff08;XSS&#xff09;、跨站请求伪造&#xff08;CSRF&#xff09;等&#xff0c;并采取相…