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为例,页表的…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
