excel批量数据导入时用poi将数据转化成指定实体工具类
1.实现目标
excel进行批量数据导入时,将批量数据转化成指定的实体集合用于数据操作,实现思路:使用注解将属性与表格中的标题进行同名绑定来赋值。
2.代码实现
2.1 目录截图如下
2.2 代码实现
package poi.constants;/*** @description: 用来定义一些通用的常量数据* @author: zengwenbo* @date: 2024/3/10 13:08*/
public class Constant {public final static String POINT = ".";public final static String SPACE = " ";
}
package poi.exception;/*** @description: 用于解析excel报错提供的异常* @author: zengwenbo* @date: 2024/3/10 12:47*/
public class ExcelException extends RuntimeException {public ExcelException() {super();}public ExcelException(String message) {super(message);}public ExcelException(String message, Throwable cause) {super(message, cause);}
}
package poi.annotation;import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.util.StringUtils;import java.lang.annotation.*;
import java.util.List;import static poi.constants.Constant.SPACE;/*** @description: 用于绑定excel和实体字段属性的注解* @author: zengwenbo* @date: 2024/3/10 12:51*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelDescription {String desc(); // excel描述的标题的内容DataType type() default DataType.String; // 指定当前title数据的数据类型enum DataType {String {@Overridepublic Object evaluateDataByType(Cell dataCell, List<List<java.lang.String>> validateList) {String cellValue = dataCell.getStringCellValue();if (StringUtils.hasLength(cellValue) && StringUtils.hasLength(cellValue.trim())) {// 判断当前值是否在序列中,在的话用SPACE进行划分取前面的值,不在的话原值返回return validateList.stream().filter(item -> item.contains(cellValue)).map(item -> cellValue.split(SPACE)[0]).findFirst().orElse(cellValue);}return cellValue;}}, Date {@Overridepublic Object evaluateDataByType(Cell dataCell, List<List<java.lang.String>> validateList) {double cellValue = dataCell.getNumericCellValue();return cellValue != 0 ? DateUtil.getJavaDate(cellValue) : null;}}, BigDecimal {@Overridepublic Object evaluateDataByType(Cell dataCell, List<List<java.lang.String>> validateList) {return java.math.BigDecimal.valueOf(dataCell.getNumericCellValue());}};/*** 根据数据类型来获取excel的数据值** @param dataCell excel单元格对象* @param validateList excel当前的序列数据有效性* @return*/public abstract Object evaluateDataByType(Cell dataCell, List<List<String>> validateList);}
}
package poi.utils;import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import poi.annotation.ExcelDescription;
import poi.exception.ExcelException;import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.OpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;import static poi.constants.Constant.POINT;/*** @description: 提供解析excel的工具类* @author: zengwenbo* @date: 2024/3/10 12:42*/
public class ExcelUtil {private final static String EXCEL_XLS = "xls";private final static String EXCEL_XLSX = "xlsx";/*** 将excel中table里面的数据转换成对应的实体** @param clazz 需要转化实体的类对象* @param titleRowNum table表格的标题行* @param sheetIndex sheet的下标* @return 返回转换后对象的list集合*/public static <T> List<T> transTableToEntity(MultipartFile file, Class<T> clazz, int titleRowNum, int sheetIndex) {// 1.获取文件的后缀String filename = file.getOriginalFilename();String suffix = filename.substring(filename.lastIndexOf(POINT) + 1);// 2.根据获取的后缀名获取操作excel的对象Workbook workbook;try (InputStream inputStream = file.getInputStream()) {switch (suffix) {case EXCEL_XLS:workbook = new HSSFWorkbook(inputStream);break;case EXCEL_XLSX:workbook = new XSSFWorkbook(inputStream);break;default:throw new ExcelException("后缀名不符");}} catch (IOException e) {throw new ExcelException("文件解析失败", e);}// 3.获取要操作的sheetSheet sheet = workbook.getSheetAt(sheetIndex);// 4.通过表格标题获取操作的开始列和结束列Row titleRow = sheet.getRow(titleRowNum);short firstCellNum = titleRow.getFirstCellNum();short lastCellNum = titleRow.getLastCellNum();// 5.获取表格中序列的数据有效性List<List<String>> validateList = new ArrayList<>();if (null != sheet.getDataValidations()) {sheet.getDataValidations().forEach(item -> {// 筛选出有效性数据时序列的进行添加if (null != item.getValidationConstraint().getExplicitListValues()) {validateList.add(Arrays.asList(item.getValidationConstraint().getExplicitListValues()));}});}// 6.遍历数据进行解析ArrayList<T> list = new ArrayList<>();Field[] fields = clazz.getDeclaredFields();for (int i = titleRowNum + 1; i < sheet.getLastRowNum(); i++) {Row row = sheet.getRow(i);try {// 获取实例对每个绑定的属性进行赋值T t = clazz.newInstance();for (int j = firstCellNum; j < lastCellNum; j++) {Cell titleCell = titleRow.getCell(j);if (null == titleCell) {throw new ExcelException("标题缺失,请检查导入模板是否正常");}String title = titleCell.getStringCellValue();if (!StringUtils.hasLength(title)) {throw new ExcelException("标题内容为空,请检查导入模板是否正常");}Optional.ofNullable(row.getCell(j)).ifPresent(value -> evaluateField(t, fields, value, title, validateList));}list.add(t);} catch (InstantiationException e) {throw new ExcelException("创建实例异常,该类缺失无参构造方法");} catch (IllegalAccessException e) {throw new ExcelException("创建实例异常,权限不足");}}return list;}/*** 通过单元格的值给对象的属性进行赋值** @param t 对象实体* @param fields 对象对应的属性数组* @param dataCell 单元格对象* @param title 单元格对象对应的title* @param validateList 数据有效性列表*/private static <T> void evaluateField(T t, Field[] fields, Cell dataCell,String title, List<List<String>> validateList) {for (Field field : fields) {// 处理属性上有ExcelDescription注解的数据进行赋值if (field.isAnnotationPresent(ExcelDescription.class)) {ExcelDescription annotation = field.getAnnotation(ExcelDescription.class);// 获取注解的描述String desc = annotation.desc();// 获取注解的数据类型ExcelDescription.DataType type = annotation.type();// 如果title和描述desc一致,则将cell里面的值赋值给该属性if (title.equals(desc)) {// 获取value的值Object value = type.evaluateDataByType(dataCell, validateList);field.setAccessible(true);try {field.set(t, value);} catch (IllegalAccessException e) {throw new ExcelException("对象属性赋值权限异常");}}}}}
}
3.测试数据
测试实体
package poi.bean;import lombok.Data;
import poi.annotation.ExcelDescription;import java.math.BigDecimal;
import java.util.Date;/*** @description:* @author: zengwenbo* @date: 2024/3/10 14:07*/
@Data
public class Person {@ExcelDescription(desc = "名称")private String name;@ExcelDescription(desc = "年龄", type = ExcelDescription.DataType.BigDecimal)private BigDecimal age;@ExcelDescription(desc = "生日", type = ExcelDescription.DataType.Date)private Date birth;@ExcelDescription(desc = "国籍")private String country;
}
测试的excel文件数据截图
对国籍数据进行了有效性填充
测试代码:将excel文件放在resource目录下
package com.example.demo;import com.example.demo.redis.User;import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import poi.bean.Person;
import poi.utils.ExcelUtil;import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
class DemoApplicationTests {@Autowiredprivate ResourceLoader resourceLoader;@Testvoid TestExcel() throws Exception {Resource resource = resourceLoader.getResource("classpath:test.xls" );String fileName = resource.getFilename();byte[] fileBytes = Files.readAllBytes(resource.getFile().toPath());MultipartFile multipartFile = new MockMultipartFile(fileName, fileName, "text/plain", fileBytes);List<Person> list = ExcelUtil.transTableToEntity(multipartFile, Person.class, 0, 0);}}
最终结果
相关文章:

excel批量数据导入时用poi将数据转化成指定实体工具类
1.实现目标 excel进行批量数据导入时,将批量数据转化成指定的实体集合用于数据操作,实现思路:使用注解将属性与表格中的标题进行同名绑定来赋值。 2.代码实现 2.1 目录截图如下 2.2 代码实现 package poi.constants;/*** description: 用…...

【软件工程导论】——软工学绪论及传统软件工程(学习笔记)
📖 前言:随着软件产业的发展,计算机应用逐步渗透到社会生活的各个角落,使各行各业都发生了很大的变化。这同时也促使人们对软件的品种、数量、功能和质量等提出了越来越高的要求。然而,软件的规模越大、越复杂…...

C语言编译成库文件的要求
keil编译成库文件 在Keil中,将C语言源文件编译成库文件通常需要进行以下步骤: 创建一个新的Keil项目,并将所需的C语言源文件添加到该项目中。 在项目设置中配置编译选项,确保生成的目标文件符合库文件的标准格式。 编译项目&…...
Python的模块应用和文件I/O
Python 解释 Python是一种高级编程语言,以其简洁、易读和易用而闻名。它是一种通用的、解释型的编程语言,适用于广泛的应用领域,包括软件开发、数据分析、人工智能等。python是一种解释型,面向对象、动态数据类型的高级程序设计…...
设计模式之依赖倒转原则
目录 1、 基本介绍 2、 应用实例 3、 依赖关系传递的三种方式 (1) 接口传递 (2) 构造方法传递 (3) setter方式传递 4、 注意事项和细节 1、 基本介绍 依赖倒转原则(Dependence Inversion Principle)是指: 高层模块不应该依赖低层模块,二者都应该依…...
Springboot启动后想要做某些事可以通过什么方法实现?
在Spring Boot应用中,如果你想在应用启动完成后执行一些特定的操作(例如缓存预热),可以实现CommandLineRunner或ApplicationRunner接口。这两个接口都提供了一个run方法,在Spring Boot应用上下文初始化完成后会被自动调…...

网络原理初识(2)
目录 一、协议分层 1、分层的作用 2、OSI七层模型 3、TCP / IP五层(或四层)模型 4、网络设备所在分层 5、网络分层对应 二、封装和分用 发送过程(封装) 1、应用层(应用程序) QQ 2、传输层 3、网络层 4、数据链路层 5、物理…...
【C++】每日一题 92 反转链表
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left < right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。 class ListNode { public:int val;ListNode* next;ListNode(int _val) {val _val;next nullptr;} };…...
算法D39 | 动态规划2 | 62.不同路径 63. 不同路径 II
今天开始逐渐有 dp的感觉了,题目不多,就两个 不同路径,可以好好研究一下 62.不同路径 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流,很难想到。 代码随想录 视频讲解:动态规划中如何初始化很重要&#x…...
面试官:如何在 Spring Boot 启动的时候提前运行一些特定的代码
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:如何在 Spring Boot 启动的时候提前运行一些特定的代码 在Spring Boot启动的时候提前运行一些特定的代码可以通过实现ApplicationRunner接口、Com…...

力扣最热100题——56.合并区间
吾日三省吾身 还记得梦想吗 正在努力实现它吗 可以坚持下去吗 目录 吾日三省吾身 力扣题号:56. 合并区间 - 力扣(LeetCode) 题目描述 Java解法一:排序然后原地操作 具体代码如下 Java解法二:new一个list…...

docker学习(十四)docker搭建私服
docker私服搭建,配置域名访问,设置访问密码 启动registry docker run -d \-p 5000:5000 \-v /opt/data/registry:/var/lib/registry \registrydocker pull hello-world docker tag hello-world 127.0.0.1:5000/hello-world docker push 127.0.0.1:5000…...
基于BERTopic模型的英文20新闻数据集主题聚类及可视化
文章目录 bertopic介绍20 newsgroups dataset20 newsgroups数据集下载数据导入nltk数据处理bertopic模型构建模型训练运行模型可视化目前主题的一致性得分语料库建模bertopic介绍 BERTopic 是基于深度学习的一种主题建模方法。BERT 是一种用于 NLP 的预训练策略,它成功地利用…...

【Oracle之DataGuard的初步学习】
** 以下所有均是基于11G版本的 ** 一、DataGuard的部署方式 DG的部署最常用的方式就是直接在备库端部署一个空库然后再设置参数,但是这样做在初始同步时如果数据量过大会耗费较长的时间;相对来说这中方式比较简单不易出错。 还有一种方式就是通过rman的备…...

PyCharm无代码提示解决
PyCharm无代码提示解决方法 在使用PyCharm工具时,调用方法却无法进行提示,针对PyCharm无代码提示整理下解决方案 1、Python内置语法无智能提示 复现:我这里以urllib库读取网页内容为例,在通过urlopen()之后调用getur…...

记一次 .NET某设备监控自动化系统 CPU爆高分析
一:背景 1. 讲故事 先说一下题外话,一个监控别人系统运行状态的程序,结果自己出问题了,有时候想一想还是挺讽刺的,哈哈,开个玩笑,我们回到正题,前些天有位朋友找到我,说…...

大数据与云计算
目录 一、大数据时代二、云计算——大数据的计算三、云计算发展现状四、云计算实现机制五、云计算压倒性的成本优势 一、大数据时代 我们先来看看百度关于 “大数据”(Big Data)的搜索指数。 可以看出,“大数据” 这个词是从2012年才引起关注…...

一. 并行处理与GPU体系架构-并行处理简介
目录 前言0. 简述1. 串行处理与并行处理的区别2. 并行执行3. 容易混淆的几个概念4. 常见的并行处理总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习下课程第一章——并行处…...

vb机试考试成绩分析与统计,设计与实现(高数概率统计)-141-(代码+程序说明)
转载地址http://www.3q2008.com/soft/search.asp?keyword141 前言: 为何口出狂言,作任何VB和ASP的系统, 这个就是很好的一个证明 :) 又有些狂了... 数据库操作谁都会,接触的多了也没什么难的,VB编程难在哪?算法上,这个是一个算法题的毕业设计,里面涉及到对试卷的 平均分,最…...

Arm MMU深度解读
文章目录 一、MMU概念介绍二、虚拟地址空间和物理地址空间2.1、(虚拟/物理)地址空间的范围2.2、物理地址空间有效位(范围) 三、Translation regimes四、地址翻译/几级页表?4.1、思考:页表到底有几级?4.2、以4KB granule为例,页表的…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...