easyExcel 3.x以上版本导入数据后,再把错误信息导出,外加自定义RGB背景色、行高、宽度等
easyExcel 3.x以上版本导入数据后,再把错误信息导出,外加自定义RGB背景色
背景
由于项目中用的easypoi导入的数据量大了,会导致OOM的问题,所以要求更换为easyExcel框架做导入。话不多说,这里只做一个导入的示例,还有把遇到的一些问题列出来,大家根据业务需要随机应变。文章参考了其他大佬写的博客,这里把参考的大佬博客列出来:
官方文档:https://easyexcel.opensource.alibaba.com/docs/3.0.x
https://blog.csdn.net/qq_36978700/article/details/123425954
https://blog.csdn.net/qq_29834241/article/details/133786536
https://blog.csdn.net/wjs_007/article/details/135118539
https://www.cnblogs.com/mike-mei/p/17732227.html
引入依赖
//我的项目用的是gradle
implementation ('com.alibaba:easyexcel:3.0.5')
//maven
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.5</version>
</dependency>
//可能会用到alibaba的fastjson
implementation 'com.alibaba:fastjson:1.2.83'
Controller代码
@PostMapping("/import")public JSONResult importExcel(@RequestParam(name = "file") MultipartFile file, HttpServletResponse response) {try {//实现easyExcel的解析对象DemoDataListener demoDataListener = new DemoDataListener();//读取excel文件EasyExcel.read(file.getInputStream(), DemoData.class, demoDataListener).sheet().doRead();List<Map<String, Object>> failDataList = demoDataListener.getFailDataList();//导出错误数据export(dataList(failDataList), response);} catch (Exception e) {log.error("导入配置异常", e);}return JSONResult.ok("成功");}private void export(List<DemoData> dataList,HttpServletResponse response) {// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为红色headWriteCellStyle.setFillForegroundColor(IndexedColors.DARK_RED.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontName("宋体");headWriteFont.setFontHeightInPoints((short)11);headWriteFont.setBold(true);headWriteFont.setColor(IndexedColors.WHITE.getIndex());headWriteCellStyle.setBorderRight(BorderStyle.THIN);headWriteCellStyle.setRightBorderColor(IndexedColors.WHITE.getIndex());headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 设置细边框contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderTop(BorderStyle.THIN);// 设置边框颜色 25灰度contentWriteCellStyle.setBottomBorderColor(IndexedColors.GREEN.getIndex());contentWriteCellStyle.setTopBorderColor(IndexedColors.GREEN.getIndex());contentWriteCellStyle.setLeftBorderColor(IndexedColors.GREEN.getIndex());contentWriteCellStyle.setRightBorderColor(IndexedColors.GREEN.getIndex());WriteFont contentWriteFont = new WriteFont();contentWriteFont.setFontName("宋体");// 字体大小contentWriteFont.setFontHeightInPoints((short)12);contentWriteCellStyle.setWriteFont(contentWriteFont);// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);try (ServletOutputStream outputStream = response.getOutputStream()) {String fileName = "demo_error_data" + System.currentTimeMillis();response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf8");response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");response.setHeader("Pragma", "public");response.setHeader("Cache-Control", "no-store");response.addHeader("Cache-Control", "max-age=0");EasyExcel.write(outputStream, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).registerWriteHandler(new CustomRgbCellStyle(contentWriteCellStyle))//自定义行高,宽度.registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 21,(short) 19))//设置自动列宽.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).head(head()).sheet("Sheet").doWrite(dataList);} catch (IOException e) {throw new RuntimeException("导出excel表格失败!", e);}}/*** 自定义表头,如不需要自定义表头,直接在DemoData对象的注解@ExcelProperty配置即可*/private List<List<String>> head() {List<List<String>> list = new ArrayList<>();List<String> head0 = new ArrayList<>();head0.add("标题");List<String> head1 = new ArrayList<>();head1.add("创建时间");List<String> head2 = new ArrayList<>();head2.add("价格");List<String> head3 = new ArrayList<>();head3.add("名称");List<String> head4 = new ArrayList<>();head4.add("规格");List<String> head5 = new ArrayList<>();head5.add("失败原因");list.add(head0);list.add(head1);list.add(head2);list.add(head3);list.add(head4);list.add(head5);return list;}private List<DemoData> dataList(List<Map<String, Object>> failList) {List<DemoData> list = ListUtils.newArrayList();for (Map<String, Object> map : failList) {list.add((DemoData) map.get("data"));}log.info("Data ===========> {}", JSON.toJSONString(list));return list;}
实体类DemoData
@Data
public class DemoData {@ExcelProperty(index = 0)//index可不写,表示读取的列下标private String title;@ExcelProperty(index = 1)private String createTime;@ExcelProperty(index = 2)private BigDecimal price;@ExcelProperty(index = 3)private String pname;@ExcelProperty(index = 4)private String spec;@ExcelProperty(index = 5)private String failReason;
}
解析对象DemoDataListener
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;/*** 错误数据上限,达到上限则停止解析数据*/private static final int ERROR_COUNT = 100;/*** 缓存的数据*/private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 失败的数据*/private List<Map<String, Object>> failDataList = new ArrayList<>();private DemoDao dao;public DemoDataListener() {// TODO 实际使用过程中可通过构造参数把dao层的对象传进来,写入数据(下面注释的构造参数)}/**public DemoDataListener(DemoDao dao) {// TODO 实际使用过程中可通过构造参数把dao层的对象传进来,写入数据this.dao = dao;}*/public List<Map<String, Object>> getFailDataList() {return failDataList;}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {log.error("解析数据异常!", exception);
// if (failDataList.size() > 0) {
// exportErrorDataToExcel();
// }ReadListener.super.onException(exception, context);}@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {ReadListener.super.invokeHead(headMap, context);}/*** 这个每一条数据解析都会来调用** @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {//去除空行,有些空行有格式但没有数据,也会被读取if (lineNull(data)) {return;}log.info("解析到一条数据:{}", JSON.toJSONString(data));//TODO 这里做数据校验,失败的数据放到failDataList中if (StringUtils.isBlank(data.getPname())) {Map<String, Object> map = new HashMap<>(1);data.setFailReason("第"+context.readRowHolder().getRowIndex()+"行:商品名称不能为空");map.put("data", data);failDataList.add(map);}
// if (failDataList.size() > ERROR_COUNT) {
// throw new RuntimeException("错误数据过多,停止解析,请检查数据");
// }//校验数据完成后,添加到缓存中cachedDataList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}private boolean lineNull(Object line) {if (line instanceof String) {return StringUtils.isEmpty((String) line);}try {Set<Field> fields = Arrays.stream(line.getClass().getDeclaredFields()).filter(f -> f.isAnnotationPresent(ExcelProperty.class)).collect(Collectors.toSet());for (Field field : fields) {field.setAccessible(true);if (field.get(line) != null) {return false;}}return true;} catch (Exception ignored) {log.error(ignored.getMessage(), ignored);}return true;}@Overridepublic void extra(CellExtra extra, AnalysisContext context) {ReadListener.super.extra(extra, context);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {}@Overridepublic boolean hasNext(AnalysisContext context) {return ReadListener.super.hasNext(context);}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", cachedDataList.size());//TODO 这里执行存储数据库的代码逻辑
// demoDAO.save(cachedDataList);log.info("存储数据库成功!");}
}
自定义RGB样式CustomRgbCellStyle
@Slf4j
public class CustomRgbCellStyle extends AbstractCellStyleStrategy {private List<WriteCellStyle> contentWriteCellStyleList;public CustomRgbCellStyle(WriteCellStyle contentWriteCellStyle) {if (contentWriteCellStyle != null) {this.contentWriteCellStyleList = ListUtils.newArrayList(contentWriteCellStyle);}}@Overridepublic void setHeadCellStyle(CellWriteHandlerContext context) {Boolean head = context.getHead();// 设置标题头样式,这里的判断可不要if (head) {log.info("afterCellCreate ====> {}", head);// 获取和创建CellStyleWriteCellData<?> cellData = context.getFirstCellData();CellStyle originCellStyle = cellData.getOriginCellStyle();if (Objects.isNull(originCellStyle)) {originCellStyle = context.getWriteWorkbookHolder().getWorkbook().createCellStyle();}// 设置背景颜色((XSSFCellStyle) originCellStyle).setFillForegroundColor(new XSSFColor(new java.awt.Color(186, 12, 47), new DefaultIndexedColorMap()));originCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 重点!!! 由于在FillStyleCellWriteHandler,会把OriginCellStyle和WriteCellStyle合并,会已WriteCellStyle样式为主,所有必须把WriteCellStyle设置的背景色清空// 具体合并规则请看WriteWorkbookHolder.createCellStyle方法WriteCellStyle writeCellStyle = cellData.getWriteCellStyle();writeCellStyle.setFillForegroundColor(null);// 重点!!! 必须设置OriginCellStylecellData.setOriginCellStyle(originCellStyle);}}@Overridepublic void setContentCellStyle(CellWriteHandlerContext context) {if (stopProcessing(context) || CollectionUtils.isEmpty(contentWriteCellStyleList)) {return;}WriteCellData<?> cellData = context.getFirstCellData();if (context.getRelativeRowIndex() == null || context.getRelativeRowIndex() <= 0) {WriteCellStyle.merge(contentWriteCellStyleList.get(0), cellData.getOrCreateStyle());} else {WriteCellStyle.merge(contentWriteCellStyleList.get(context.getRelativeRowIndex() % contentWriteCellStyleList.size()),cellData.getOrCreateStyle());}}protected boolean stopProcessing(CellWriteHandlerContext context) {return context.getFirstCellData() == null;}
}
到此结束,如有疑问,欢迎留言!
相关文章:
easyExcel 3.x以上版本导入数据后,再把错误信息导出,外加自定义RGB背景色、行高、宽度等
easyExcel 3.x以上版本导入数据后,再把错误信息导出,外加自定义RGB背景色 背景 由于项目中用的easypoi导入的数据量大了,会导致OOM的问题,所以要求更换为easyExcel框架做导入。话不多说,这里只做一个导入的示例&…...
React的img图片路径怎么写
在React中,图片路径的写法取决于你的图片资源是如何被管理和存放的。这里有几种常见的情况和对应的写法: 1. 图片作为React组件的静态资源 如果你的图片文件放在React项目的public文件夹下(这是Create React App项目的默认结构)…...
UGUI优化篇--UGUI合批
UGUI合批 UGUI合批规则概述UGUI性能查看工具合批部分的特殊例子一个白色image、蓝色image覆盖了Text,白色image和Text哪个先渲染 Mask合批Mask为什么会产生两个drawcallMask为什么不能合批Mask注意要点 RectMask2D为什么RecMask2D比Mask性能更好主要代码RectMask2D注…...
FineBI连接MySQL5.7
一、在FineBI系统管理中,点击【新建数据库连接】 选择MySQL数据库 配置数据库连接,如下,其中数据库名称就是需要连接的目标数据库...
基于tkinter的学生信息管理系统之登录界面和主界面菜单设计
目录 一、tkinter的介绍 二、登陆界面的设计 1、登陆界面完整代码 2、部分代码讲解 3、登录的数据模型设计 4、效果展示 三、学生主界面菜单设计 1、学生主界面菜单设计完整代码 2、 部分代码讲解 3、效果展示 四、数据库的模型设计 欢迎大家进来学习和支持!…...
web基础以及http协议
⼀、web基本概念和常识 Web:为⽤户提供的⼀种在互联⽹上浏览信息的服务,Web 服 务是动态的、可交 互的、跨平台的和图形化的。 Web 服务为⽤户提供各种互联⽹服务,这些服务包括信息浏览 服务,以及各种交互式服务,包括…...
DataEase一键部署:轻松搭建数据可视化平台
DataEase是一个开源的数据可视化和分析工具,旨在帮助用户轻松创建和共享数据仪表盘。它支持多种数据源,包括关系型数据库,文件数据源,NoSQL数据库等,提供强大的数据查询、处理和可视化功能。DataEase 不仅是一款数据可…...
网络安全相关竞赛比赛
赛事日历(包含全国所有网络安全竞赛) https://datacon.qianxin.com/competition/competitions https://www.ichunqiu.com/competition/all 全国网络安全竞赛 名称链接全国大学生信息安全竞赛http://www.ciscn.cn/信息安全与对抗技术竞赛(In…...
Vscode——如何快速搜索项目工程中的某个文件的位置
第一步:按 shift ctrl p 第二步:然后把 > 删除 第三步:输入文件名称即可...
Kubernetes 正在弃用 Docker?Docker将何去何从?
一段时间以来,当人们想到容器时,似乎都会想到Docker和Kubernetes。在构建和运行容器方面,Docker 一直是大名鼎鼎的品牌,而在管理和编排容器方面,Kubernetes 一直是大名鼎鼎的品牌。听到 Kubernetes 从 1.20 版开始不再…...
编程语言「描述符」漫谈——以C++与Rust为例的行为声明与类型描述
编程语言中有三种描述符: 声明符: 表示一种动作, 比如创建变量, 定义函数等等;说明符: 也就是类型说明符, 表示一种数据类型;修饰符: 表示动作或类型的属性, 例如不可变…… swift语言就是严格遵循这些描述符的, 例如, objc是修饰符 , 表示编译成OC兼容函数, func 是声明符, …...
电脑屏幕录制软件哪个好?推荐3款,满足各种录制需求
大家好,今天和大家来聊一个既实用又有点神秘的话题——电脑屏幕录制软件哪个好?这是个让众多网友头疼的问题,毕竟谁不想拥有一款既好用又好玩的录制神器呢? 首先,我们得明确屏幕录制软件可不是简单地录屏而已…...
大模型学习应用 1:用 itrex 创新高效实现 LLM 的部署和微调
用 itrex 创新高效实现 LLM 的部署和微调 - 项目作业 目录 准备工作Task 1 完成在线环境的工具包安装,包含 基础环境包、Extension for Transformers 包、加速计算包Task 2 利用 Intel Extension for Transformers 部署通义千问 Qwen-7B Chat,并根据 pr…...
【Android】碎片—动态添加、创建Fragment生命周期、通信
简单用法 在一个活动中添加两个碎片,并让这两个碎片平分活动空间 先新建一个左侧碎片布局和一个右侧碎片布局 左侧碎片 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/…...
前端 SSE 长连接
使用 const options {withCredentials: true, // 默认 false}const eventSource new EventSource(/api, options);eventSource.addEventListener(open, () > {});eventSource.onmessage (event) > {}; // 或addEventListener(message,callback)eventSource.addEvent…...
.mp4格式的视频为何不能通过video标签在chrome浏览器中播放?
chrome浏览器目前只支持编解码格式为H264格式的视频,如果某个.mp4后缀的视频不能在chrome浏览器中播放,多半是这个视频的编码格式不是H264的! 1、可以通过ffmpeg工具查看当前视频的编码格式: ffprobe -v error -select_streams v…...
Python酷库之旅-第三方库Pandas(051)
目录 一、用法精讲 186、pandas.Series.is_monotonic_increasing属性 186-1、语法 186-2、参数 186-3、功能 186-4、返回值 186-5、说明 186-6、用法 186-6-1、数据准备 186-6-2、代码示例 186-6-3、结果输出 187、pandas.Series.is_monotonic_decreasing属性 187…...
linux timestamp
驱动或应用中获取时间戳的接口。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/time.h> #if 0 #include <linux/ktime.h> /* 内核驱动中获取时间戳 */ static ktime_t get_kernel_time…...
Vue.js 搭建大屏可视化项目
引言 在数字化转型的时代背景下,大屏可视化项目因其直观的数据展示和实时的业务监控能力而变得日益重要。Vue.js,以其简洁的语法、高效的虚拟DOM和强大的组件化能力,成为了构建大屏可视化应用的首选框架之一。本文将从零开始,引导…...
Linux:进程信号(二.信号的保存与处理、递达、volatile关键字、SIGCHLD信号)
上次介绍了:(Linux:进程信号(一.认识信号、信号的产生及深层理解、Term与Core))[https://blog.csdn.net/qq_74415153/article/details/140624810] 文章目录 1.信号保存1.1递达、未决、阻塞等概念1.2再次理解信号产生与保存1.3信号…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
