当前位置: 首页 > 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;&…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

STM32标准库-ADC数模转换器

文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”&#xff1a;输入模块&#xff08;GPIO、温度、V_REFINT&#xff09;1.4.2 信号 “调度站”&#xff1a;多路开关1.4.3 信号 “加工厂”&#xff1a;ADC 转换器&#xff08;规则组 注入…...