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

EasyExcel 校验后导入

引入pom

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

触发校验类

import com.baomidou.mybatisplus.extension.api.R;
import lombok.experimental.UtilityClass;import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;@UtilityClass
public class MyValidatorUtils {public <T> R valid(Validator validator, T t){Set<ConstraintViolation<T>> violations = validator.validate(t);Iterator<ConstraintViolation<T>> iterator = violations.iterator();List<String> msgList = new ArrayList<>();while (iterator.hasNext()) {ConstraintViolation<T> cvl = iterator.next();msgList.add(cvl.getMessageTemplate());}if (msgList.isEmpty()) {return null;}else {return R.failed(String.join(",", msgList));}}
}

封装的easyexcel 导入

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.api.R;
import com.my.test.eo.listen.ErrMsgEO;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.springframework.web.multipart.MultipartFile;import java.util.List;@UtilityClass
public class MyExcelUtils {public R importData(MultipartFile file,Class clazz, MyReadListener readListener){return baseImportData(file,clazz,readListener,2);}@SneakyThrowsprivate R baseImportData(MultipartFile file,Class clazz, MyReadListener readListener,Integer headRowNumber){EasyExcel.read(file.getInputStream(), clazz, readListener).sheet().headRowNumber(headRowNumber).doRead();List<ErrMsgEO> errList = readListener.getErrList();return R.ok(errList);}
}

封装的监听器

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.extension.api.R;
import com.my.test.eo.listen.ErrMsgEO;
import lombok.extern.slf4j.Slf4j;import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;@Slf4j
public abstract class MyReadListener<T> implements ReadListener<T> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 5;/*** 缓存的数据*/private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 获取要提交的缓存数据*/public List<T> getCachedDataList() {return cachedDataList;}/*** 记录错误信息的list*/private List<ErrMsgEO> errList = new ArrayList<>();/*** 传入的校验对象*/private Validator validator;/*** 结束语,统计导入成功失败的条数*/private String resultMsg;public List<ErrMsgEO> getErrList() {return errList;}public void  addErr(ErrMsgEO errMsgEO){getErrList().add(errMsgEO);}public String getResultMsg() {return resultMsg;}private void setResultMsg(String resultMsg) {this.resultMsg = resultMsg;}private Validator getValidator() {return validator;}public void setValidator(Validator validator) {this.validator = validator;}/*** 数据对象加入批量提交缓存list*/public void addData(T data){cachedDataList.add(data);}/*** 校验一个数据对象,有错误就返回错误信息对象*/public ErrMsgEO validOne(T data, AnalysisContext context){R valid = MyValidatorUtils.valid(getValidator(), data);if (null!=valid) {ErrMsgEO eo= new ErrMsgEO();eo.setErr(valid.getMsg());eo.setRowNum(context.readRowHolder().getRowIndex().toString());return eo;}else {return null;}}/*** 保存业务逻辑 子类实现*/public abstract boolean saveData(AnalysisContext context);/*** 业务逻辑的校验*/public abstract ErrMsgEO bizValid(T data);/*** 判断最后的数据是否能保存*/public boolean lastCanSave(){return getCachedDataList().size() >0;}/*** 校验对象数据, 错误就加入错误信息list,正确就加入缓存数据池*/public void validThenAdd(T data, AnalysisContext context){ErrMsgEO valid = validOne(data, context);if (null!=valid) {addErr(valid);}else {ErrMsgEO eo = bizValid(data);if (null!=eo){addErr(eo);}else {addData(data);}}}/***达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM*/public void tryThenSave(AnalysisContext context){if (cachedDataList.size() >= BATCH_COUNT) {
//            批量保存if (saveData(context)) {// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}}/***  校验然后保存*/public void validThenSave(T data, AnalysisContext context) {validThenAdd(data, context);tryThenSave(context);}/*** 填充导入结果提示*/public void fillResultMsg(AnalysisContext context){int errNum=getErrList().size();int okNum=context.readSheetHolder().getApproximateTotalRowNumber()-errNum-context.readSheetHolder().getHeadRowNumber();setResultMsg("成功导入:"+okNum+"条数据,失败:"+errNum+"条数据");}public void lastSave(AnalysisContext context){if (lastCanSave()) {saveData(context);}else {log.info("木有保存");}fillResultMsg(context);}
}

调用的监听器

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener extends MyReadListener<XxxEO> {private IMyTestService myTestService;/*** 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来*/public DemoDataListener(IMyTestService service,Validator validator) {this.myTestService = service;super.setValidator(validator);}/*** 这个每一条数据解析都会来调用*/@Overridepublic void invoke(XxxEO data, AnalysisContext context) {log.info("解析到一条数据:{}行", context.readSheetHolder().getRowIndex()+1);super.validThenSave(data,context);}@Overridepublic ErrMsgEO bizValid(XxxEO data) {List<MyTest> list = myTestService.list();System.out.println(list);return null;}/*** 所有数据解析完成了 都会来调用*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {super.lastSave(context);log.info("所有数据解析完成!");}@Overridepublic boolean saveData(AnalysisContext context) {
//            log.info("{}条数据,开始存储数据库!", super.getCachedDataList().size());log.info("执行保存逻辑 {}" ,context.readSheetHolder().getRowIndex());return false;}
}

控制层调用的方法

    @Autowiredprivate Validator validator;@PostMapping("/importData")@ApiOperation("导入")public R importData(@RequestPart("file") MultipartFile file, @RequestParam("id") String id) throws Exception {if (id.length()>20) {return R.failed("长度过长");}if (!file.getOriginalFilename().contains(".xlsx")) {return R.failed("只能导入的xlsx文件");}DemoDataListener listener = new DemoDataListener(myTestService,validator);R r = MyExcelUtils.importData(file, XxxEO.class, listener);System.out.println(listener.getResultMsg());return r;}

相关文章:

EasyExcel 校验后导入

引入pom <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.3</version></dependency>触发校验类 import com.baomidou.mybatisplus.extension.api.R; import lombok.experimental…...

【星计划★C语言】c语言初相识:探索编程之路

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;星计划★C语言、Linux实践室 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️第一个c语言程序二. ⛳️数据类型2.1 &#x1f514;数据单位2.2 &…...

搜维尔科技:借助 ARVR 的力量缩小现代制造业的技能差距

借助ARVR的力量缩小现代制造业的技能差距 搜维尔科技&#xff1a;Senseglove案例-扩展机器人技术及其VR应用...

数据结构之栈和队列

1.前言 大家好久不见&#xff0c;这段时间由于忙去了。就没有即使维护我的博客&#xff0c;先给大家赔个不是。 我们还是规矩不乱&#xff0c;先赞后看~ 今天讲的内容是数据结构中非常重要的一个部分&#xff1a;栈和队列。它在今后的学习中也会再次出现&#xff08;c&#…...

centos安装使用elasticsearch

1.首先可以在 Elasticsearch 官网 Download Elasticsearch | Elastic 下载安装包 2. 在指定的位置(我的是/opt/zhong/)解压安装包 tar -zxvf elasticsearch-7.12.1-linux-x86_64.tar.gz 3.启动es-这种方式启动会将日志全部打印在当前页面&#xff0c;一旦使用 ctrlc退出就会导…...

4.7学习总结

java学习 一.Stream流 (一.)概念: Stream将要处理的元素集合看作一种流&#xff0c;在流的过程中&#xff0c;借助Stream API对流中的元素进行操作&#xff0c;比如&#xff1a;筛选、排序、聚合等。Stream流是对集合&#xff08;Collection&#xff09;对象功能的增强&…...

自定义gitlog格式

git log命令非常强大而好用&#xff0c;在复杂系统的版本管理中扮演着重要的角色&#xff0c;但默认的git log命令显示出的东西实在太丑&#xff0c;不好好打扮一下根本没法见人&#xff0c;打扮好了用alias命令拍个照片&#xff0c;就正式出道了&#xff01; 在使用git查看lo…...

Redission--分布式锁

Redission的锁的好处 Redission分布式锁的底层是setnx和lua脚本(保证原子性) 1.是可重入锁。 2.Redisson 锁支持自动续期功能&#xff0c;这可以帮助我们合理控制分布式锁的有效时长&#xff0c;当业务逻辑执行时间超出了锁的过期时间&#xff0c;锁会自动续期&#xff0c;避免…...

非关系型数据库(缓存数据库)redis的集群

目录 一.群集模式——Cluster 1.原理 2.作用 3.特点 4.工作机制 哈希槽 哈希槽的分配 哈希槽可按照集群主机数平均分配&#xff08;默认分配&#xff09; 根据主机的性能以及功能自定义分配 redis集群的分片 分片 如何找到给定key的分片 优势 二. 搭建Redis群集…...

MySQL:表的约束(上)

文章目录 空属性默认值列描述zerofill主键 本篇总结的是MySQL中关于表的约束部分的内容 空属性 在进行表的创建时&#xff0c;会有两个值&#xff0c;null和not null&#xff0c;而数据库默认的字段基本都是空&#xff0c;但是在实际的开发过程中要保证字段不能为空&#xff…...

树莓派5使用体验

原文地址&#xff1a;树莓派5使用体验 - Pleasure的博客 下面是正文内容&#xff1a; 前言 好久没有关于教程方面的博文了&#xff0c;由于最近打算入门嵌入式系统&#xff0c;所以就去购入了树莓派5开发板 树莓派5是2023年10月23日正式发售的&#xff0c;过去的时间不算太远吧…...

代码随想录算法训练营第42天| 背包问题、416. 分割等和子集

01 背包 题目描述&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 二维dp数组01背包&#xff1a; 确定dp数组以及下标的含义 …...

Node.js安装及环境配置指南

Node.js安装及环境配置指南 一、Node.js的安装 安装Node.js之前&#xff0c;首先需要确保你的电脑已经安装了合适的编译器和开发环境。Node.js是一个开源的、跨平台的JavaScript运行环境&#xff0c;它使得JavaScript可以在服务器端运行。 下载Node.js安装包 访问Node.js的…...

【Java基础】面试题汇总

Java基础面试题1. JVM vs JDK vs JRE 2. 什么是字节码?采用字节码的好处是什么?3. 为什么说 Java 语言“编译与解释并存”&#xff1f;4. AOT 有什么优点&#xff1f;为什么不全部使用 AOT 呢&#xff1f;5. Java 和 C 的区别&#xff1f;6. Java 中的基本数据类型&#xff1…...

数据库事务的超级详细讲解,包括事务特性、事务隔离级别、MVCC(多版本并发控制)

数据库事务&#xff1a; 主要有事务特性&#xff0c;事务的隔离级别&#xff0c;MVCC。 事务特性&#xff1a; 事务&#xff08;Transaction&#xff09;是指作为单个逻辑工作单元执行的一系列操作&#xff0c;这些操作要么全部成功执行&#xff0c;要么全部不执行&#xff…...

鸿蒙Lottie动画-实现控制动画的播放、暂停、倍速播放、播放顺序

介绍 本示例展示了lottie对动画的操作功能。引入Lottie模块&#xff0c;实现控制动画的播放、暂停、倍速播放、播放顺序、播放到指定帧停止或从指定帧开始播放、侦听事件等功能&#xff0c;动画资源路径必须是json格式。 效果预览 使用说明&#xff1a; 进入页面默认开始201…...

C++面试100问与自动驾驶100问

C的学习和面试其实是非常的不友好的&#xff0c;首先C的学习内容非常的多&#xff0c;其次C的面试不单单面试C的知识点&#xff0c;还有它的“七大姑八大姨”&#xff08;计算机网络、数据结构、算法、计算机组成原理、操作系统、编译、xxx的底层实现 and so on&#xff09;。 …...

加速 Redis 操作:掌握管道技术提升性能与效率

Redis 管道技术是一种用于优化 Redis 命令执行效率的机制。在传统的 Redis 操作中&#xff0c;每次向 Redis 服务器发送一个命令&#xff0c;都需要等待命令执行完成并返回结果&#xff0c;这样会导致频繁的网络通信和服务器端的命令执行开销&#xff0c;降低系统的性能和吞吐量…...

深入浅出 -- 系统架构之分布式系统底层的一致性

在分布式领域里&#xff0c;一致性成为了炙手可热的名词&#xff0c;缓存、数据库、消息中间件、文件系统、业务系统……&#xff0c;各类分布式场景中都有它的身影&#xff0c;因此&#xff0c;想要更好的理解分布式系统&#xff0c;必须要理解“一致性”这个概念。 其实关于…...

idea Springboot 电影推荐系统LayUI框架开发协同过滤算法web结构java编程计算机网页

一、源码特点 springboot 电影推荐系统是一套完善的完整信息系统&#xff0c;结合mvc框架和LayUI框架完成本系统springboot dao bean 采用协同过滤算法进行推荐 &#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&…...

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

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

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...