【springboot+vue项目(十一)】springboot整合EasyExcel

        EasyExcel是阿里巴巴开源的一个Java库,用于操作Excel文件。它提供了简单易用的API,可以读取、写入和转换Excel文件,支持大量数据的导入和导出操作。

一、添加依赖(版本3.2)

<!--easyexcel操作excel-->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.0</version>
</dependency>

二、根据Excel来建立数据库表

        根据Excel的表头建立数据库表,注意每一张表有2个字段需要添加,即id和period(账期),建在最前面,此项工作可以借助chatgpt来完成

三、快速生成代码

        使用EasyCode 快速生成代码entity、service、mapper、servicelmpl

四、修改实体类entity

修改实体类entity,添加“账期”字段的自动插入

五、类继承、引用的方法引入

entity、service、mapper.、servicelmpl类继承、引用的方法引入,使用Alt+Enter键

六、easyExcel的model和listeners

package com.pbcnn.easyExcelCollector.excel.model;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;import java.math.BigDecimal;@Data
public class SheetSucffiBwbModel {@ExcelProperty(index = 1)private String indexName;@ExcelProperty(index = 2)private BigDecimal currentBalance;@ExcelProperty(index = 3)private BigDecimal currentMonthChange;@ExcelProperty(index = 4)private BigDecimal currentYearChange;@ExcelProperty(index = 5)private BigDecimal yearChangeRate;@ExcelProperty(index = 6)private BigDecimal lastYearBalance;@ExcelProperty(index = 7)private BigDecimal lastTwoYearsBalance;@ExcelProperty(index = 8)private BigDecimal lastYearGrowthRate;}
package com.pbcnn.easyExcelCollector.excel.listeners;import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson2.JSON;
import com.pbcnn.easyExcelCollector.common.SpringUtil;
import com.pbcnn.easyExcelCollector.entity.data.User;
import com.pbcnn.easyExcelCollector.excel.model.ExcelUserData;
import com.pbcnn.easyExcelCollector.mapper.UploadFileMapper;
import com.pbcnn.easyExcelCollector.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** ExcelModelListener 不能被spring管理,要每次读取 excel 都要 new,然后里面用到 spring 可以构造方法传进去** @author makejava* @create 2023-01-19 20:59*/
@Slf4j
public class UserDataListener implements ReadListener<ExcelUserData> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理 list ,方便内存回收,避免 OOM*/private static final int BATCH_COUNT = 100;/*** 缓存的数据,在 invoke 函数中存储每次读到的数据,这里的泛型虽业务变化而变化,存储的可以是excel表数据处理后的数据* 假如我要啊存入数据库中就需要将 ExcelUserData 转换成 User 那么这里的泛型就是User,在 invoke 中处理后添加*/private List<ExcelUserData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 这个是一个DAO,当然有业务逻辑这个也可以是一个service。可以用来解析数据后操作数据库*/@Autowiredprivate UserService userService;@Autowiredprivate UploadFileMapper uploadFileMapper;/*** 每读到一条数据都会调用这个函数,可以在这里对数据的预处理** @param excelUserData* @param analysisContext*/@Overridepublic void invoke(ExcelUserData excelUserData, AnalysisContext analysisContext) {log.info("解析到一条数据:{}", JSON.toJSONString(excelUserData));cachedDataList.add(excelUserData);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {log.info("已达到BATCH_COUNT,共{}条数据", cachedDataList.size());// 调用储存数据函数saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}/*** 所有数据解析完成了 都会来调用 做收尾工作,确保最后遗留的数据也持久化(存储到数据库)** @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", cachedDataList.size());//  TODO 数据存储,使用批处理操作防止多次连接数据库,例如 userService.saveBatch();if (cachedDataList.size() > 0) {List<User> userList = BeanUtil.copyToList(cachedDataList, User.class, null);UserService userService = SpringUtil.getBean(UserService.class);userService.saveBatch(userList);}log.info("存储数据库成功!");}}

添加的时候:

  1. model,复制entity的类,然后添加@ExcelProperty(index = 1),去掉id和period(账期)
  2. Listeners,直接复制其他类,然后将类的名字替换掉即可。

七、controller 解析Excel

package com.pbcnn.easyExcelCollector.controller;import com.alibaba.excel.EasyExcel;
import com.pbcnn.easyExcelCollector.excel.listeners.UserDataListener;
import com.pbcnn.easyExcelCollector.excel.model.ExcelUserData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;@RestController
public class UploadController {@Value("${file.upload-dir}")private String uploadDir;@PostMapping(value = "/uploadFiles", produces = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<?> upload(@RequestParam("files") MultipartFile[] files) {try {List<String> fileNames = new ArrayList<>();for (MultipartFile file : files) {if (!file.isEmpty()) {String fileName = UUID.randomUUID().toString() + "_" + StringUtils.cleanPath(file.getOriginalFilename());Path dest = Path.of(uploadDir, fileName);try (InputStream inputStream = file.getInputStream()) {Files.copy(inputStream, dest, StandardCopyOption.REPLACE_EXISTING);}fileNames.add(fileName);// 异步保存上传信息到数据库//CompletableFuture.runAsync(() -> {//    UploadFile uploadFile = new UploadFile();//    uploadFile.(fileName);//    uploadFile.setFilePath(dest.toString());//    uploadFile.setUploadTime(new Date());//    uploadFile.setStatus(0);//    uploadFileMapper.insert(uploadFile);//});/*根据文件路径读取excel*/String pathName = dest.toString();CompletableFuture.runAsync(() -> {EasyExcel.read(pathName, ExcelUserData.class, new UserDataListener()).sheet().doRead();});}}return ResponseEntity.ok(fileNames);} catch (IOException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传文件失败");}}
}

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

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

相关文章

Hadoop入门学习笔记——八、数据分析综合案例

视频课程地址&#xff1a;https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接&#xff1a;https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 Hadoop入门学习笔记&#xff08;汇总&#xff09; 目录 八、数据分析综合案例8.1. 需求分析8.1.1. 背景介绍8.1.2…

ocrmypdf_pdf识别

安装 安装说明 https://ocrmypdf.readthedocs.io/en/latest/installation.html#native-windows提到需要的软件&#xff1a; Python 3.7 (64-bit) or later Tesseract 4.0 or later Ghostscript 9.50 or later 安装 ocrmypdf pip install ocrmypdf 添加语言包 https://oc…

一篇文章带你了解基于 Jenkins 流水线方式部署的好处

在软件开发过程中&#xff0c;部署是将代码从开发环境转移到生产环境的关键步骤。传统的部署方式可能涉及多个手动步骤和容易出错的过程。然而&#xff0c;基于 Jenkins 流水线方式部署可以带来许多好处&#xff0c;包括提高效率、一致性和可靠性。本文将探讨基于 Jenkins 流水…

Flume基础知识(六):Flume实战之实时监控目录下的多个追加文件

Exec source 适用于监控一个实时追加的文件&#xff0c;不能实现断点续传&#xff1b;Spooldir Source 适合用于同步新文件&#xff0c;但不适合对实时追加日志的文件进行监听并同步&#xff1b;而 Taildir Source 适合用于监听多个实时追加的文件&#xff0c;并且能够实现断点…

C++高阶:元编程(Metaprogramming)--入门篇

模板元编程&#xff08;Template Meta programming&#xff0c;TMP&#xff09; 就是面向模板编程&#xff0c;把计算过程从运行时提前到编译期&#xff0c;提升性能&#xff1b; 区别于泛型编程&#xff08;利用模板实现“安全的宏”&#xff09; 应用场景&#xff1a; 编译期…

delphi中自定义自己的定时器

最近用上了rpt工具&#xff0c;但是用rpt自带的工具执行起一些定时任务不方便&#xff0c;有些功能不能自主&#xff0c;于是我在delphi中用定时器制作了自己的定时执行程序。 1、首先在窗体中放一个timer对象 2、在窗体的formcreate事件中加入以下关键代码&#xff0c;让定时器…

flask web学习之模板(一)

文章目录 一、模板基本用法1.1 定界符1.2 模板语法1.3 渲染模板 二、模板辅助工具2.1 上下文2.2 全局对象2.3 过滤器2.4 测试器2.5 模板环境对象 在动态web程序中&#xff0c;视图函数返回的HTML数据往往需要根据相应的变量&#xff08;比如查询参数&#xff09;动态生成。当HT…

Spring 与 Spring Boot:深入解析

Spring 与 Spring Boot&#xff1a;深入解析 前言: 欢迎来到本篇博客&#xff0c;今天我们将深度挖掘 Java 开发领域的两个主要框架——Spring 和 Spring Boot。尽管它们之间有着紧密的联系&#xff0c;但在某些方面却存在显著的区别。让我们逐步深入&#xff0c;挖掘它们的特…

【React系列】React中的CSS

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. React中的css方案 1.1. react 中的 css 事实上&#xff0c;css 一直是 React 的痛点&#xff0c;也是被很多开发…

接了一条路由器视频广告

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 2023年7月&#xff0c;松松团队荣幸的承接了“某口袋路由器”的短视频广告。 我们向客户索取了了几个卖点&#xff1a; 1.家用美观不用走线(无线小巧美观) 外出便携(出差、户外直播、露营等&#xff0c;只要充满电…

基于深度学习大模型实现离线翻译模型私有化部署使用,通过docker打包开源翻译模型,可到内网或者无网络环境下运行使用,可以使用一千多个翻译模型语言模型进行翻译

基于深度学习大模型实现离线翻译模型私有化部署使用,通过docker打包开源翻译模型,可到内网或者无网络环境下运行使用,可以使用一千多个翻译模型语言模型进行翻译,想要什么语种直接进行指定和修改就行。 环境要求,电脑内存低于8G建议不要尝试了,有无GPU都可以运行,但是有…

SpringBoot3多数据源动态切换

demo使用的时SpringBoot3.x、JDK17、MybatisPlus3.5.x、MySQL8 从数据中加载数据源 定义接口&#xff0c;指定数据源&#xff0c;从不同数据库获取数据 创建数据源表&#xff0c;用于指定不同数据源&#xff0c;程序自动动态获取 项目版本依赖关系 demo中所用到的工具以及…

宝塔安装的imagemagick不能用,必须自己手动安装

1 安装 用composer安装 2 宝塔安装的imagemagick不能用&#xff0c;必须自己手动安装&#xff08;3.4.3版本 php 7.3&#xff09; 1 步骤&#xff1a; wget https://pecl.php.net/get/imagick-3.4.3.tgz tar -zxf imagick-3.4.3.tgz cd imagick-3.4.3 /www/server/php/73…

代码+视频,手把手教你R语言使用forestploter包绘制单组及双组森林图

森林图在论文中很常见&#xff0c;多用于表示多因素分析中的变量与结果变量的比值效应&#xff0c;可以用图示的方法比较直观的绘制出来。既往我们在文章《R语言快速绘制多因素回归分析森林图&#xff08;1&#xff09;》已经介绍了怎么绘制森林图&#xff0c;但是绘图比较简单…

开启Android学习之旅-2-架构组件实现数据列表及添加(kotlin)

Android Jetpack 体验-官方codelab 1. 实现功能 使用 Jetpack 架构组件 Room、ViewModel 和 LiveData 设计应用&#xff1b;从sqlite获取、保存、删除数据&#xff1b;sqlite数据预填充功能&#xff1b;使用 RecyclerView 展示数据列表&#xff1b; 2. 使用架构组件 架构组…

Python从入门到网络爬虫(内置函数详解)

前言 Python 内置了许多的函数和类型&#xff0c;比如print()&#xff0c;input()等&#xff0c;我们可以直接在程序中使用它们&#xff0c;非常方便&#xff0c;并且它们是Python解释器的底层实现的&#xff0c;所以效率是比一般的自定义函数更有效率。目前共有71个内置函数&…

lambda表达式使用和示例

lambda表达式 什么是lambda 学习lamdba有两个结构十分关键&#xff0c;一个是lamdba自己&#xff0c;另一个是函数式接口 lamdba lamdba表达式本质上就是匿名方法&#xff0c;不能独立运行用于实现函数式接口定义的另一个方法&#xff0c;因此lamdba会产生一个匿名类lamdba…

全球海洋数据 (GLODAP) v2.2023(海洋碳数据产品)

全球海洋数据分析项目 (GLODAP) v2.2023 全球海洋数据分析项目 (GLODAP) v2.2023 代表了海洋生物地球化学瓶数据合成方面的重大进步。此更新主要关注海水无机碳化学&#xff0c;以 GLODAPv2.2022 为基础&#xff0c;包含多项关键增强功能。值得注意的是&#xff0c;增加了 43 …

CISSP 第9章:安全脆弱性、威胁和对策

第九章 安全脆弱性、威胁和对策 9.1 评估和缓解安全脆弱性 9.1 硬件 处理器 执行类型 多任务处理&#xff1a; 同时处理两个或更多任务 多处理&#xff1a; 利用多个处理器完成一个应用程序的处理能力 多程序设计&#xff1a;通过操作系统对单个处理器上的两个任务进行协调&…

Node.js+Express+Mysql实现分页查询

根据记录数总数和分页数获到页总数 function pageCount (totalnum,limit){return totalnum > 0 ? ((totalnum < limit) ? 1 : ((totalnum % limit) ? (parseInt(totalnum / limit) 1) : (totalnum / limit))) : 0; } 接收请求代码 router.get(/api/user/page, asy…