Java操作Excel导入导出——POI、Hutool、EasyExcel
目录
一、POI导入导出
1.数据库导出为Excel文件
2.将Excel文件导入到数据库中
二、Hutool导入导出
1.数据库导出为Excel文件——属性名是列名
2.数据库导出为Excel文件——列名起别名
3.从Excel文件导入数据到数据库——属性名是列名
4.从Excel文件导入数据到数据库——列名改为属性名
三、EasyExcel
1.数据库导出数据到一个sheet中
2.数据库导出数据到多个sheet中
3.从Excel文件导入数据到数据库
4.读取大数据量Excel文件到数据库中
5.从页面上传Excel写入数据库
6.封装导出数据库到Excel工具类
一、POI导入导出
CREATE TABLE `test_student` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,`name` varchar(255) DEFAULT NULL,`age` int DEFAULT NULL
);
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version>
</dependency>
1.数据库导出为Excel文件
@Test
void f1() {// 数据库导出为Excel文件List<TestStudent> list = testStudentService.list();// 导出的位置String path = "D:\\save\\stu1.xlsx";// 工作薄 workbook(Excel本身)->sheet页签工作表 -> 行->单元格try (XSSFWorkbook workbook = new XSSFWorkbook()) {// 新建 工作薄对象// 新建sheet对象XSSFSheet sheet = workbook.createSheet("test_stu");//创建行XSSFRow row0 = sheet.createRow(0);// 创建单元格row0.createCell(0).setCellValue("学生ID");row0.createCell(1).setCellValue("学生姓名");row0.createCell(2).setCellValue("学生年龄");for (int i = 0; i < list.size(); i++) {// 略过首行XSSFRow row = sheet.createRow(i + 1);TestStudent testStudent = list.get(i);row.createCell(0).setCellValue(testStudent.getId());row.createCell(1).setCellValue(testStudent.getName());row.createCell(2).setCellValue(testStudent.getAge());}//内容写出去workbook.write(new FileOutputStream(path));} catch (IOException e) {throw new RuntimeException(e);}
}
2.将Excel文件导入到数据库中
@Test
void f2() throws IOException {// 将Excel文件导入到数据库中ArrayList<TestStudent> stuList = new ArrayList<>();// 导入的源文件String path = "D:\\save\\stu1.xlsx";// 工作薄对象Workbook workbook = WorkbookFactory.create(new FileInputStream(path));// 工作表 sheetSheet sheet = workbook.getSheetAt(0);// 行int rows = sheet.getPhysicalNumberOfRows();// 行的头信息,第一行,可以不处理for (int i = 1; i < rows; i++) {Row row = sheet.getRow(i);TestStudent student = new TestStudent();// 第一个单元格,因为是主键,可以不要// 第二个单元格student.setName(row.getCell(1).getStringCellValue());// 第三个单元格student.setAge((int) row.getCell(2).getNumericCellValue());// 把组装好的 student对象,存入集合stuList.add(student);// 不能循环调用数据库// testStudentService.save(student);}// 存数据到 数据库// 批量调用testStudentService.saveBatch(stuList);
}
二、Hutool导入导出
Hutool官网:https://hutool.cn/
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>
1.数据库导出为Excel文件——属性名是列名
@Test
void f1() {List<TestStudent> list = testStudentService.list();String path = "D:\\save\\stu2.xlsx";// 属性名就是Excel的列名ExcelWriter writer = ExcelUtil.getWriter(path);writer.write(list);writer.close();
}
2.数据库导出为Excel文件——列名起别名
@Test
void f2() {List<TestStudent> list = testStudentService.list();String path = "D:\\save\\stu3.xlsx";ExcelWriter writer = ExcelUtil.getWriter(path);writer.addHeaderAlias("id", "学生ID");writer.addHeaderAlias("name", "学生姓名");writer.addHeaderAlias("age", "学生年龄");writer.write(list);writer.close();
}
3.从Excel文件导入数据到数据库——属性名是列名
@Test
void f3() {String path = "D:\\save\\stu2.xlsx";ExcelReader reader = ExcelUtil.getReader(path);List<TestStudent> list = reader.readAll(TestStudent.class);testStudentService.saveBatch(list);
}
4.从Excel文件导入数据到数据库——列名改为属性名
@Test
void f4() {String path = "D:\\save\\stu3.xlsx";ExcelReader reader = ExcelUtil.getReader(path);// Excel列名信息与 属性不一致时,使用别名的方式读取reader.addHeaderAlias("学生ID", "id");reader.addHeaderAlias("学生姓名", "name");reader.addHeaderAlias("学生年龄", "age");List<TestStudent> list = reader.readAll(TestStudent.class);testStudentService.saveBatch(list);
}
三、EasyExcel
官网:https://easyexcel.opensource.alibaba.com/
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestStudent extends Model<TestStudent> {@TableId(type = IdType.AUTO)@ExcelProperty("学生ID")private Integer id;@ExcelProperty("学生姓名")private String name;@ExcelProperty("年龄")private Integer age;
}
1.数据库导出数据到一个sheet中
@Test
void f1() {// 数据库导出为Excel文件String path = "D:\\save\\stu4.xlsx";List<TestStudent> list = testStudentService.list();EasyExcel.write(path, TestStudent.class).sheet(0, "学生信息").doWrite(list);
}
2.数据库导出数据到多个sheet中
@Test
void f2() {// 数据库导出为Excel文件String path = "D:\\save\\stu5.xlsx";try (ExcelWriter excelWriter = EasyExcel.write(path, TestStudent.class).build()) {long count = testStudentService.count();long num = count % 100 == 0 ? count / 100 : count / 100 + 1;for (int i = 0; i < num; i++) {WriteSheet writeSheet = EasyExcel.writerSheet(i, "学生信息" + i).build();List<TestStudent> pageList = testStudentService.pageList(i + 1, 100);excelWriter.write(pageList, writeSheet);}} catch (Exception e) {throw new RuntimeException(e);}
}
3.从Excel文件导入数据到数据库
@Test
void f3() {String path = "D:\\save\\stu4.xlsx";EasyExcel.read(path,TestStudent.class,new PageReadListener<TestStudent>(list->{// 自带的分页读取,每次 只读取100条数据,防止数据量过大导致内存溢出testStudentService.saveBatch(list);})).sheet().doRead();
}
4.读取大数据量Excel文件到数据库中
@Test
void f4() {String path = "D:\\save\\stu10.xlsx";EasyExcel.read(path, TestStudent.class, new ReadListener<TestStudent>() {private static final int saveSize = 10000;private List<TestStudent> saveList = ListUtils.newArrayListWithCapacity(saveSize);// 每次读取一条,执行一次invoke方法@Overridepublic void invoke(TestStudent testStudent, AnalysisContext analysisContext) {saveList.add(testStudent);if (saveList.size() >= saveSize) {// 保存数据saveData();// 清空集合,重置集合saveList = ListUtils.newArrayListWithCapacity(saveSize);}}// 当所有的数据都读取完成时,会执行invoke方法,但是此时数据还未保存到数据库,所以需要执行doAfterAllAnalysed方法@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 执行完了所有的方法,还有一些没凑够saveSize的数据,所以需要执行saveData方法进行存储saveData();}private void saveData() {testStudentService.saveBatch(saveList);}}).sheet().doRead();
}
5.从页面上传Excel写入数据库
后端接口:
@RestController
@RequestMapping("/upload")
public class UploadController {@ResourceTestStudentService testStudentService;@PostMapping("/test1")public R upload1(MultipartFile file) throws IOException {// 该方法每次自动存100条数据到数据库EasyExcel.read(file.getInputStream(),TestStudent.class,new PageReadListener<TestStudent>(list -> {testStudentService.saveBatch(list);})).sheet().doRead();return R.ok("上传成功");}
}
前端页面:Student.vue
<template><div class="common-layout"><el-container><el-header><Top/></el-header><el-container><el-aside><Menu/></el-aside><el-main><el-row><el-col><el-upload ref="uploadRef" class="upload-demo"action="http://localhost:8081/upload/test1":auto-upload="false":with-credentials="true":on-success="ups"><template #trigger> <!--#trigger用于自定义触发上传、弹出对话框或其他交互操作的按钮或元素--><el-button type="primary">选择文件</el-button></template><el-button class="ml-4" type="success" @click="submitUpload">点击上传</el-button><template #tip> <!--#tip用于插入提示信息或其他额外内容--><div class="el-upload__tip"></div></template></el-upload></el-col></el-row><el-table :data="stuList" stripe style="width: 100%"><el-table-column prop="id" label="学生ID" width="180"/><el-table-column prop="name" label="学生姓名" width="180"/><el-table-column prop="age" label="学生年龄"/></el-table></el-main></el-container></el-container></div>
</template><script setup>
import {ref, reactive, onMounted} from "vue";
import axios from '@/plugins/axios.js'
import {ElMessage} from 'element-plus'
import LoginUser from "@/stores/LoginUser.js";
import router from "@/router/index.js";
import Top from "@/components/Top.vue";
import Menu from "@/components/Menu.vue";const uploadRef = ref([])
let submitUpload = () => {uploadRef.value.submit()
}
let ups = (response, file, fileList) => {console.log(response)if (response.code === 200) {ElMessage.success(response.msg)query()} else {ElMessage.error(response.msg)}
}
let stuList = ref([])
let query = () => {let param = {"pageNum": 1,"pageSize": 10}axios.get("/test/stu/page", param).then(result => {if (result.code === 200) {stuList.value = result.data}})
}
onMounted(() => {query()
})
</script><style scoped></style>
路由:
import {createRouter, createWebHistory} from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginView from '../views/LoginView.vue'
import TaskList from '../views/task/TaskList.vue'
import Student from '../views/test/Student.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',name: 'home',component: HomeView,}, {path: '/login',name: 'login',component: LoginView,}, {path: '/task/list',name: 'taskList',component: TaskList}, {path: '/test',name: 'test',children: [{path: 'student',name: 'student',component: Student,}]}],
})export default router
导出数据库到Excel后端接口:
@RestController
@RequestMapping("/export")
public class ExportController {@ResourceHttpServletResponse response;@Resourceprivate TestStudentService testStudentService;@GetMapping("/stu/excel")public void exportStuExcel() throws IOException {//获取 需要导出的信息List<TestStudent> list = testStudentService.list();// 设置导出的文件名// 这行代码将编码后的字符串中的所有 + 替换为 %20,这样可以确保文件名在下载时不会被错误地解释为空格。String fileName = URLEncoder.encode("学生信息表", "UTF-8").replaceAll("\\+", "%20");// 设置响应头信息// response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// response.setCharacterEncoding("utf-8");response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);// 使用 filename* 参数可以正确处理包含非 ASCII 字符的文件名。response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + fileName + ".xlsx");/* attachment:指示浏览器将文件作为附件下载。filename*=utf-8'':使用 filename* 参数来支持非 ASCII 字符,utf-8 表示编码格式,'' 表示语言标签(通常为空)。fileName + ".xlsx":拼接编码后的文件名和文件扩展名。*/// response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 这行代码使用 EasyExcel 将 list 中的数据写入 Excel 文件,并将其输出到 response.getOutputStream()。EasyExcel.write(response.getOutputStream(), TestStudent.class).sheet("数据1").doWrite(list);// 不需要手动关闭 response.getOutputStream(),EasyExcel 会自动处理。// response.getOutputStream().close();}
}
前端页面:
<el-col><a href="http://localhost:8081/export/stu/excel">导出全部数据</a>
</el-col>
6.封装导出数据库到Excel工具类
@Component
public class ExportUtil<T> {@ResourceHttpServletResponse response;public void expExcel(String fileName, List<T> list, Class<T> tClass){try {fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");// 设置响应头信息// response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");// response.setCharacterEncoding("utf-8");response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);// 使用 filename* 参数可以正确处理包含非 ASCII 字符的文件名。response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + fileName + ".xlsx");/* attachment:指示浏览器将文件作为附件下载。filename*=utf-8'':使用 filename* 参数来支持非 ASCII 字符,utf-8 表示编码格式,'' 表示语言标签(通常为空)。fileName + ".xlsx":拼接编码后的文件名和文件扩展名。*/// response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 这行代码使用 EasyExcel 将 list 中的数据写入 Excel 文件,并将其输出到 response.getOutputStream()。EasyExcel.write(response.getOutputStream(), tClass).sheet("数据1").doWrite(list);}catch (IOException e){throw new RuntimeException(e);}}
}
/*** 使用工具类导出数据库到Excel*/
@Resource
ExportUtil<TestStudent> exportUtil;
@GetMapping("/stu/excel2")
public void exportStuExcel2(){exportUtil.expExcel("学生信息表", testStudentService.list(), TestStudent.class);
}
相关文章:

Java操作Excel导入导出——POI、Hutool、EasyExcel
目录 一、POI导入导出 1.数据库导出为Excel文件 2.将Excel文件导入到数据库中 二、Hutool导入导出 1.数据库导出为Excel文件——属性名是列名 2.数据库导出为Excel文件——列名起别名 3.从Excel文件导入数据到数据库——属性名是列名 4.从Excel文件导入数据到数据库…...

BUUCTF_Web([GYCTF2020]Ezsqli)
1.输入1 ,正常回显。 2.输入1 ,报错false,为字符型注入,单引号闭合。 原因: https://mp.csdn.net/mp_blog/creation/editor/145170456 3.尝试查询字段,回显位置,数据库,都是这个。…...

微软宣布Win11 24H2进入新阶段!设备将自动下载更新
快科技1月19日消息,微软于1月16日更新了支持文档,宣布Windows 11 24H2进入新阶段。 24H2更新于2024年10月1日发布,此前为可选升级,如今微软开始在兼容的Windows 11设备上自动下载并安装24H2版本。 微软表示:“运行Wi…...

SpringBoot:解决前后端请求跨域问题(详细教程)
文章目录 一、前言二、解决方式 2.1 使用 CrossOrigin 注解(简单方便,适用于单个或少量接口)2.2 全局配置跨域(适用于整个项目中大量接口都需要跨域的情况)2.3 使用过滤器来处理跨域(更底层的实现方式&…...
Android-V lmkd 中的那些属性值
源码基于:Android V 相关博文: Android lmkd 机制详解(一) Android lmkd 机制详解(二) Android lmkd 机制从R到T 1. 汇总 属性名说明默认值 ro.lmk.debug 启动 lmkd 的debug 模式,会打印一…...

PageHelper快速使用
依赖 <!--分页插件PageHelper--> <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.7</version> </dependency>示例 /** * 封装分页结果…...

图像处理基础(3):均值滤波器及其变种
均值滤波器可以归为低通滤波器,是一种线性滤波器,其输出为邻域模板内的像素的简单平均值,主要用于图像的模糊和降噪。 均值滤波器的概念非常的直观,使用滤波器窗口内的像素的平均灰度值代替图像中的像素值,这样的结果就…...
力扣刷题心得_JAVA
数学 > 数组 > 链表 > 字符串 > 哈希表 > 双指针 > 递归 > 栈 > 队列 > 树 //一般力扣中传入的参数和新建的对象作为返回值,都不列入空间复杂度中 //但是面试的时候要和面试官商量好,灵活定义空间复杂度 //当然最好是就在传入的对象作为返回值,(在原…...

音乐播放器实现:前端HTML,CSS,JavaScript综合大项目
音乐播放器实现:前端HTML,CSS,JavaScript综合大项目 项目概述项目视图效果一、侧边栏相关代码(一)HTML代码(二)css代码 二、登录页面(一)HTML代码(二)css代码…...

Unity编辑器缩放设置
Unity默认界面UI字体太小了,可以设置一下缩放 打开首选项, UI Scaling 设置成125%或者更大 ,然后重启...

ChatGPT大模型极简应用开发-CH1-初识 GPT-4 和 ChatGPT
文章目录 1.1 LLM 概述1.1.1 语言模型和NLP基础1.1.2 Transformer及在LLM中的作用1.1.3 解密 GPT 模型的标记化和预测步骤 1.2 GPT 模型简史:从 GPT-1 到 GPT-41.2.1 GPT11.2.2 GPT21.2.3 GPT-31.2.4 从 GPT-3 到 InstructGPT1.2.5 GPT-3.5、Codex 和 ChatGPT1.2.6 …...
Golang学习笔记_27——单例模式
Golang学习笔记_24——泛型 Golang学习笔记_25——协程Golang学习笔记_25——协程 Golang学习笔记_26——通道 文章目录 单例模式1. 介绍2. 应用场景3. 实现3.1 饿汉式3.2 懒汉模式 源码 单例模式 1. 介绍 单例模式是一种创建型设计模式,它确保一个类只有一个实例…...

хорошо哈拉少wordpress俄语主题
хорошо哈拉少wordpress俄语主题 wordpress俄文网站模板,推荐做俄罗斯市场的外贸公司建俄语独立站使用。 演示 https://www.jianzhanpress.com/?p7360...

[数据结构与算法]js实现二叉树
DFS 与 BFS dfs 递归 本质通过栈结构 bfs 层序遍历 通过队列结构 function permute(nums) {let res [];let cur []; // 记录当前内容let visted {}; //记录访问过的节点let len nums.length;function dfs(nth) {//递归终止条件if (nth len) {res.push([...cur]);return …...
MySQL程序之:连接到服务器的命令选项
本节介绍大多数MySQL客户端程序支持的选项,这些选项控制客户端程序如何建立与服务器的连接、连接是否加密以及连接是否压缩。这些选项可以在命令行或选项文件中给出。 连接建立的命令选项 本节介绍控制客户端程序如何建立与服务器的连接的选项。 表6.4连接建立选…...

python3GUI--仿崩坏三二次元登录页面(附下载地址) By:PyQt5
文章目录 一.前言二.预览三.实现方案1.实现原理1.PyQt52. 具体实现 2.UI设计1.UI组件化、模块化2.UI设计风格思路 3.项目代码结构4.使用方法3.代码分享1.支持跳转网页的QLabel组件2.三角形ICON按钮 四.总结 大小:33.3 …...

阿里云 Serverless 助力盟主直播:高并发下的稳定性和成本优化
在直播场景中,阿里云 Serverless 应用引擎 SAE 提供的无缝弹性伸缩与极速部署能力,确保直播间高并发时的流畅体验,降低了我们的运营成本,简化了运维流程。结合阿里云云原生数据库 PolarDB 的 Serverless 能力,实现了数…...
Unity 学习指南与资料分享
Unity学习资料 Unity学习资料 Unity学习资料 Unity 作为一款强大的跨平台游戏开发引擎,在游戏开发及实时 3D 内容创作领域占据着重要地位。它功能丰富、易于上手,支持多平台发布,为开发者提供了广阔的创作空间。下面为你带来全面的 Unity 学…...
Android SystemUI——CarSystemBar视图解析(十一)
前面文章我们已经把 CarSystemBar 从启动到构建视图,再到将视图添加到 Window 的流程分析完毕,我们知道默认情况下在车载系统中只显示顶部栏和底部栏视图的。这里我们在前面文章的基础上以顶部栏为例具体解析其视图的结构。 一、顶部栏解析 通过《CarSystemBar车载状态栏》这…...

.NET周刊【1月第1期 2025-01-05】
国内文章 3款.NET开源、功能强大的通讯调试工具,效率提升利器! https://www.cnblogs.com/Can-daydayup/p/18631410 本文介绍了三款功能强大的.NET开源通讯调试工具,旨在提高调试效率。这些工具包括LLCOM,提供串口调试和自动化处…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...