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语言初相识:探索编程之路
🌈个人主页:聆风吟_ 🔥系列专栏:星计划★C语言、Linux实践室 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. ⛳️第一个c语言程序二. ⛳️数据类型2.1 🔔数据单位2.2 &…...
搜维尔科技:借助 ARVR 的力量缩小现代制造业的技能差距
借助ARVR的力量缩小现代制造业的技能差距 搜维尔科技:Senseglove案例-扩展机器人技术及其VR应用...
数据结构之栈和队列
1.前言 大家好久不见,这段时间由于忙去了。就没有即使维护我的博客,先给大家赔个不是。 我们还是规矩不乱,先赞后看~ 今天讲的内容是数据结构中非常重要的一个部分:栈和队列。它在今后的学习中也会再次出现(c&#…...
centos安装使用elasticsearch
1.首先可以在 Elasticsearch 官网 Download Elasticsearch | Elastic 下载安装包 2. 在指定的位置(我的是/opt/zhong/)解压安装包 tar -zxvf elasticsearch-7.12.1-linux-x86_64.tar.gz 3.启动es-这种方式启动会将日志全部打印在当前页面,一旦使用 ctrlc退出就会导…...
4.7学习总结
java学习 一.Stream流 (一.)概念: Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。Stream流是对集合(Collection)对象功能的增强&…...
自定义gitlog格式
git log命令非常强大而好用,在复杂系统的版本管理中扮演着重要的角色,但默认的git log命令显示出的东西实在太丑,不好好打扮一下根本没法见人,打扮好了用alias命令拍个照片,就正式出道了! 在使用git查看lo…...
Redission--分布式锁
Redission的锁的好处 Redission分布式锁的底层是setnx和lua脚本(保证原子性) 1.是可重入锁。 2.Redisson 锁支持自动续期功能,这可以帮助我们合理控制分布式锁的有效时长,当业务逻辑执行时间超出了锁的过期时间,锁会自动续期,避免…...
非关系型数据库(缓存数据库)redis的集群
目录 一.群集模式——Cluster 1.原理 2.作用 3.特点 4.工作机制 哈希槽 哈希槽的分配 哈希槽可按照集群主机数平均分配(默认分配) 根据主机的性能以及功能自定义分配 redis集群的分片 分片 如何找到给定key的分片 优势 二. 搭建Redis群集…...
MySQL:表的约束(上)
文章目录 空属性默认值列描述zerofill主键 本篇总结的是MySQL中关于表的约束部分的内容 空属性 在进行表的创建时,会有两个值,null和not null,而数据库默认的字段基本都是空,但是在实际的开发过程中要保证字段不能为空ÿ…...
树莓派5使用体验
原文地址:树莓派5使用体验 - Pleasure的博客 下面是正文内容: 前言 好久没有关于教程方面的博文了,由于最近打算入门嵌入式系统,所以就去购入了树莓派5开发板 树莓派5是2023年10月23日正式发售的,过去的时间不算太远吧…...
代码随想录算法训练营第42天| 背包问题、416. 分割等和子集
01 背包 题目描述:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 二维dp数组01背包: 确定dp数组以及下标的含义 …...
Node.js安装及环境配置指南
Node.js安装及环境配置指南 一、Node.js的安装 安装Node.js之前,首先需要确保你的电脑已经安装了合适的编译器和开发环境。Node.js是一个开源的、跨平台的JavaScript运行环境,它使得JavaScript可以在服务器端运行。 下载Node.js安装包 访问Node.js的…...
【Java基础】面试题汇总
Java基础面试题1. JVM vs JDK vs JRE 2. 什么是字节码?采用字节码的好处是什么?3. 为什么说 Java 语言“编译与解释并存”?4. AOT 有什么优点?为什么不全部使用 AOT 呢?5. Java 和 C 的区别?6. Java 中的基本数据类型࿱…...
数据库事务的超级详细讲解,包括事务特性、事务隔离级别、MVCC(多版本并发控制)
数据库事务: 主要有事务特性,事务的隔离级别,MVCC。 事务特性: 事务(Transaction)是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全部成功执行,要么全部不执行ÿ…...
鸿蒙Lottie动画-实现控制动画的播放、暂停、倍速播放、播放顺序
介绍 本示例展示了lottie对动画的操作功能。引入Lottie模块,实现控制动画的播放、暂停、倍速播放、播放顺序、播放到指定帧停止或从指定帧开始播放、侦听事件等功能,动画资源路径必须是json格式。 效果预览 使用说明: 进入页面默认开始201…...
C++面试100问与自动驾驶100问
C的学习和面试其实是非常的不友好的,首先C的学习内容非常的多,其次C的面试不单单面试C的知识点,还有它的“七大姑八大姨”(计算机网络、数据结构、算法、计算机组成原理、操作系统、编译、xxx的底层实现 and so on)。 …...
加速 Redis 操作:掌握管道技术提升性能与效率
Redis 管道技术是一种用于优化 Redis 命令执行效率的机制。在传统的 Redis 操作中,每次向 Redis 服务器发送一个命令,都需要等待命令执行完成并返回结果,这样会导致频繁的网络通信和服务器端的命令执行开销,降低系统的性能和吞吐量…...
深入浅出 -- 系统架构之分布式系统底层的一致性
在分布式领域里,一致性成为了炙手可热的名词,缓存、数据库、消息中间件、文件系统、业务系统……,各类分布式场景中都有它的身影,因此,想要更好的理解分布式系统,必须要理解“一致性”这个概念。 其实关于…...
idea Springboot 电影推荐系统LayUI框架开发协同过滤算法web结构java编程计算机网页
一、源码特点 springboot 电影推荐系统是一套完善的完整信息系统,结合mvc框架和LayUI框架完成本系统springboot dao bean 采用协同过滤算法进行推荐 ,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发)&…...
滑模控制消抖新思路:双曲正切函数VS饱和函数效果实测对比
滑模控制消抖技术深度对比:双曲正切函数与饱和函数的实战解析 在智能控制算法的演进历程中,滑模控制(SMC)因其强鲁棒性成为处理系统不确定性和外部干扰的利器。但传统符号函数带来的高频抖振问题,一直是工程师们亟待解…...
Keil5主题配色进阶:不只是好看,更要好用!详解如何区分函数、变量、宏定义的颜色
Keil5主题配色进阶:不只是好看,更要好用!详解如何区分函数、变量、宏定义的颜色 作为一名嵌入式开发者,每天面对Keil5的默认编辑器界面,你是否也感到视觉疲劳?那些单调的配色不仅影响编码心情,更…...
京东云GPU服务器省钱攻略:如何根据业务需求灵活选择计费模式和虚拟化方案
京东云GPU服务器成本优化实战指南:精准匹配业务需求的选型策略 在AI与高性能计算领域,GPU服务器已成为企业技术基础设施的核心组件。然而,面对复杂的计费模式、多样的硬件配置以及差异化的虚拟化方案,许多技术决策者常常陷入"…...
对话意图识别新选择:轻量ESFT模型高效易用
对话意图识别新选择:轻量ESFT模型高效易用 【免费下载链接】ESFT-token-intent-lite 基于HuggingFace平台,deepseek-ai团队推出的ESFT-token-intent-lite模型,是ESFT-vanilla-lite的精简版,专为意图识别优化,性能卓越&…...
告别网络依赖:用这个开源工具+高德离线包,5步搞定前端地图离线展示
前端开发者的离线地图解决方案:5步实现高德地图本地化部署 在紧急演示、内网开发或网络不稳定的环境中,依赖在线地图服务往往成为前端开发的痛点。我曾参与过一个政府内网项目,现场演示时因网络权限问题导致地图无法加载,最后不得…...
Realistic Vision V5.1开源镜像部署教程:Docker+Streamlit一体化环境搭建
Realistic Vision V5.1开源镜像部署教程:DockerStreamlit一体化环境搭建 1. 项目概述 Realistic Vision V5.1是目前SD 1.5生态中最顶级的写实风格模型之一,能够生成媲美专业单反相机拍摄的人像照片。本文将带你从零开始,通过Docker容器和St…...
终极PrimeVue Toast组件交互事件回调指南:从基础到高级应用
终极PrimeVue Toast组件交互事件回调指南:从基础到高级应用 【免费下载链接】primevue Next Generation Vue UI Component Library 项目地址: https://gitcode.com/GitHub_Trending/pr/primevue PrimeVue是一款功能强大的Vue UI组件库,其中Toast组…...
Simulink与Plecs联合仿真实现三相桥式电路能量双向流动
simulinkplecs联合仿真源件,三相桥式电路,采用母线电压外环与电流内环控制,可整流也可逆变并网,实现能量双向流动,采用SVPWM调制方式。 1.plecssimulink 2.SVPWM 3.双闭环 支持simulink2022以下版本,联系跟…...
梦行云软件——溯源系统-》企业方》产品溯源管理》员工管理
梦行云软件——溯源系统-》企业方》产品溯源管理》员工管理 湖南梦辰软件开发有限公司是立足怀化、服务全国的数字化技术服务商。公司拥有19项软件著作权及多项自主知识产权。专注于Web系统、APP与小程序定制开发,提供全链路数字化解决方案。以合规先行与稳定交付为…...
基于springboot的某学院勤工俭学岗位兼职平台设计与实现
目录 技术选型与架构设计核心功能模块划分数据库设计要点关键代码实现示例安全与权限控制测试与部署计划扩展性考虑 项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作 技术选型与架构设计 后端采用SpringBoot框架,集…...
