excel批量数据导入时用poi将数据转化成指定实体工具类

2024-03-11 15:20

本文主要是介绍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将数据转化成指定实体工具类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/798207

相关文章

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

sqlite3 命令行工具使用指南

《sqlite3命令行工具使用指南》本文系统介绍sqlite3CLI的启动、数据库操作、元数据查询、数据导入导出及输出格式化命令,涵盖文件管理、备份恢复、性能统计等实用功能,并说明命令分类、SQL语... 目录一、启动与退出二、数据库与文件操作三、元数据查询四、数据操作与导入导出五、查询输出格式化六、实用功

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

SpringBoot中4种数据水平分片策略

《SpringBoot中4种数据水平分片策略》数据水平分片作为一种水平扩展策略,通过将数据分散到多个物理节点上,有效解决了存储容量和性能瓶颈问题,下面小编就来和大家分享4种数据分片策略吧... 目录一、前言二、哈希分片2.1 原理2.2 SpringBoot实现2.3 优缺点分析2.4 适用场景三、范围分片