Java 读取excel文件
导入:
先导入依赖:
<!-- 文件上传 -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.7</version>
</dependency>
<!-- JSON -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.41</version>
</dependency>
<!-- POI -->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version>
</dependency>
1、获取想要上传excel文件的路径
2、获得路径后,通过路径定位生成数据流,使用FileInputStream方法读取路径对应文件的原始字节流。
//根据路径生成 FileInputStream字节流
FileInputStream inputStream = new FileInputStream(new File(fileName));
3、使用ExcelUtils工具类读取 字节流 + 路径。
//通过ExcelUtils工具将Excel数据存入到list中,工具代码下面细讲,这一步读取Excel已经完成了,如果不想进行插入数据库操作,可以直接拿着list用啦。
List<List<Object>> list = ExcelUtils.getListByExcel(inputStream,fileName);
4、ExcelUtils工具类对数据进行处理,因为表格有行和列,所以处理完数据使用二维集合List<List>对数据进行存储。
ExcelUtils类讲解:
public class ExcelUtils {private final static String excel2003L =".xls"; //2003- 版本的excelprivate final static String excel2007U =".xlsx"; //2007版本/*** @Description:获取IO流中的数据,组装成List<List<Object>>对象* @param in,fileName* @return* @throws*/public static List<List<Object>> getListByExcel(InputStream in, String fileName) throws Exception{List<List<Object>> list = null;//创建Excel工作薄Workbook work = getWorkbook(in,fileName);if(null == work){throw new Exception("创建Excel工作薄为空!");}Sheet sheet = null; //页数Row row = null; //行数Cell cell = null; //列数list = new ArrayList<List<Object>>();//遍历Excel中所有的sheetfor (int i = 0; i < work.getNumberOfSheets(); i++) {sheet = work.getSheetAt(i);if(sheet==null){continue;}//遍历当前sheet中的所有行for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {row = sheet.getRow(j);if(row==null){continue;}//遍历所有的列List<Object> li = new ArrayList<Object>();for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {cell = row.getCell(y);li.add(getValue(cell));}list.add(li);}}return list;}/*** @Description:根据文件后缀,自适应上传文件的版本* @param inStr,fileName* @return* @throws Exception*/public static Workbook getWorkbook(InputStream inStr,String fileName) throws Exception{Workbook wb = null;String fileType = fileName.substring(fileName.lastIndexOf("."));if(excel2003L.equals(fileType)){wb = new HSSFWorkbook(inStr); //2003-}else if(excel2007U.equals(fileType)){wb = new XSSFWorkbook(inStr); //2007+}else{throw new Exception("解析的文件格式有误!");}return wb;}/*** @Description:对表格中数值进行格式化* @param cell* @return*///解决excel类型问题,获得数值public static String getValue(Cell cell) {String value = "";if(null==cell){return value;}switch (cell.getCellType()) {//数值型case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {//如果是date类型则 ,获取该cell的date值Date date = DateUtil.getJavaDate(cell.getNumericCellValue());SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");value = format.format(date);;}else {// 纯数字BigDecimal big=new BigDecimal(cell.getNumericCellValue());value = big.toString();//解决1234.0 去掉后面的.0if(null!=value&&!"".equals(value.trim())){String[] item = value.split("[.]");if(1<item.length&&"0".equals(item[1])){value=item[0];}}}break;//字符串类型case STRING:value = cell.getStringCellValue();break;// 公式类型case FORMULA://读公式计算值value = String.valueOf(cell.getNumericCellValue());if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串value = cell.getStringCellValue();}break;// 布尔类型case BOOLEAN:value = " "+ cell.getBooleanCellValue();break;default:value = cell.getStringCellValue();}if("null".endsWith(value.trim())){value="";}return value;}
}
5、已经获取到了Excel表格中所有的数据,包含所有的行和列,都在List<List>中,这一步所有的数据获取完了
6、有了数据,要将数据存储到数据库。
7、需要创建数据库字段的实体类,使用@Excel注解将表格和数据库字段名一一对应
@Data
@TableName("t_student")//数据库名字
public class Student{@TableId(type = IdType.AUTO)@Excel(name = "序号", cellType = Excel.ColumnType.NUMERIC)private Long id;@Excel(name = "学生ID")private Long id;@Excel(name = "名称")private String name;@Excel(name = "性别")private String sex;@Excel(name = "年龄")private String age;}
8、通过双重 for循环遍历List<List>,内层List为列,外层List为行,如下图将第一行数据单独拿出来,作为判断字段,如果实体类等@Excel注解属性和Excel表格第一行名字相同,对实体类进行set赋值
//定义Excel第一行的属性
List<Object> firstRows = null;
//获取第一行属性 放入firstRows中。
if(list != null && list.size() > 0){firstRows = list.get(0);
}
//遍历除第一行以外的Excel表格中的值
for (int i = 1; i < list.size(); i++) {//rows是某一行,i = 1 为第二行, i = 2 为第三行List<Object> rows = list.get(i);//数据库数据的实体类Student student =new student();//遍历这一行所有的值for (int j = 0; j < rows.size(); j++){//某一行的某一列 j为列的坐标 String cellVal = (String) rows.get(j);//对实体类进行赋值,使用setFieldValueByFieldName方法,下面详细讲代码TestExcel.setFieldValueByFieldName(questionBank, firstRows.get(j).toString().trim(), cellVal);}}// 使用spring插入到数据库questionBankService.save(questionBank);}
9、从第二行开始,每遍历完一行,将获得一个实体类对象,因为是结合数据库写的实体类,通过springboot可以直接插入数据库。
public class TestExcel {/*** 用反射方法,获取列名,比较,为属性赋值* @param object* @param fieldName* @param val*/public static void setFieldValueByFieldName(Object object, String fieldName, Object val) {try {//通过反射获取所有实体类所有定义的方法,object为数据库实体类Field[] fields = object.getClass().getDeclaredFields();//遍历fieldsfor (int i = 0; i < fields.length; i++) {Field field = fields[i];//读取注释,如@Excel(name = "科目")Excel annotation = field.getAnnotation(Excel.class);//因为private类型,所有要设置允许field.setAccessible(true);//annotation.name() 注解里的属性,如果annotation没写注解,读取原始名字如subjectif(annotation == null){if(fieldName.equals(field.getName())){if(field.getType() == Integer.class){field.set(object, Integer.valueOf(val.toString()));}else if(field.getType() == Long.class){field.set(object, Long.valueOf(val.toString()));}else {field.set(object, val);}return;} }else {//设置了注解,并且表格里的Excel字段值和注解的name值相同,则为相应字段赋值if(fieldName.equals(annotation.name())){//进行类型判断,因为实体类中变量类型不同。if(field.getType() == Integer.class){field.set(object, Integer.valueOf(val.toString()));}else if(field.getType() == Long.class){field.set(object, Long.valueOf(val.toString()));}else {field.set(object, val);}return;}}}}catch (Exception e){e.printStackTrace();}}}
六、通用读取excel工具类
package com.ssm;import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;public class ReadExcel {public List<Map<String,String>> readExcel(String filepath, String filename, int startrow, int startcol, int sheetnum) {List<Map<String, String>> varList = new ArrayList<Map<String, String>>();String suffix = filename.substring(filename.lastIndexOf(".") + 1);if ("xls".equals(suffix)) {varList = readExcel2003(filepath, filename, startrow, startcol, sheetnum);} else if ("xlsx".equals(suffix)) {varList = readExcel2007(filepath, filename, startrow, startcol, sheetnum);} else {System.out.println("Only excel files with XLS or XLSX suffixes are allowed to be read!");return null;}return varList;}/*** 读取2003Excel* * @param filepath 文件路径* @param filename 文件名,包括扩展名* @param startrow 开始行号,索引从0开始* @param startcol 开始列号,索引从0开始* @param sheetnum 工作簿,索引从0开始* @return*/public static List<Map<String,String>> readExcel2003(String filepath, String filename, int startrow, int startcol, int sheetnum) {List<Map<String, String>> varList = new ArrayList<Map<String, String>>();try {File target = new File(filepath, filename);FileInputStream fis = new FileInputStream(target);HSSFWorkbook wb = new HSSFWorkbook(fis);fis.close();// sheet 从0开始HSSFSheet sheet = wb.getSheetAt(sheetnum);// 取得最后一行的行号int rowNum = sheet.getLastRowNum() + 1;HSSFRow rowTitle = sheet.getRow(0);// 标题行的最后一个单元格位置int cellTitleNum = rowTitle.getLastCellNum();String[] title = new String[cellTitleNum];for (int i = startcol; i < cellTitleNum; i++) {HSSFCell cell = rowTitle.getCell(Short.parseShort(i + ""));if (cell != null) {cell.setCellType(CellType.STRING);title[i] = cell.getStringCellValue();} else {title[i] = "";}}// 行循环开始for (int i = startrow + 1; i < rowNum; i++) {Map<String, String> varpd = new HashMap<String, String>();// 行HSSFRow row = sheet.getRow(i);// 列循环开始for (int j = startcol; j < cellTitleNum; j++) {HSSFCell cell = row.getCell(Short.parseShort(j + ""));String cellValue = "";if (cell != null) {// 把类型先设置为字符串类型cell.setCellType(CellType.STRING);cellValue = cell.getStringCellValue();}varpd.put(title[j], cellValue);}varList.add(varpd);}wb.close();} catch (Exception e) {System.out.println(e);}return varList;}/*** 读取2007Excel* * @param filepath 文件路径* @param filename 文件名,包括扩展名* @param startrow 开始行号,索引从0开始* @param startcol 开始列号,索引从0开始* @param sheetnum 工作簿,索引从0开始* @return*/public List<Map<String,String>> readExcel2007(String filepath, String filename, int startrow, int startcol, int sheetnum) {List<Map<String, String>> varList = new ArrayList<Map<String, String>>();try {File target = new File(filepath, filename);InputStream ins = new FileInputStream(target);XSSFWorkbook wb = new XSSFWorkbook(ins);ins.close();// 得到Excel工作表对象XSSFSheet sheet = wb.getSheetAt(sheetnum);// 取得最后一行的行号int rowNum = sheet.getLastRowNum() + 1;XSSFRow rowTitle = sheet.getRow(0);int cellTitleNum = rowTitle.getLastCellNum();String[] title = new String[cellTitleNum];for (int i = startcol; i < cellTitleNum; i++) {XSSFCell cell = rowTitle.getCell(Short.parseShort(i + ""));if (cell != null) {// 把类型先设置为字符串类型cell.setCellType(CellType.STRING);title[i] = cell.getStringCellValue();} else {title[i] = "";}}// 行循环开始for (int i = startrow + 1; i < rowNum; i++) {Map<String, String> varpd = new HashMap<String, String>();// 得到Excel工作表的行XSSFRow row = sheet.getRow(i);// 列循环开始for (int j = startcol; j < cellTitleNum; j++) {// 得到Excel工作表指定行的单元格XSSFCell cell = row.getCell(j);String cellValue = "";if (cell != null) {// 把类型先设置为字符串类型cell.setCellType(CellType.STRING);cellValue = cell.getStringCellValue();}varpd.put(title[j], cellValue);}varList.add(varpd);}wb.close();} catch (Exception e) {System.out.println(e);}return varList;}}
相关文章:
Java 读取excel文件
导入: 先导入依赖: <!-- 文件上传 --> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.7</version> </dependency> <!-- JSON -…...
PageRank(上):数据分析 | 数据挖掘 | 十大算法之一
⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…...
吃鸡达人专享!提高战斗力,分享干货,查询装备皮肤,保护账号安全!
大家好!作为专业吃鸡行家,我将为您带来一些热门话题和实用内容,帮助您提升游戏战斗力,分享顶级游戏作战干货,并提供便捷的作图工具和查询服务。让我们一起享受吃鸡的乐趣! 首先,我要推荐一款绝地…...
力扣第101题 c++ 递归 迭代 双方法 +注释 ~
题目 101. 对称二叉树 简单 给你一个二叉树的根节点 root , 检查它是否轴对称。 示例 1: 输入:root [1,2,2,3,4,4,3] 输出:true示例 2: 输入:root [1,2,2,null,3,null,3] 输出:false提示&a…...
Go:实现SMTP邮件发送订阅功能(包含163邮箱、163企业邮箱、谷歌gmail邮箱)
需求很简单,就是用户输入自己的邮箱后,使用官方邮箱给用户发送替邮件模版 目录 前置邮件模版邮箱开启SMTP服务163邮箱163企业邮箱谷歌gmail邮箱腾讯企业邮箱-失败其他邮箱-未操作 邮件发送核心代码config.yaml配置读取邮件相关配置发送邮件 附录 前置 邮…...
Scala第十六章节
Scala第十六章节 scala总目录 文档资料下载 章节目标 掌握泛型方法, 类, 特质的用法了解泛型上下界相关内容了解协变, 逆变, 非变的用法掌握列表去重排序案例 1. 泛型 泛型的意思是泛指某种具体的数据类型, 在Scala中, 泛型用[数据类型]表示. 在实际开发中, 泛型一般是结合…...
C语言 实现 链 显示 效果 查找 修改 删除
显示所有信息 2023年10月1日的描述:今天放假 2023年10月2日的描述:今天有体育 2023年10月3日的描述:今天有数学 2023年10月4日的描述:今天有语文 2023年10月5日的描述:今天有政治 2023年10月6日的描述:今天交学费 2023年10月7日的描述:今天周末 2023年10月8日的描述:今天给家里…...
CSS基础语法第一天
目录 一、CSS 简介 1.1 CSS简介 1.2 CSS语法 1.3 CSS 语法规范 1.4 CSS 代码风格 1.4.1 样式格式书写 1.4.2 样式大小写 1.4.3 空格规范 二、CSS 基础选择器 2.1选择器分类 2.2标签选择器 2.3 类选择器 2.4 id选择器 2.5 通配符选择器 三、盒子尺寸和背景色 …...
Leetcode 1492.n的第k个因子
给你两个正整数 n 和 k 。 如果正整数 i 满足 n % i 0 ,那么我们就说正整数 i 是整数 n 的因子。 考虑整数 n 的所有因子,将它们 升序排列 。请你返回第 k 个因子。如果 n 的因子数少于 k ,请你返回 -1 。 示例 1: 输入&#…...
十一工具箱流量主小程序源码
无授权,去过滤机制版本 看到网上发布的都是要授权的 朋友叫我把他去授权,能用就行 就把过滤去了 这样就不用授权 可以免费使用 白嫖党专属 一切接口可用,无需担心不能用 授权者不关站一直可以用 源码下载:https://download.csdn.…...
10.5汇编语言整理
【汇编语言相关语法】 1.汇编语言的组成部分 1.伪操作:不参与程序的执行,但是用于告诉编译器程序该怎么编译 .text .global .end .if .else .endif .data 2.汇编指令 编译器将一条汇编指令编译成一条机器码,在内存里一条指令占4字节内存&…...
Connect to 127.0.0.1:1080 [/127.0.0.1] failed: Connection refused: connect
报错信息 A problem occurred configuring root project CourseSelection. > Could not resolve all artifacts for configuration :classpath.> Could not resolve com.android.tools.build:gradle:3.6.1.Required by:project :> Could not resolve com.android.tool…...
驱动器类产品的接口EMC拓扑方案
驱动器类产品的接口EMC拓扑方案 1. 概述 本文以高压伺服驱动器和变频器类产品为例,对常用端口滤波拓扑方案进行总结,后续根据不同的应用场景可进行适当删减,希望对大家有帮助。 2. 驱动器验证等级 本文推荐拓扑的实验结果,满足…...
2023最新ICP备案查询系统源码 附教程 Thinkphp框架
2023最新ICP备案查询系统源码 附教程 thinkphp框架 本系统支持网址备案,小程序备案,APP备案查询,快应用备案查询 优势: 响应速度快,没有延迟,没有缓存,数据与官方同步 源码下载:ht…...
大数据Doris(六):编译 Doris遇到的问题
文章目录 编译 Doris遇到的问题 一、js_generator.cc:(.text+0xfc3c): undefined reference to `well_known_types_js’...
vue重修004上部
文章目录 版权声明组件的三大组成部分scoped解决样式冲突scoped原理2.代码演示 组件data函数说明演示 组件通信组件关系分类通信解决方案父子通信流程子向父通信代 props详解props校验props&data、单向数据流 小黑记事本(组件版)基础组件结构需求和实…...
【C++ techniques】要求/禁止/判断—对象产生于堆中
有时候我们想让某种对象具有“自杀”的能力,所以我们必须要求对象存在堆中,以便我们调用delete this;另一些时候,我们要求拥有某种确定性,保证某一些类型绝不会发生内存泄漏,原因是没有任何一个该类型的对象…...
吃鸡高手亲授:玩转绝地求生,分享顶级游戏干货!
绝地求生(PUBG)自上线以来,成为了全球热门游戏。作为吃鸡行家,我将分享一些独家技巧和干货,帮助您提高游戏战斗力,享受顶级游戏作战体验! 首先,让我们谈一谈战斗力升级。想要在吃鸡游…...
Vue中如何进行自定义图表与可视化图形设计
Vue中如何进行自定义图表与可视化图形设计 在现代Web应用程序开发中,数据可视化图表和图形设计是至关重要的一部分。Vue.js是一个流行的JavaScript框架,它提供了强大的工具来构建交互性强大的用户界面。本文将探讨如何在Vue.js中进行自定义图表和可视化…...
学信息系统项目管理师第4版系列19_质量管理
1. 公差 1.1. 质量测量中公差是测量指标的可允许变动范围,而不是实际测量值与预期值的差 1.1.1. 【高22下选35】 1.2. 结果的的可接受范围 2. 控制界限 2.1. 统计意义上稳定的过程或过程绩效的普通偏差的边界 3. 3版 3.1. 质量控制新七工具 3.1.1. 【高19下…...
10个免费Illustrator脚本:让你的设计效率提升300%的终极工具集
10个免费Illustrator脚本:让你的设计效率提升300%的终极工具集 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 如果你经常使用Adobe Illustrator进行设计工作࿰…...
从《EE Times》看电子工程师的变迁:技术浪潮与职业坚守
1. 从一份行业报纸的生日说起:我们为何怀念《EE Times》?前几天,我偶然翻到一篇旧文,是《EE Times》前主编史蒂夫韦茨纳在2013年,为这份报纸创刊40周年写的一篇回顾。文章不长,但字里行间那种对行业黄金时代…...
2026届学术党必备的六大AI论文工具推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 撰写AI毕业论文之时,需一直坚守学术伦理底线,严格禁止直接靠着生成式…...
AI系统提示词安全防护:从泄露风险到后端代理实战
1. 项目概述:当系统提示词不再“秘密”最近在AI应用开发圈里,一个名为“asgeirtj/system_prompts_leaks”的项目引起了我的注意。这名字直译过来就是“系统提示词泄露”,听起来就有点意思。简单来说,这个项目收集并展示了在各种AI…...
如何快速容器化100-Days-Of-ML-Code机器学习项目:终极Docker部署指南
如何快速容器化100-Days-Of-ML-Code机器学习项目:终极Docker部署指南 【免费下载链接】100-Days-Of-ML-Code 100 Days of ML Coding 项目地址: https://gitcode.com/gh_mirrors/10/100-Days-Of-ML-Code 100-Days-Of-ML-Code是一个完整的机器学习学习计划&…...
【Prometheus】当 Prometheus 内存使用率过高时,应该从哪些方面入手进行排查和优化?
Prometheus 内存溢出深度排查指南:从 TSDB Head 到 Goroutine 泄露的全链路优化 用户问题原文:“当 Prometheus 内存使用率过高时,应该从哪些方面入手进行排查和优化?” 在支撑单集群500万+时间序列的生产环境中,Prometheus 的内存管理是 SRE 团队的核心挑战。一次未被及时…...
终于蹲到了!“能读一半就是赚到”的《编码》精装版来了
前言:介绍一本好书 《编码》的第1版出版于1999年9月,从非常简单的概念开始讲解计算机工作的基础原理,帮助零基础的读者理解计算机的底层逻辑,建立计算机世界观。出版后立即收获全球范围内的广泛好评,成为影响几代程序员…...
从车窗升降到自动驾驶:用5个真实故事看懂汽车总线LIN、CAN、CAN-FD、FlexRay和以太网的进化史
从车窗升降到自动驾驶:用5个真实故事看懂汽车总线技术的进化史 清晨七点,当上班族按下车钥匙解锁按钮时,车门锁、后视镜展开、仪表盘亮起的动作几乎同步完成——这背后是汽车电子系统数十年的进化缩影。从最初控制车窗升降的简单信号传输&…...
Bun用Claude自己“换心手术“?AI重构软件的新纪元来了
五月中旬的编程界上演了一出荒诞又魔幻的戏码——Bun,这个曾以 Zig 语言为傲的 JavaScript 运行时,在短短六天时间里,由被它拖累的 Claude AI 亲手把自己从 Zig 重写成 Rust 语言。事情得从两年前说起。2024年,Bun 创始人 Jarred …...
RISC-V开源指令集架构:从设计哲学到商业落地的芯片设计新范式
1. 开源指令集架构的浪潮:从RISC-V研讨会看芯片设计新范式2015年6月底,加州大学伯克利分校的一场研讨会,意外地成为了半导体行业一个微小但意义深远的注脚。这场以RISC-V——一个源自伯克利的开源指令集架构——为主题的会议,不仅…...
