POI导入导出、EasyExcel批量导入和分页导出
文件导入导出POI、EasyExcel
POI:消耗内存非常大,在线上发生过堆内存溢出OOM;在导出大数据量的记录的时候也会造成堆溢出甚至宕机,如果导入导出数据量小的话还是考虑的,下面简单介绍POI怎么使用
POI导入
首先拿到文件对象,这个对象可以是前端上传的或者从目录读取的,或者OOS里面下载的。
下面是关于POI导入的核心代码,非常的简单。
// 把文件转为Workbook 对象,这样就能任意操作它了
Workbook workbook = new XSSFWorkbook(file.getInputStream());
// 获取第0页的数据
Sheet sheet = workbook.getSheetAt(0);
// 获取第一行
int firstRowNum = sheet.getFirstRowNum();
// 获取最后一行
int lastRowNum = sheet.getLastRowNum();
// 获取第一行数据-即表头
// 如果需要用到表头的话,可以调用Row对象里面的getCell取值
Row head = sheet.getRow(firstRowNum);
// 获取第一列
short firstCellNum = head.getFirstCellNum();
// 获取最后一列
short lastCellNum = head.getLastCellNum();
// 遍历所有数据行-跳过表头for (int rowIndex = firstRowNum + 1; rowIndex <= lastRowNum; rowIndex++){// 获取数据行Row dataRow = sheet.getRow(rowIndex);// 接下来遍历这一行的数据for (int cellIndex = firstCellNum; cellIndex < lastCellNum; cellIndex++) {// 获取单元格Cell cell = dataRow.getCell(cellIndex);// 把单元格数据转为StringSystem.out.println(cell.toString());}}
POI导出
导出功能的话一般会从数据库查出来数据,导入到Excel表中
下面是关于POI导出的核心代码,非常的简单。
// 创建工作簿Workbook wb = new XSSFWorkbook();// 创建页Sheet sheet = wb.createSheet("Sheet1");// 创建表头Row tableHeadRow = sheet.createRow(0);// 下面就是对表头与行添加数据了// 创建表头的单元格int headIndex = 0;// 这个列数自己控制-可以通过对象的字段数控制,通过反射机制获取对象信息for (int i = 0; i < 10; i++) {// 创建单元格Cell cell = tableHeadRow.createCell(headIndex++); // 设置值-这里的值是自己对象的值cell.setCellValue("表头列"+i);}// 现在表头设置好了,接下来设置数据行// 这里从第一行开始,第0行是表头for (int i = 1; i < 20; i++) {Row dataRow= sheet.createRow(i);// 为数据行填充数据,这里的列数和表头的列数一致就行for (int i = 0; i < 10; i++) {// 创建单元格Cell cell = dataRow.createCell(index ++); // 设置值-这里的值是自己对象的值cell.setCellValue("数据行的数据"+i);}}
EasyExcel导入
EasyExcel是阿里巴巴开源的框架,它是对POI进行了封装,解决了POI耗内存的痛点。
使用EasyExcel步骤比较多,但是却能帮助我们更加灵活的开发。
1、实体类上加注解@ExcelProperty(“日期”),日期是表头名
@ExcelProperty("日期")private String prodDate;
2、EasyExcel的监听器,实现ReadListener接口,这里的泛型为实体类
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
public class ImportWRPListenner implements ReadListener<WorkRollPlan> {private List<WorkRollPlan> list = new ArrayList<>();/*** 每读一行触发一次*** @param workRollPlan* @param analysisContext*/@Overridepublic void invoke(WorkRollPlan workRollPlan, AnalysisContext analysisContext) {// 每次触发把workRollPlan放进列表list.add(workRollPlan);}/*** 所有数据读完之后触发一次*** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}
}
3、使用
public String uploadExcel(MultipartFile[] files) throws IOException {ImportWRPListenner importWRPListenner = new ImportWRPListenner();for (int i = 0; i < files.length; i++) {MultipartFile file = files[i];InputStream inputStream = file.getInputStream();EasyExcel.read(inputStream, WorkRollPlan.class, importWRPListenner).sheet(0) // 读第0页.headRowNumber(1) // 表头占1几行.doRead();}return "ok";}
4、如何入库
在doAfterAllAnalysed方法里把list 入库,入库需要有Service对象,而Listenner是不被Spring管理的,所以说不能通过注入的方式获取Service。
方法一:通过容器获取对象,下面是获取Spring容器的工具类。
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;/*** spring工具类 方便在非spring管理环境中获取bean* * @author ruoyi*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
{/** Spring应用上下文环境 */private static ConfigurableListableBeanFactory beanFactory;private static ApplicationContext applicationContext;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {SpringUtils.beanFactory = beanFactory;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtils.applicationContext = applicationContext;}/*** 获取对象** @param name* @return Object 一个以所给名字注册的bean的实例* @throws BeansException**/@SuppressWarnings("unchecked")public static <T> T getBean(String name) throws BeansException{return (T) beanFactory.getBean(name);}/*** 获取类型为requiredType的对象** @param clz* @return* @throws BeansException**/public static <T> T getBean(Class<T> clz) throws BeansException{T result = (T) beanFactory.getBean(clz);return result;}/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @param name* @return boolean*/public static boolean containsBean(String name){return beanFactory.containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @param name* @return boolean* @throws NoSuchBeanDefinitionException**/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException{return beanFactory.isSingleton(name);}/*** @param name* @return Class 注册对象的类型* @throws NoSuchBeanDefinitionException**/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException{return beanFactory.getType(name);}/*** 如果给定的bean名字在bean定义中有别名,则返回这些别名** @param name* @return* @throws NoSuchBeanDefinitionException**/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException{return beanFactory.getAliases(name);}/*** 获取aop代理对象* * @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker){return (T) AopContext.currentProxy();}/*** 获取当前的环境配置,无配置返回null** @return 当前的环境配置*/public static String[] getActiveProfiles(){return applicationContext.getEnvironment().getActiveProfiles();}/*** 获取当前的环境配置,当有多个环境配置时,只获取第一个** @return 当前的环境配置*/public static String getActiveProfile(){final String[] activeProfiles = getActiveProfiles();return "StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null";}/*** 获取配置文件中的值** @param key 配置文件的key* @return 当前的配置文件的值**/public static String getRequiredProperty(String key){return applicationContext.getEnvironment().getRequiredProperty(key);}
}
通过Spring获取Service
private WorkRollPlanService workRollPlanService = SpringUtils.getBean(WorkRollPlanService.class);
方法2:构建监听器的时候把Service传进来
private WorkRollPlanService workRollPlanService;public ImportWRPListenner(WorkRollPlanService workRollPlanService) {this.workRollPlanService = workRollPlanService;}
在Service里面使用
ImportWRPListenner importWRPListenner = new ImportWRPListenner(this);
拿到Service之后在监听器的doAfterAllAnalysed方法入库就OK了。
5、如何导入指定条数就插入数据库。
public class ImportWRPListenner implements ReadListener<WorkRollPlan> {// 计数器public static int count = 0;private WorkRollPlanService workRollPlanService;public ImportWRPListenner(WorkRollPlanService workRollPlanService) {this.workRollPlanService = workRollPlanService;}private List<WorkRollPlan> list = new ArrayList<>(2000);/*** 每读一行触发一次*** @param workRollPlan* @param analysisContext*/@Overridepublic void invoke(WorkRollPlan workRollPlan, AnalysisContext analysisContext) {// 每次触发把workRollPlan放进列表list.add(workRollPlan);count++;// 一旦计数器到达2000或者2000的倍数时,插入数据库,并清空list,释放内存if (count % 2000 == 0) {workRollPlanService.preUpload(list);list.clear();}}/*** 所有数据读完之后触发一次*** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 最后不满2000条的数据在这里插入数据库workRollPlanService.preUpload(list);}
}
EasyExcel导出
public void WorkRollPlansToFileStream(HttpServletResponse response, List<WorkRollPlan> workRollPlans) throws IOException {response.setHeader("Content-disposition", "attachment;");OutputStream output = response.getOutputStream();EasyExcel.write(output).head(WorkRollPlan.class).excelType(ExcelTypeEnum.XLSX).sheet("Sheet1").doWrite(workRollPlans);output.close();
}
看下效果
把id也导出了,这是我们不需要的。
需要在实体类上加注解
@ExcelIgnoreUnannotated
EasyExcel结合Mybatis plus的分页功能进行分页导出
工具类
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Builder;
import lombok.Data;
import org.springframework.http.HttpHeaders;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;public class EasyExcelUtil {@Data@Builderpublic static class ExcelParam {/*** 查询 Mapper*/private BaseMapper baseMapper;/*** Lambda查詢方式*/private LambdaQueryWrapper lambdaQueryWrapper;/*** 页码,默认从1开始*/private Integer pageNo = 1;/*** 分页条数,,默认每个sheet 1000 条数据*/private Integer pageSize = 1000;/*** 用于存放查询到的結果,让Excel生成*/private Class<?> respClazz;/*** 生成的Excel 名称,不加后缀*/private String fileName;/*** Excel sheet名称*/private String sheetName;}public static void exportExcel(ExcelParam excelParam, HttpServletResponse response) {response.setContentType("application/vnd.ms-excel;charset=utf-8");response.setCharacterEncoding("utf-8");response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + excelParam.getFileName() + ".xlsx");try (ServletOutputStream outputStream = response.getOutputStream();ExcelWriter excelWriter = EasyExcel.write(outputStream, excelParam.getRespClazz()).build();) {Page page = new Page(excelParam.getPageNo(), excelParam.getPageSize());page = (Page) excelParam.getBaseMapper().selectPage(page, excelParam.getLambdaQueryWrapper());/** 构建 */WriteSheet writeSheet1 = EasyExcel.writerSheet(1, excelParam.getSheetName() + "第" + excelParam.getPageNo() + "页").build();/** 获取总数 */Long totalPage = page.getPages();List records = page.getRecords();/** 写入内容 */excelWriter.write(records, writeSheet1);writeSheet1 = null; // GC// 若为空表if (CollUtil.isEmpty(page.getRecords())) {/** 生成完毕 */excelWriter.finish();/** 立即刷回 */outputStream.flush();return;}for (int i = excelParam.pageNo + 1, index = 2; i <= totalPage; i++, index++) {/** 清空*/records.clear();WriteSheet writeSheet = EasyExcel.writerSheet(index, excelParam.getSheetName() + "第" + i + "页").build();page.setCurrent(i);/** 新的查询 */page = (Page) excelParam.getBaseMapper().selectPage(page, excelParam.getLambdaQueryWrapper());records = page.getRecords();/** 输入内容內容 */excelWriter.write(records, writeSheet);}/** 生成完毕 */excelWriter.finish();/** 立即刷回 */outputStream.flush();} catch (IOException e) {throw new RuntimeException(e);}}
}
使用
EasyExcelUtil.ExcelParam p = EasyExcelUtil.ExcelParam.builder().baseMapper(workRollPlanService.getBaseMapper()) // 传Service类的BaseMapper进去.lambdaQueryWrapper(new LambdaQueryWrapper<WorkRollPlan>() // 构建查询条件.eq(true, WorkRollPlan::getIsDeleted, 0)).pageNo(1) // 数据从第一行开始,如果表头只有一行就是1,表头有两行的话就写2.respClazz(WorkRollPlan.class) // 这里写实体类.pageSize(1000) // Excel每页数据大小.fileName("test") // 文件名.sheetName("测试sheet") // 页名.build();EasyExcelUtil.exportExcel(p, response);
相关文章:

POI导入导出、EasyExcel批量导入和分页导出
文件导入导出POI、EasyExcel POI:消耗内存非常大,在线上发生过堆内存溢出OOM;在导出大数据量的记录的时候也会造成堆溢出甚至宕机,如果导入导出数据量小的话还是考虑的,下面简单介绍POI怎么使用 POI导入 首先拿到文…...

手把手教你做微信公众号
手把手教你做微信公众号 微信公众号可以通过注册的方式来建立。 1.进入微信公众平台 首先,在浏览器中搜索微信公众号,网页第一个就是,如下图所示,我们点进去。 2.注册微信平台账号 进入官网之后,如下图所示&#…...

python-在macOS上安装python库 xlwings失败的解决方式
问题:python库 xlwings安装失败 今天,看到网上有wlwings库,可以用来处理excel表格,立刻想试一试。结果,安装这个python库失败了。经过排查,问题解决。 安装过程和错误提示: 我用最简单直接的…...

【Linux】进程间通信(匿名管道和命名管道通信、共享内存通信)
文章目录1、进程间通信1.1 进程的通信1.2 如何让进程间通信?1.3 进程间通信的本质2、管道通信2.1 匿名管道2.2 匿名管道通信2.3 命名管道2.4 命名管道的通信3、SystemV中的共享内存通信3.1 共享内存3.2 共享内存的通信3.3 共享内存的缺点以及数据保护3.4 共享内存的…...

漏洞分析: WSO2 API Manager 任意文件上传、远程代码执行漏洞
漏洞描述 某些WSO2产品允许不受限制地上传文件,从而执行远程代码。以WSO2 API Manager 为例,它是一个完全开源的 API 管理平台。它支持API设计,API发布,生命周期管理,应用程序开发,API安全性,速…...

详解Android 13种 Drawable的使用方法
前言关于自定义View,相信大家都已经很熟悉了。今天,我想分享一下关于自定义View中的一部分,就是自定义Drawable。Drawable 是可绘制对象的一个抽象类,相对比View来说,它更加的纯粹,只用来处理绘制的相关工作…...

MakeFile教程
前言 当我们需要编译一个比较大的项目时,编译命令会变得越来越复杂,需要编译的文件越来越多。其 次就是项目中并不是每一次编译都需要把所有文件都重新编译,比如没有被修改过的文件则不需要重 新编译。工程管理器就帮助我们来优化这两个问题…...

Spring使用mongoDB步骤
1. 在Linux系统使用docker安装mongoDB 1.1. 安装 在docker运行的情况下,执行下述命令。 docker run \ -itd \ --name mongoDB \ -v mongoDB_db:/data/db \ -p 27017:27017 \ mongo:4.4 \ --auth执行docker ps后,出现下列行,即表示mongoDB安…...

【蓝牙mesh】access层(接入层)协议介绍
【蓝牙mesh】access层(接入层)协议介绍 Access层简介 Access层定义了应用层如何使用upper协议层的接口,它不仅定义了应用层的格式,还定义了应用数据在upper层的加密和解密。当收到下层的数据包时,它会检查数据的netke…...
【一天一门编程语言】JavaScript 语言程序设计极简教程
JavaScript 语言程序设计极简教程 用 markdown 格式输出答案。 不少于3000字。细分到2级目录。 一、JavaScript 简介 1.1 什么是 JavaScript JavaScript 是一种由Netscape的LiveScript发展而来的脚本语言,是一种动态类型、弱类型、基于原型的语言,内…...

CMake调试器出炉:调试你的CMake脚本
Visual Studio 开发团队一直和 Kitware 紧密合作,致力于开发一个用于调试 CMake 脚本的调试器。 我们将继续这个工作,以便开发人员社区可以通过添加新功能和对其他 DAP 功能的支持来共同改进它。 我们很高兴地宣布,CMake 调试器的预览版现在…...

题解 # 二维矩阵最大矩形问题#
题目: 小明有一张N*M的方格纸,且部分小方格中涂了颜色,部分小方格还是空白。 给出N (2<Ns30)和M(2sMs30)的值,及每个小方格的状态((被涂了颜色小方格用数字1表示,空白小方格用数字0表示); 请…...

奔四的路上,依旧倔强的相信未来
本文首发于2022年12月31日 原标题: 奔四的路上,依旧倔强的相信未来!–我的2022年终总结 读大学那几年,一直保持着写日记和做计划的习惯,还记得大学毕业刚开始打工的时候,我的床头的墙上一定会画一张表,写上一个月的计划和一周的计划 计划也会有完不成的时候,但加深了…...
61 k8s + rancher + karmada容器化部署
文章目录 一、什么是rancher二、为什么使用rancher三、rancher安装1、细部介绍四、图形化操作1、执行2、补充五、 karmada1、官网2、细部介绍一、什么是rancher 1、Rancher 是一个 全栈式 的 Kubernetes 容器管理平台,为你提供在任何地方都能成功运行 Kubernetes 的工具。 二…...

Vue3的新特性变化,上手指南!
文章目录一、Vue3相比Vue2,更新了什么变化?二、Proxy 代理响应式原理三、组合式 API (Composition API)setup()函数:ref()函数reactive()函数组合式 setup 中使用 Props 父向子传递参数计算属性watch(数据监视)watchEffect&#x…...

OllyDbg
本文通过吾爱破解论坛上提供的OllyDbg版本为例,讲解该软件的使用方法 F2对鼠标所处的位置打下断点,一般表现为鼠标所属地址位置背景变红F3加载一个可执行程序,进行调试分析,表现为弹出打开文件框F4执行程序到光标处F5缩小还原当前…...
记一次键盘维修,最终修复
我的笔记本是华硕的K45VD,是我亲人在高二那年买的,之后就一直给我用,距今2023年已经差不多13年,它承载了太多记忆。在大学期间也给它升级,重要的零部件基本没问题。只在大学时加了8G内存和一个240G固态,换了…...
LeetCode 155.最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。实现 MinStack 类:MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。int getMin(…...
C++学习笔记-重载运算符和重载函数
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。 C 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重…...
Java —— JDBC
引入mysql链接 创建表格 Navicat查看建表代码双击要打开的表,右侧顶端点击ddl小方框 CREATE TABLE s (id int(6) NOT NULL,name varchar(20) COLLATE utf8_bin DEFAULT NULL,age int(11) DEFAULT NULL,gender varchar(2) COLLATE utf8_bin DEFAULT NULL,dept var…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...