springboot使用EasyExcel实现Excel导入导出

         java生成Excel比较有名的框架有Apache poi、jxl等,但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。

        EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部载到内存中,而是从磁盘上一行行读取数据,逐个解析。EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理( AnalysisEventListener )。

1、pom添加easyexcel依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.3</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version>
</dependency>

2、实体类UserDO与Excel数据对应

@Data
public class UserDO {// 设置excel表头名称@ExcelProperty("用户编号")@ColumnWidth(20)private Long id;// 设置该列的名称为'用户名';@ExcelProperty("用户名")// 设置表格列的宽度为20@ColumnWidth(20)private String username;// 导出时忽略该字段@ExcelIgnoreprivate String password;@ExcelProperty("昵称")@ColumnWidth(20)private String nickname;@ExcelProperty("生日")@ColumnWidth(20)// 按照指定的格式对日期进行格式化;@DateTimeFormat("yyyy-MM-dd")private Date birthday;@ExcelProperty("手机号")@ColumnWidth(20)private String phone;@ExcelProperty("身高(米)")@NumberFormat("#.##")@ColumnWidth(20)private Double height;// 自定义内容转换器@ExcelProperty(value = "性别", converter = GenderConverter.class)@ColumnWidth(10)private Integer gender;}

常用注解有:
@ExcelProperty 指定当前字段对应excel中的哪一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。
@ExcelIgnore EasyExcel默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
@DateTimeFormat 日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat
@NumberFormat 数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat

3、converter自定义转换器

自定义转换器将数据库中表示性别的1、0转换成男、女

  3.1、GenderConverter 

/*** 性别转换器* */
public class GenderConverter implements Converter<Integer> {@Overridepublic Class<?> supportJavaTypeKey() {// 实体类中对象属性类型return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {// Excel中对应的CellData(单元格数据)属性类型return CellDataTypeEnum.STRING;}/*** 将单元格里的数据转为java对象,也就是女转成2,男转成1,用于导入excel时对性别字段进行转换* */@Overridepublic Integer convertToJavaData(ReadConverterContext<?> context) throws Exception {// 从CellData中读取数据,判断Excel中的值,将其转换为预期的数值return GenderEnum.convert(context.getReadCellData().getStringValue()).getValue();}/*** 将java对象转为单元格数据,也就是2转成女,1转成男,用于导出excel时对性别字段进行转换* */@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) throws Exception {// 判断实体类中获取的值,转换为Excel预期的值,并封装为CellData对象return new WriteCellData<>(GenderEnum.convert(context.getValue()).getDescription());}
}

 3.2、GenderEnum

@Getter
@AllArgsConstructor
public enum GenderEnum {/*** 未知*/UNKNOWN(0, "未知"),/*** 男性*/MALE(1, "男性"),/*** 女性*/FEMALE(2, "女性");private final Integer value;@JsonFormatprivate final String description;public static GenderEnum convert(Integer value) {
//        用于为给定元素创建顺序流
//        values:获取枚举类型的对象数组return Stream.of(values()).filter(bean -> bean.value.equals(value)).findAny().orElse(UNKNOWN);}public static GenderEnum convert(String description) {return Stream.of(values()).filter(bean -> bean.description.equals(description)).findAny().orElse(UNKNOWN);}}

4、导出

/*** 设置响应结果** @param response    响应结果对象* @param rawFileName 文件名* @throws UnsupportedEncodingException 不支持编码异常*/
private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {//设置内容类型response.setContentType("application/vnd.vnd.ms-excel");//设置编码格式response.setCharacterEncoding("utf-8");//设置导出文件名称(避免乱码)String fileName = URLEncoder.encode(rawFileName.concat(".xlsx"), "UTF-8");// 设置响应头response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
}private Date getBirthday(int year, int month, int day){Calendar calendar = Calendar.getInstance();calendar.set(year, month, day);return calendar.getTime();
}/*** 导出数据* */
@GetMapping("/export/user")
public void exportUserExcel(HttpServletResponse response) throws IOException {OutputStream outputStream = response.getOutputStream();try {this.setExcelResponseProp(response, "用户列表");// 模拟根据条件在数据库查询数据List<UserDO> userList = new ArrayList<>();for(int i = 0;i < 30;i++){UserDO userDO = new UserDO();userDO.setBirthday(getBirthday(2001,1,i));userDO.setGender(1);userDO.setHeight(Double.valueOf(i));userDO.setId(Long.valueOf(i));userDO.setPhone("138"+i);userDO.setNickname("yuanhaoz");userDO.setPassword("5849"+i);userDO.setUsername("monky"+i);userList.add(userDO);}//这个实现方式非常简单直接,使用EasyExcel的write方法将查询到的数据进行处理,以流的形式写出即可EasyExcel.write(outputStream,UserDO.class)//对应的导出实体类.excelType(ExcelTypeEnum.XLSX)//excel文件类型,包括CSV、XLS、XLSX.sheet("用户列表")//导出sheet页名称.doWrite(userList); //查询获取的数据集合List<T>,转成excel} catch (IOException e) {throw new RuntimeException(e);}finally {outputStream.flush();outputStream.close();}
}

5、多sheet导出

/*** 多sheet导出数据* */
@GetMapping("/manySheet")
public void exportManySheet(HttpServletResponse response)throws IOException{OutputStream outputStream=response.getOutputStream();ExcelWriter writer = EasyExcel.write(outputStream, UserDO.class).excelType(ExcelTypeEnum.XLSX).build();try {this.setExcelResponseProp(response, "用户列表");// 模拟根据条件在数据库分页查询数据for(int j = 1;j <= 5;j++){List<UserDO> userList = new ArrayList<>();for(int i = 0;i < 30;i++){UserDO userDO = new UserDO();userDO.setBirthday(getBirthday(2001,1,i));userDO.setGender(1);userDO.setHeight(Double.valueOf(i));userDO.setId(Long.valueOf(i));userDO.setPhone("138"+i);userDO.setNickname("yuanhaoz"+i);userDO.setPassword("5849"+i);userDO.setUsername("monky"+i);userList.add(userDO);System.out.println(i);}//创建新的sheet页WriteSheet writeSheet = EasyExcel.writerSheet("用户信息" + j).build();//将list集合中的对象写到对应的sheet中去writer.write(userList,writeSheet);}} catch (IOException e) {throw new RuntimeException(e);//给提示todo}finally {writer.finish();outputStream.flush();outputStream.close();}
}

6、导入

6.1、UserListener

/*** 自定义监听器,对下载的excel中的数据进行校验* */
public class UserListener extends AnalysisEventListener {List<String> names = new ArrayList<>();/*** 每解析一行,回调该方法** @param data* @param context*/@Overridepublic void invoke(Object data, AnalysisContext context) {//校验名称String name = ((UserDO) data).getUsername();if (StrUtil.isBlank(name)) {throw new RuntimeException(String.format("第%s行名称为空,请核实", context.readRowHolder().getRowIndex() + 1));}if (names.contains(name)) {throw new RuntimeException(String.format("第%s行名称已重复,请核实", context.readRowHolder().getRowIndex() + 1));} else {names.add(name);}}/*** 出现异常回调** @param exception* @param context* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof ExcelDataConvertException) {/**从0开始计算*/Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;String message = "第" + rowIndex + "行,第" + columnIndex + "列" + "数据格式有误,请核实";throw new RuntimeException(message);} else if (exception instanceof RuntimeException) {throw exception;} else {super.onException(exception, context);}}/*** 解析完,全部回调** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//解析完,全部回调逻辑实现names.clear();}
}

6.2、ImportData

/*** 导入数据* */
@PostMapping(value = "/importData")
public void ImportData(MultipartFile file){try {//获取文件的输入流InputStream inputStream = file.getInputStream();List<UserDO> list = EasyExcel.read(inputStream) //调用read方法//注册自定义监听器,字段校验可以在监听器内实现.registerReadListener(new UserListener()).head(UserDO.class) //对应导入的实体类.sheet(0) //导入数据的sheet页编号,0代表第一个sheet页,如果不填,则会导入所有sheet页的数据.headRowNumber(1) //列表头行数,1代表列表头有1行,第二行开始为数据行.doReadSync(); //开始读Excel,返回一个List<T>集合,继续后续入库操作//模拟导入数据库操作for (UserDO userDO : list){System.out.println(userDO.toString());}} catch (IOException exception){throw new RuntimeException(exception);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/731340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微前端之再说无界的使用

运行模式 保活模式单例模式重建模式 生命周期改造 改造入口函数&#xff1a; 应用间通信 原理props 通信 主应用可以通过 props 注入数据和方法&#xff1a;子应用可以通过 $wujie 对象来获取数据&#xff1a; window 通信 主应用调用子应用的全局数据&#xff1a;子应用调用主…

每天学习一个Linux命令之find

每天学习一个Linux命令之find 概述 在Linux系统中&#xff0c;find命令是一个非常强大的工具&#xff0c;用于查找和操作文件和目录。它可以根据一些条件来搜索指定路径下的文件&#xff0c;并执行相应的操作。本篇博客将详细介绍find命令的各个可用选项及其用法。 基本语法…

lvs集群中NAT模式

群集的含义 由多台主机构成&#xff0c;但对外表现为一个整体&#xff0c;只提供一个访问入口&#xff0c;相当于一台大型的计算机。 横向发展:放更多的服务器&#xff0c;有调度分配的问题。 垂直发展&#xff1a;升级单机的硬件设备&#xff0c;提高单个服务器自身功能。 …

如何保证消息不丢之MQ重试机制消息队列

1. 简介 死信队列&#xff0c;简称&#xff1a;DLX&#xff0c;Dead Letter Exchange&#xff08;死信交换机&#xff09;&#xff0c;当消息成为Dead message后&#xff0c;可以被重新发送到另外一个交换机&#xff0c;这个交换机就是DLX 那么什么情况下会成为Dead message&a…

波卡 Alpha 计划启动,呼唤先锋创新者重新定义 Web3 开发

原文&#xff1a;https://polkadot.network/blog/the-polkadot-alpha-program-a-new-era-for-decentralized-building-collaboration/ 编译&#xff1a;OneBlock 区块链领域不断发展&#xff0c;随之而来的是发展和创新机会的增加。而最新里程碑是令人振奋的 Polkadot Alpha …

深入理解nginx一致性哈希负载均衡模块[上]

1. 引言 在现代的网络应用中&#xff0c;负载均衡是一个至关重要的组件。它能够分配流量到多个服务器上&#xff0c;实现高可用性和性能扩展。Nginx是一个广泛使用的高性能Web服务器和反向代理服务器&#xff0c;其负载均衡模块提供了多种算法来实现流量的分发。其中&#xff0…

【刷题记录】详谈设计循环队列

下题目为个人的刷题记录&#xff0c;在本节博客中我将详细谈论设计循环队列的思路&#xff0c;并给出代码&#xff0c;有需要借鉴即可。 题目&#xff1a;LINK 循环队列是线性表吗&#xff1f;或者说循环队列是线性结构吗&#xff1f; 对于这个问题&#xff0c;我们来看一下线…

【Linux进阶之路】网络 —— “?“ (下)

文章目录 前言一、概念铺垫1.TCP2.全双工 二、网络版本计算器1. 原理简要2. 实现框架&&代码2.1 封装socket2.2 客户端与服务端2.3 封装与解包2.4 请求与响应2.5 对数据进行处理2.6 主程序逻辑 3.Json的简单使用 总结尾序 前言 在上文我们学习使用套接字的相关接口进行了…

面试经典150题(108-110)

leetcode 150道题 计划花两个月时候刷完之未完成后转&#xff0c;今天&#xff08;第3天&#xff09;完成了3道(108-110)150 108.(201. 数字范围按位与) 题目描述&#xff1a; 给你两个整数 left 和 right &#xff0c;表示区间 [left, right] &#xff0c;返回此区间内所有数…

Tomcat的安装

下载Tomcat&#xff08;这里以Tomcat8.5为例&#xff09; 直接进入官网进行下载&#xff0c;Tomcat官网 选择需要下载的版本&#xff0c;点击下载这里一定要注意&#xff1a;下载路径一定要记住&#xff0c;并且路径中尽量不要有中文&#xff01;&#xff01;&#xff01;&…

怎么把视频变成gif动图?一招在线生成gif动画

MP4是一种常见的视频文件格式&#xff0c;它是一种数字多媒体容器格式&#xff0c;可以用于存储视频、音频和字幕等多种媒体数据。MP4格式通常用于在计算机、移动设备和互联网上播放和共享视频内容。要将MP4视频转换为GIF格式&#xff0c;您可以使用专门的视频转gif工具。这个工…

三款顶级开源RAG (检索增强生成)工具:Verba、Unstructured 和 Neum

三款顶级开源RAG (检索增强生成)工具&#xff1a;Verba、Unstructured 和 Neum 概述 随着企业对话式数据处理需求的提升&#xff0c;面临的挑战是数据隐私性和缺乏企业级解决方案。虽然类似LangChain能在短时间内构建RAG应用&#xff0c;但忽视了文档解析、多来源数据ETL、批量…

Python 对Excel工作表中的数据进行排序

在Excel中&#xff0c;排序是整理数据的一种重要方式&#xff0c;它可以让你更好地理解数据&#xff0c;并为进一步的分析和报告做好准备。本文将介绍如何使用第三方库Spire.XLS for Python通过Python来对Excel中的数据进行排序。包含以下三种排序方法示例&#xff1a; 按数值…

【洛谷 P8723】[蓝桥杯 2020 省 AB3] 乘法表 题解(数学+进制转换+字符串)

[蓝桥杯 2020 省 AB3] 乘法表 题目描述 九九乘法表是学习乘法时必须要掌握的。在不同进制数下&#xff0c;需要不同的乘法表。 例如, 四进制下的乘法表如下所示&#xff1a; 1*11 2*12 2*210 3*13 3*212 3*321请注意&#xff0c;乘法表中两个数相乘的顺序必须为样例中所示的…

从0开始的 Vue 生活

Vue 一、配置环境1.1 安装node.js1.1.1 node.js 下载1.1.2 node.js 安装1.1.3 node.js 配置 1.2 安装VSCode1.2.1 VSCode 下载1.2.2 VSCode 安装1.2.3 VSCode 配置 二、创建Vue项目2.1 使用命令行创建Vue项目2.2 使用VSCode运行Vue项目2.3 尝试编写Vue项目2.3.1 准备工作2.3.2 …

线性代数笔记14--投影

1. 一维空间投影 p X A e B − p B − X A A ⊤ e 0 A ⊤ ( B − X A ) 0 X A ⊤ A A ⊤ B X A ⊤ B A ⊤ A p X A A A ⊤ B A ⊤ A pXA\\ eB-pB-XA\\ A^{\top}e0\\ A^{\top}(B-XA)0\\ XA^{\top}AA^{\top}B\\ X\frac{A^{\top}B}{A^{\top}A}\\ pXAA\frac{A^{\top}B}{A^…

Java开发与配置用到的各类中间件官网

开发配置时用到了一些官网地址&#xff0c;记录一下。 activemq 官网&#xff1a;ActiveMQ elk 官网&#xff1a;Elasticsearch 平台 — 大规模查找实时答案 | Elastic nginx 官网&#xff1a;nginx maven 官网&#xff1a;Maven – Welcome to Apache Maven nexus 官网&a…

Zoom软件怎么购买?zoom付费订阅教程

首先&#xff0c;让我们来了解一下Zoom的各个版本以及它们的价格。简单来说&#xff0c;Zoom分为免费版和收费版&#xff0c;收费版又包括专业版、商业版和企业版。 一、免费版 Zoom的免费版功能已经非常实用了&#xff0c;适合个人用户和小团队使用。免费版提供以下功能: 最多…

centos7 python3.12.1 报错 No module named _ssl

https://blog.csdn.net/Amio_/article/details/126716818 安装python cd /usr/local/src wget https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tgz tar -zxvf Python-3.12.1.tgz cd Python-3.12.1/ ./configure -C --enable-shared --with-openssl/usr/local/opens…

小程序学习

一、第一天 1、小程序体验 2、注册账号 小程序 (qq.com) 3、开发工具下载 下载 / 稳定版更新日志 (qq.com) 4、目录结构 "navigationBarBackgroundColor": "#00b26a" 配置头部背景色 4、wxml模板介绍 5、wxss 6、js文件 7、宿主环境 1、通信主体 2…