当前位置: 首页 > news >正文

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以上版本导入数据后&#xff0c;再把错误信息导出&#xff0c;外加自定义RGB背景色 背景 由于项目中用的easypoi导入的数据量大了&#xff0c;会导致OOM的问题&#xff0c;所以要求更换为easyExcel框架做导入。话不多说&#xff0c;这里只做一个导入的示例&…...

React的img图片路径怎么写

在React中&#xff0c;图片路径的写法取决于你的图片资源是如何被管理和存放的。这里有几种常见的情况和对应的写法&#xff1a; 1. 图片作为React组件的静态资源 如果你的图片文件放在React项目的public文件夹下&#xff08;这是Create React App项目的默认结构&#xff09;…...

UGUI优化篇--UGUI合批

UGUI合批 UGUI合批规则概述UGUI性能查看工具合批部分的特殊例子一个白色image、蓝色image覆盖了Text&#xff0c;白色image和Text哪个先渲染 Mask合批Mask为什么会产生两个drawcallMask为什么不能合批Mask注意要点 RectMask2D为什么RecMask2D比Mask性能更好主要代码RectMask2D注…...

FineBI连接MySQL5.7

一、在FineBI系统管理中&#xff0c;点击【新建数据库连接】 选择MySQL数据库 配置数据库连接&#xff0c;如下&#xff0c;其中数据库名称就是需要连接的目标数据库...

基于tkinter的学生信息管理系统之登录界面和主界面菜单设计

目录 一、tkinter的介绍 二、登陆界面的设计 1、登陆界面完整代码 2、部分代码讲解 3、登录的数据模型设计 4、效果展示 三、学生主界面菜单设计 1、学生主界面菜单设计完整代码 2、 部分代码讲解 3、效果展示 四、数据库的模型设计 欢迎大家进来学习和支持&#xff01…...

web基础以及http协议

⼀、web基本概念和常识 Web&#xff1a;为⽤户提供的⼀种在互联⽹上浏览信息的服务&#xff0c;Web 服 务是动态的、可交 互的、跨平台的和图形化的。 Web 服务为⽤户提供各种互联⽹服务&#xff0c;这些服务包括信息浏览 服务&#xff0c;以及各种交互式服务&#xff0c;包括…...

DataEase一键部署:轻松搭建数据可视化平台

DataEase是一个开源的数据可视化和分析工具&#xff0c;旨在帮助用户轻松创建和共享数据仪表盘。它支持多种数据源&#xff0c;包括关系型数据库&#xff0c;文件数据源&#xff0c;NoSQL数据库等&#xff0c;提供强大的数据查询、处理和可视化功能。DataEase 不仅是一款数据可…...

网络安全相关竞赛比赛

赛事日历&#xff08;包含全国所有网络安全竞赛&#xff09; https://datacon.qianxin.com/competition/competitions https://www.ichunqiu.com/competition/all 全国网络安全竞赛 名称链接全国大学生信息安全竞赛http://www.ciscn.cn/信息安全与对抗技术竞赛&#xff08;In…...

Vscode——如何快速搜索项目工程中的某个文件的位置

第一步&#xff1a;按 shift ctrl p 第二步&#xff1a;然后把 > 删除 第三步&#xff1a;输入文件名称即可...

Kubernetes 正在弃用 Docker?Docker将何去何从?

一段时间以来&#xff0c;当人们想到容器时&#xff0c;似乎都会想到Docker和Kubernetes。在构建和运行容器方面&#xff0c;Docker 一直是大名鼎鼎的品牌&#xff0c;而在管理和编排容器方面&#xff0c;Kubernetes 一直是大名鼎鼎的品牌。听到 Kubernetes 从 1.20 版开始不再…...

编程语言「描述符」漫谈——以C++与Rust为例的行为声明与类型描述

编程语言中有三种描述符: 声明符: 表示一种动作, 比如创建变量, 定义函数等等;说明符: 也就是类型说明符, 表示一种数据类型;修饰符: 表示动作或类型的属性, 例如不可变…… swift语言就是严格遵循这些描述符的, 例如, objc是修饰符 , 表示编译成OC兼容函数, func 是声明符, …...

电脑屏幕录制软件哪个好?推荐3款,满足各种录制需求

大家好&#xff0c;今天和大家来聊一个既实用又有点神秘的话题——电脑屏幕录制软件哪个好&#xff1f;这是个让众多网友头疼的问题&#xff0c;毕竟谁不想拥有一款既好用又好玩的录制神器呢&#xff1f; 首先&#xff0c;我们得明确屏幕录制软件可不是简单地录屏而已&#xf…...

大模型学习应用 1:用 itrex 创新高效实现 LLM 的部署和微调

用 itrex 创新高效实现 LLM 的部署和微调 - 项目作业 目录 准备工作Task 1 完成在线环境的工具包安装&#xff0c;包含 基础环境包、Extension for Transformers 包、加速计算包Task 2 利用 Intel Extension for Transformers 部署通义千问 Qwen-7B Chat&#xff0c;并根据 pr…...

【Android】碎片—动态添加、创建Fragment生命周期、通信

简单用法 在一个活动中添加两个碎片&#xff0c;并让这两个碎片平分活动空间 先新建一个左侧碎片布局和一个右侧碎片布局 左侧碎片 <?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格式的视频&#xff0c;如果某个.mp4后缀的视频不能在chrome浏览器中播放&#xff0c;多半是这个视频的编码格式不是H264的&#xff01; 1、可以通过ffmpeg工具查看当前视频的编码格式&#xff1a; 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 搭建大屏可视化项目

引言 在数字化转型的时代背景下&#xff0c;大屏可视化项目因其直观的数据展示和实时的业务监控能力而变得日益重要。Vue.js&#xff0c;以其简洁的语法、高效的虚拟DOM和强大的组件化能力&#xff0c;成为了构建大屏可视化应用的首选框架之一。本文将从零开始&#xff0c;引导…...

Linux:进程信号(二.信号的保存与处理、递达、volatile关键字、SIGCHLD信号)

上次介绍了&#xff1a;(Linux&#xff1a;进程信号&#xff08;一.认识信号、信号的产生及深层理解、Term与Core&#xff09;)[https://blog.csdn.net/qq_74415153/article/details/140624810] 文章目录 1.信号保存1.1递达、未决、阻塞等概念1.2再次理解信号产生与保存1.3信号…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...