Spring Boot + EasyExcel + SqlServer 进行批量处理数据

前言

在日常开发和工作中,我们可能要根据用户上传的文件做一系列的处理,本篇文章就以Excel表格文件为例,模拟用户上传Excel文件,讲述后端如何高效的进行数据的处理。

一.引入 EasyExcel  依赖

        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.2</version>
        </dependency>

二.在接口中编写代码

(一).使用什么参数接收?

由于用户上传的是一个Excel文件,也就是说前端发来的是一个Excel表格的文件,那么我们后端就需要使用  MultipartFile file  来进行接收

 @PostMapping("/importExcelUpdateFlag")
    public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) {
           //具体代码......
    }

(二).如何存储到本地目录中(最后说为什么存储到本地)

既然前端发来了一个Excel文件,后端需要对其进行重命名还有大量的数据处理,那么如何存储到本地是一个问题。我们在三层架构的基础上,这个存储到本地的工作一般放在 Service 层进行处理。

Controller层的代码

下面的 uploadPath(也就是你要存储到本地的目录) 是自己在 yml文件中定义好的,然后进行使用,截图如下:

@PostMapping("/importExcelUpdateFlag")
    public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) {

        //把前端发来的文件数据,传到本机指定的 uploadPath 目录之下
        String pathAndFileName = jdCloudService.uploadFile(file,uploadPath);
         //其他代码....
    }

注意这里 pathAndFileName 接收的是一个本地路径,后续需要根据这个路径找到指定文件

Service 层的代码

    @Override
    public String uploadFile(MultipartFile file, String uploadPath) {
        if(file.isEmpty()){
            return "上传文件为空";
        }
        try {
            String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String newFilename = generateFilename() + fileExtension;
            File targetFile = new File(uploadPath + File.separator + newFilename);
            file.transferTo(targetFile);
            return uploadPath + "\\" + newFilename;
        } catch (Exception e) {
            return "文件上传失败: " +  e.getMessage();
        }

    }



    private String generateFilename() {
        // 根据你的需求生成新的文件名,例如使用时间戳或随机字符串等,这里使用时间戳
        return String.valueOf("更新文件名.." + System.currentTimeMillis());
    }
代码解读:我们假设前端传来了一个 hello.xlsx 文件
  1. String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());这行代码会将 "hello.xlsx " 赋值给 originalFilename 变量。

  2. String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));

    这行代码会从 "hello.txt" 中提取出文件扩展名 ".txt",并将其赋值给 fileExtension 变量。
  3. String newFilename = generateFilename() + fileExtension;

    这行代码会调用 generateFilename() 方法生成一个新的唯一文件名,例如 "abc123"。
  4. 将生成的文件名 "abc123.xlsx" 与文件扩展名 ".txt" 拼接,赋值给 newFilename 变量。
  5. File targetFile = new File(uploadPath + File.separator + newFilename);

    假设 uploadPath 是 "/path/to/uploads/"。这行代码会创建一个 File 对象,代表文件的保存路径和文件名 "/path/to/uploads/abc123.xlsx"。那么这个就会创建出文件了(但是没有内容)
  6. file.transferTo(targetFile);

    这行代码会将用户上传的 "hello.xlsx" 文件的内容,写入到 "/path/to/uploads/abc123.xlsx" 文件中。

通过这样的处理,原本名为 "hello.xlsx" 的文件会被保存为 "abc123.xlsx",并且保存在 "/path/to/uploads/" 目录下。这样可以避免文件名与现有文件发生冲突,确保文件上传的安全性。

注意这里返回给 Controller 层的是一个本地目录,是根据目录来找到指定的文件!

三.假设需求

现在假设我们本地指定的目录下面已经有用户上传的文件了,那么我们要对这个文件进行一系列的处理。 现在假设我们的需求是根据Excel文件中用户的 工号,更新用户的 Flag 标签(0变为1)

那么应该如何做呢?

继续编写代码

Controller层

    @PostMapping("/importExcelUpdateFlag")
    public Map<String,Object> importExcelUpdateFlag(@RequestBody MultipartFile file) {
        Map<String,Object> response = new HashMap<>();
        response.put("code",0);
        response.put("data",":");
        //把前端发来的文件数据,传到本机指定的 uploadPath 目录之下
        String pathAndFileName = jdCloudService.uploadFile(file,uploadPath);

        if(pathAndFileName.equals("上传文件为空") || pathAndFileName.equals("文件上传失败")) {
            response.put("msg",pathAndFileName);
            return response;
        }

        String feedBackMsg = jdCloudService.enableFlagUpdate(pathAndFileName);


        response.put("msg",feedBackMsg);
        return response;
    }

这里主要是 feedBackMsg,这个调用的 Service 层的代码是处理表格数据的主要内容,我们来看

Service层

    @Override
    public String enableFlagUpdate(String filename) {
        //获取 PersonSynData 类的 Class 对象。
        Class<PersonSynData> head = PersonSynData.class;
        List<PersonSynData> updateList = new ArrayList<>();
        ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<PersonSynData>() {
            @Override
            public void invoke(PersonSynData personSynData, AnalysisContext analysisContext) {

                updateList.add(personSynData);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("Excel解析完成......");
            }
        }).build();

        //创建 sheet 对象,并且读取Excel的第一个sheet(下表从0开始),也可以根据 sheet 名称获取
        ReadSheet readSheet = EasyExcel.readSheet(0).build();
        //读取 sheet 表格数据,参数是可变参数,也可以读取多个sheet
        //这个操作会读取 excel 表格的数据
        excelReader.read(readSheet);
        //需要自己关闭流操作,在读取文件的时候会创建临时文件,如果不关闭的话,会损耗磁盘
        excelReader.finish();

        
    }

代码解读:

1.首先获取到实体类的 class 对象,后续需要进行使用

2.updateList 是要存储 Excel 表格中的每一行,每一行都是一个 实体类对象

3. ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<PersonSynData>() {...});是Alibaba提供的一个工厂方法,用于创建一个 ExcelReader 对象。
filename 是要解析的 Excel 文件的路径。
head 是前面获取的 PersonSynData 类的 Class 对象,用于告诉 EasyExcel 应该如何解析 Excel 数据。
new AnalysisEventListener<PersonSynData>() {...} 是一个匿名内部类,实现了 AnalysisEventListener 接口。这个监听器用于处理 Excel 数据的解析过程

4. invoke 是必须重写的方法

  • 每解析到一行 Excel 数据,就会调用这个方法,并将解析后的 PersonSynData 实例作为参数传递进来。
  • 在这个方法中,我们将解析出的 PersonSynData 实例添加到 updateList 中。

5. doAfterAllAnalysed也是必须重写的方法

  • 这个方法是 AnalysisEventListener 接口的 doAfterAllAnalysed 方法的实现。
  • 当 Excel 文件的所有数据都解析完成后,就会调用这个方法。
  • 在这个方法中,我们打印了一条消息,表示 Excel 解析完成。

6.当代码执行到  excelReader.read(readSheet); 此时 updateList 中就有我们需要的数据了

注意!更新操作在下一篇博客: http://t.csdnimg.cn/RUZvM

四.为什么要缓存到本地?

缓存到本地和在内存中进行处理是两种不同的解决方案

在处理前端传来的Excel文件时,后端是否需要将其存储到本地再进行解析,确实存在几种不同的处理方式。

  1. 存储到本地后再解析:这种方式的优点是可以避免在内存中一次性加载整个Excel文件,从而减轻内存压力。同时,如果需要对文件进行多次处理,存储到本地后可以直接读取而无需重新上传,提高效率。缺点是需要占用服务器硬盘空间,并且需要额外的IO操作。

  2. 直接在内存中解析:这种方式可以省略存储到本地的步骤,直接从前端传来的数据流中进行解析。优点是减少了IO操作,提高了处理速度。缺点是需要一次性加载整个Excel文件到内存中,如果文件很大可能会造成内存溢出的风险。

综合来看,两种方式各有优缺点。具体采用哪种方式,需要根据实际业务需求、文件大小、服务器资源等因素进行权衡。如果Excel文件较小,且只需要处理一次,直接在内存中解析可能是更好的选择。而对于较大的Excel文件,或需要多次处理的场景,将其存储到本地可能会更合适。总之,在设计后端处理逻辑时,需要充分考虑各种因素,选择最佳的解决方案。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos下创建raid6磁盘阵列

在CentOS系统中创建RAID 6阵列&#xff0c;可以使用mdadm工具。 以下是创建RAID 6阵列的基本步骤和示例代码&#xff1a; 安装mdadm工具&#xff08;如果尚未安装&#xff09;&#xff1a; sudo yum install mdadm 假设你有至少四个以上的磁盘设备&#xff08;例如 /dev/sdi…

Visual Studio Code的安装与配置

Visual Studio Code&#xff08;简称 VS Code&#xff09;是 Microsoft 在2015年4月30日 Build 开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Linux 之上的&#xff0c;针对于编写现代 Web 和云应用的跨平台源代码编辑器&#xff0c;可在桌面上运行&#xff0c;并且可用…

golang函数

【1】函数&#xff1a; 对特定的功能进行提取&#xff0c;形成一个代码片段&#xff0c;这个代码片段就是我们所说的函数 【2】函数的作用&#xff1a;提高代码的复用性 【3】函数和函数是并列的关系&#xff0c;所以我们定义的函数不能写到main函数中 【4】基本语法 func 函…

Redis高并发高可用

1. 复制机制 在分布式系统中&#xff0c;为了解决单点问题&#xff0c;通常会将数据复制多个副本部署到其他机器&#xff0c;以满足故障恢复和负载均衡等需求。Redis提供了复制功能&#xff0c;实现了相同数据的多个Redis副本。复制功能是高可用Redis的基础&#xff0c;后面的…

DeepSpeed Monitoring Comm. Logging

Monitoring 支持多种后端&#xff1a;Tensorboard、WandB、Comet、CSV文件&#xff1b; TensorBoard例子&#xff1a; 自动监控&#xff1a;DeepSpeed自动把重要metric记录下来。只需在配置文件里enable相应的看板后端即可&#xff1a; {"tensorboard": {"enabl…

HTML+CSS+JS 自定义下拉菜单

效果演示 实现了一个下拉菜单的动画效果&#xff0c;包括一个主按钮和一个下拉菜单列表。点击主按钮会展开下拉菜单列表&#xff0c;同时箭头会旋转&#xff0c;列表项会逐渐显示出来。鼠标悬停在列表上时&#xff0c;会出现一个浮动图标。整个下拉菜单的样式比较简洁&#xff…

vue3第三十九节(TS中的高级类型,分类以及使用注意事项)

前言&#xff1a;为什么需要使用高级类型&#xff0c;正常的类型不能满足日常的业务需求&#xff0c;对于复杂的数据结构、函数签名、类型转换&#xff0c;我们需要使用高级类型来处理&#xff0c;常用的高级类型包含以下几种&#xff1a; 常用的类型定义&#xff1a; 基本类…

理解 GPIO 的推挽与开漏

在日常的嵌入式开发过程当中&#xff0c;GPIO可以说是接触最多的外设了。小到点亮一个LED灯&#xff0c;大到模拟总线通讯&#xff0c;都必不可少地需要用到GPIO资源。而对于GPIO的两大输出模式 ——推挽输出和开漏输出&#xff0c;你是否真正理解了呢&#xff1f; 首先我们看…

HCIA14 DHCP 实验

动态主机配置协议 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;由 RFC 2131 定义&#xff0c;采用客户端/服务器通信模式&#xff0c;由客户端&#xff08;DHCP Client&#xff09;向服务器&#xff08;DHCP Server&#xff09;提出配置申请&#xff0c;服…

哈希应用——布隆过滤器

布隆过滤器的提出 场景一&#xff1a;在注册账号设置昵称的时候&#xff0c;为了保证每个用户昵称的唯一性&#xff0c;系统必须检测你输入的昵称是否被使用过&#xff0c;这本质就是一个key的模型&#xff0c;我们只需要判断这个昵称被用过&#xff0c;还是没被用过。 场景二&…

声学气膜馆:高品质声效与灵活应用的完美结合—轻空间

声学气膜馆是一种结合气膜建筑和声学优化的新型场馆。这种建筑形式不仅可以快速搭建和灵活使用&#xff0c;还能提供出色的声学效果&#xff0c;非常适合用于音乐演出、体育比赛、会议展览等多种场合。 气膜建筑的声学优势 气膜建筑利用空气压力支撑膜材&#xff0c;形成稳定的…

计算机图形学入门09:深度缓存

在前面知道了怎么将一个三角形显示到屏幕上&#xff0c;那么如果有很多三角形&#xff0c;各自距离相机的远近也不一样&#xff0c;并且三角形会相互遮挡。也就是三维空间中有很多物体&#xff0c;通常近处的物体会遮挡住远处的物体&#xff0c;那么在计算机渲染中该如何处理呢…

第十四篇——互信息:相关不是因果,那相关是什么?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/499cd9af2ea14cbf8d12813f6f…

Linux命令详解(2)

文本处理是Linux命令行的重要应用之一。通过一系列强大的命令&#xff0c;用户可以轻松地对文本文件进行编辑、查询和转换。 cat&#xff1a; 这个命令用于查看文件内容。它可以一次性显示整个文件&#xff0c;或者分页显示。此外&#xff0c;cat 还可以用于合并多个文件的内容…

超全分析MybatisPlus中的MetaObjectHandler全局字段填充的基本知识(附Demo及实战)

目录 前言1. 源码及API2. Demo架构3. 全局字段填充&#xff08;实战&#xff09;4. 局部字段不填充&#xff08;实战&#xff09; 前言 对于Java的相关知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项…

nginx ws长连接配置

nginx ws长连接配置 http根节点下配上 map $http_upgrade $connection_upgrade {default upgrade; close;}如下&#xff1a; server服务节点下&#xff0c;后端接口的代理配置 proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connec…

电脑意外出现user32.dll丢失的八种修复方法,有效解决user32.dll文件丢失

遇到与 user32.dll 相关的错误通常是因为该文件已损坏、丢失、或者与某些软件冲突。今天这篇文章寄给大家介绍八种修复user32.dll丢失的方法&#xff0c;下面是一步步的详细教程来解决这个问题。 1. 重新启动电脑 第一步总是最简单的&#xff1a;重新启动你的电脑。许多小问题…

52.Python-web框架-Django - 多语言编译-fuzzy错误

目录 1.起因 2.原因 3.解决方法 3.1手动移除fuzzy标记 3.2重新生成po文件&#xff0c;并检查是否还存在fuzzy标记 3.3重新编译生成mo文件 1.起因 在Django的国际化和本地化过程中&#xff0c;当你发现某些字段仅显示msgid&#xff0c;而不显示msgstr时&#xff0c;可能是…

Python爬虫实战(实战篇)—18获取【小红书】首页信息写入Excel(仅用于学习-附完整版代码)

文章目录 专栏导读背景1、分析首页页面2、分析获取信息2-1,获取:笔记类型2-2,获取:标题2-3,获取:用户信息2-4,获取:用户ID2-5,获取:用户头像2-6,获取:文章连接完整代码总结专栏导读 文章名称链接Python爬虫实战(实战篇)—16获取【百度热搜】数据—写入Ecel(附完整…

日常销售数据分析为什么重要?三个维度全面分析日常销售数据

在当今电子商务的浪潮席卷全球的时代&#xff0c;网店如雨后春笋般涌现&#xff0c;并且竞争日趋激烈。在这样一个充满挑战与机遇的环境中&#xff0c;如何洞察市场动向&#xff0c;把握消费者需求&#xff0c;实现销售业绩的稳步增长&#xff0c;成为每一位电商运营者必须面对…