Springboot整合EasyExcel,实现Excel文件上传

news2024/11/26 11:51:05

一、概念

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。
它能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。EasyExcel是在尽可能节约内存的情况下支持读写百M的Excel。

二、Excel的上传(读Excel)

1.Excel读取的实现方案

实现Springboot结合EasyExcel实现对Excel中数据的读取,并且将读取的数据通过Mybatis-plus保存到Mysql数据库。

2. maven依赖,pom文件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>3.1.1</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.8</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.76</version>
    </dependency>
</dependencies>

3. pom文件,加载xml文件

由于用到MyBatisplus,所以一定不要忘记加下面的这段代码,否则你的mapper是编译不到你的classpath中的。

<build>
    <!-- 由于用到MyBatis,所以一定不要忘记加下面的这段代码,否则你的mapper是编译不到你的classpath中的。-->
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

4. application.yml文件配置mybatis-plus

server:
  port: 80

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/redhorse?serverTimezone=UTC
      username: root
      password: root

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5. 表格和表对应的实体类

既然要读取Excel,同时存入数据库,那么就必然需要对应的表,以及表对应的实体类,而Excel也需要对应的实体类。因为Excel表格会增加一些不必要的字段,而这些字段并不需要存入数据库中,同理数据库实体类同样存在一些字段不是从表格中获取。

5.1 表格对应的实体类

package com.atorientsec.entities;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import lombok.Data;

@Data
public class ExcelAttdnOver {

    @ExcelProperty(index =2)
    private String department;

    @ExcelProperty(index = 0)
    private String name;

    /**
     * 这里用String去接日期,才能格式化,接收年月日的格式
     */
    @ExcelProperty(index = 3)
    @DateTimeFormat(value = "yyyy-MM-dd")
    private String overDate;

    @ExcelProperty(index = 4)
    private Double overHours;

    /**
    *接收百分比的数字
    */
    @ExcelProperty(index = 7)
    @NumberFormat("#.##%")
    private String rate;
}

5.2 数据库对应的实体类 

package com.atorientsec.entities;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

@Data
public class AttdnOver {

    @TableId(type = IdType.AUTO)
    private Integer id;

    private String department;

    private String name;

    private String attdnMonth;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date overDate;

    private Double overHours;


    private Double rate;
}

注释:数据库实体类的overDate是Date类型,而Excel对应的类中overDate是String类型,只有String去接日期才能格式化。

6. 默认一行行的读取excel,所以需要创建excel一行一行的回调监听器

package com.atorientsec.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.atorientsec.entities.AttdnOver;
import com.atorientsec.entities.ExcelAttdnOver;
import com.atorientsec.service.AttdnOverService;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class AttdnDataListener implements ReadListener<ExcelAttdnOver> {
    /**
     * Excel模板的读取类
     * 有个很重要的点,AttdnDataListener不能被Spring管理
     * 要每次读取excel都要new,然后里面用到spring可以构造方法传进去
     * @param excelAttdnOver
     * @param analysisContext
     */

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    private int count = 0;
    /**
     * 缓存的数据,List<AttdnOver>
     */
    private List<AttdnOver> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private AttdnOverService attdnOverService;
    private String month;

    public AttdnDataListener(){

    }
    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     */
    public AttdnDataListener(AttdnOverService attdnOverService,String month){
        this.attdnOverService = attdnOverService;
        this.month = month;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     */
    @Override
    public void invoke(ExcelAttdnOver excelAttdnOver, AnalysisContext analysisContext) {
        log.info("解析到第 {} 条数据:{}", (++count), JSON.toJSONString(excelAttdnOver));
        try {
            //把表格对应的实体类对象转化成数据库表对应的对象
            AttdnOver attdnOver = new AttdnOver();
            attdnOver.setDepartment(excelAttdnOver.getDepartment());
            attdnOver.setName(excelAttdnOver.getName());
            attdnOver.setAttdnMonth(this.month);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse(excelAttdnOver.getOverDate());
            attdnOver.setOverDate(date);
            attdnOver.setOverHours(excelAttdnOver.getOverHours());
            attdnOver.setRate(Double.parseDouble(excelAttdnOver.getRate().replace("%", "")));
            cachedDataList.add(attdnOver);
            if(cachedDataList.size()>=BATCH_COUNT){
                saveData();
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }
    /**
     * 接收表头信息
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        Map<Integer,String> StringMap = ConverterUtils.convertToStringMap(headMap,context);
        Set<Integer> keySet = StringMap.keySet();
        System.out.println("该Excel表头信息是:");
        for(int i=0;i<keySet.size();i++){
            System.out.println("第 "+(i+1)+" 列 = "+StringMap.get(i));
        }
        ReadListener.super.invokeHead(headMap, context);
    }
    */
    /**
     * 所有数据解析完成了 都会来调用
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("表格中的所有数据解析完成!!!");
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
    }

    /**
     * 存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        attdnOverService.batchSave(cachedDataList);
        log.info("存储数据库成功!");
    }
}

7. mapper-继承Mybatis-plus的baseMapper

package com.atorientsec.mapper;

import com.atorientsec.entities.AttdnOver;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AttdnOverMapper extends BaseMapper<AttdnOver> {

}

8. service:Mybatis-plus实现批量插入,并开启事务

package com.atorientsec.service;

import com.atorientsec.entities.AttdnOver;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;

public interface AttdnOverService extends IService<AttdnOver> {

    @Transactional
    boolean batchSave(ArrayList<AttdnOver> attdnOverArrayList);
}
package com.atorientsec.service.impl;

import com.atorientsec.entities.AttdnOver;
import com.atorientsec.mapper.AttdnOverMapper;
import com.atorientsec.service.AttdnOverService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.ArrayList;

@Service
public class AttdnOverServiceImpl extends ServiceImpl<AttdnOverMapper, AttdnOver> implements AttdnOverService {

    public boolean batchSave(ArrayList<AttdnOver> attdnOverArrayList){
        //saveBatch是mybatisplus的批量插入方法
        boolean status = saveBatch(attdnOverArrayList);
        return status;
    }
}

9. Controller:MultipartFile上传文件

EasyExcel读文件

package com.atorientsec.controller;
import com.alibaba.excel.EasyExcel;
import com.atorientsec.entities.ExcelAttdnOver;
import com.atorientsec.listener.AttdnDataListener;
import com.atorientsec.service.AttdnOverService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@RestController
@RequestMapping("/excel")
public class AttdnOverController {
    @Autowired
    private AttdnOverService attdnOverService;

    @PostMapping("/upload/{month}")
    public String upload(MultipartFile file, @PathVariable String month) throws IOException {
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(file.getInputStream(), ExcelAttdnOver.class,new AttdnDataListener(attdnOverService,month))
                .sheet().headRowNumber(1).doRead();
        return "success";
    }
}

三、postman测试文件上传

1. postman设置Header的key=Content-Type,Value=multipart/form-data

2. postman设置Body的key=file,并选择为File,value选择目录

 注释:key=file,此处的file变量与Java代码的Controller中的MultipartFile file变量名保持一样,否则不起作用,读不到文件。

@PostMapping("/upload/{month}") public String upload(MultipartFile file, @PathVariable String month) {}

 

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

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

相关文章

Spring Batch 批处理-作业增量参数

引言 接着上篇&#xff1a;Spring Batch 批处理-作业参数校验&#xff0c;了解作业参数校验后&#xff0c;本篇就来了解一下Spirng Batch 作业增量参数。 作业增量参数 不知道大家发现了没有&#xff0c;每次运行作业时&#xff0c;都改动作业名字&#xff0c;或者改动作业的…

php就业招聘系统mysql数据库web结构计算机软件工程网页wamp

一、源码特点 PHP就业招聘系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环 境为PHP APACHE&#xff0c;数据库为mysql5.0&#xff0c;使用php语言开发。 php就…

【C00098】基于SSM的校园疫情防控管理系统——可视化大屏

基于SSM的校园疫情防控管理系统——可视化大屏项目简介项目获取开发环境项目技术运行截图注意&#xff1a;2022年最新款&#xff0c;全网唯一&#xff01;&#xff01; 先到先得&#xff01;&#xff01; 项目简介 基于ssm框架开发的校园疫情防控管理系统共分为四个角色&…

非零基础自学Golang 第6章 Go语言内置容器 6.3 映射

非零基础自学Golang 文章目录非零基础自学Golang第6章 Go语言内置容器6.3 映射6.3.1 声明映射6.3.2 初始化映射6.3.3 遍历映射6.3.4 从映射中删除键值对第6章 Go语言内置容器 6.3 映射 映射&#xff08;map&#xff09;是一种无序的键值对的集合&#xff0c;map的键类似于索引…

聚观早报 | 特斯拉上线Steam平台;苹果CEO库克访问索尼

今日要闻&#xff1a;特斯拉上线Steam平台&#xff1b;苹果CEO库克访问索尼&#xff1b;三星向华为转让多项专利&#xff1b;NASA将在太空调查水资源&#xff1b;传推特拖欠总部租金数周特斯拉上线Steam平台 12 月 14 日消息&#xff0c;特斯拉已经为其ModelS和ModelX电动汽车上…

建筑建材企业如何高效进行合同签署?数商云B2B系统推动企业合同签约规范化

建筑建材行业作为重要的材料工业&#xff0c;其主要产品包括建筑材料及制品、非金属矿及制品、无机非金属新材料三大门类&#xff0c;现广泛应用于建筑、军工、环保、高新技术产业和人民生活等领域&#xff0c;占国民生产总值的20&#xff05;左右&#xff0c;但目前建筑建材行…

开关电源环路稳定性分析(08)——电流型补偿网络

大家好&#xff0c;这里是大话硬件。 在上一节分析了3种类型的电压型补偿网络&#xff0c;当然前面的内容还达不到环路补偿的要求&#xff0c;在后面会有内容对其进行补充。我们先把整个开关电源的闭环控制所需要基本知识点过一遍&#xff0c;再针对性的分析。 这一讲我们来分…

源码角度详解Java中的优先队列PriorityQueue(堆的实现)

if (e null) throw new NullPointerException(); modCount; int i size; if (i > queue.length) grow(i 1); size i 1; if (i 0) queue[0] e; else siftUp(i, e); return true; } 在offer方法中&#xff0c;我们会先判断数组是否需要扩容&#xff0c;然…

DataX 原理解析和性能优化

datax简介 datax是阿里开源的用于异构数据源之间的同步工具&#xff0c;由于其精巧的设计和抽象&#xff0c;数据同步效率极高&#xff0c;在很多公司数据部门都有广泛的使用。本司基于datax在阿里云普通版的rds服务器上实现了通过公网&#xff0c;从阿里云杭州到美国西部俄勒…

一种基于Spark深度随机森林的网络入侵检测模型

一种基于Spark深度随机森林的网络入侵检测模型学习目标学习内容目前存在的不足为了解决这个问题特征分片深度并行随机森林Deep Parallel Random Forest(DPRF)投票策略Spark 上的并行化高复用缓存计算每个RDD的权重分层替换模型评估局限性参考论文申明&#xff1a; 未经许可&…

ASP.NET Core Web API 学习笔记

目录 一、Demo 1. 创建项目 2. 启动项目 3. 编写 api demo 二、C# .NET WEB 程序结构 一、Demo 1. 创建项目 创建的项目结构如下: Properties 配置文件&#xff0c;存放了一些 .json 文件用于配置 ASP.NET Core 项目 Propertics/launchSettings.json 启动配置文件&…

以岭药业:连花清瘟火爆背后,数字化重塑人力资源管理

近日&#xff0c;随着疫情防控政策“国十条”发布&#xff0c;新冠防疫政策逐步进入后防疫时代&#xff0c;每个人要做自己健康的“第一责任人”。而连花清瘟作为中医药治疗新冠肺炎筛选出的“三药三方”之一&#xff0c;也成为新疫情防控模式下的家庭常备药。连花清瘟自上市以…

怎么将图片内容转换成文字?这两种方法可以轻松实现

如何将图片的内容转换成文字呢&#xff1f;大家在使用图片文件的时候&#xff0c;遇到那种图片中包含一些有用的文字信息时&#xff0c;没有办法直接复制下来使用&#xff0c;只能对照着图片将文字信息给记录下来&#xff0c;这样会很耗费我们的时间。其实是有方法能够直接将图…

Python学习中常见的几个报错,看你踩雷没

前言 嗨嗨 今天给大家统计一下, 在学习Python中遇到的常见报错, 不一定会很全面, 但是应该会持续更新, 有用的话, 记得收藏哦~ 下面我会总结遇到的报错截图, 给出解决办法, 如果有需要补充的报错, 或者你解决不了的报错, 欢迎来文章最下方QQ群里面找我~ 1. 模块未安装 (Mod…

面试中这样介绍自己的项目经验,轻松拿Offer

面试时7分靠能力&#xff0c;3分靠技能&#xff0c;而刚开始时的介绍项目又是技能中的重中之重&#xff0c;所以本文将从“介绍”和“引导”两大层面告诉大家如何准备面试时的项目介绍。 在面试时&#xff0c;经过寒暄后&#xff0c;一般面试官会让介绍项目经验 。常见的问法是…

Go C 编程 第4课 变色魔法(魔法学院的奇幻之旅 有Go C编程绘图)

慧通教育 慧通教育 34.画彩色旗帜 (魔法学院第4课)--2022.12.15 登录 35.画转动的方形 (魔法学院第4课) 登录 36.画wifi信号 (魔法学院第4课) 登录 888.哪个大&#xff1f; (课程6&#xff09; 难度&#xff1a;1 登录 889.余数大小 (课程6) 难度&#xff1a;1 登录 适合…

Java学习—网络编程

网络编程 目的&#xff1a;数据交换、通信 1. 网络通信的要素 通信双方地址&#xff08;IP端口号&#xff09;网络通信协议 Java万物皆对象 2. IP地址 IP地址的类&#xff1a;InetAddress 唯一定位一台网络上的计算机127.0.0.1 本机地址 package com.xiaozhang.lesson01;…

第二证券|钠电池三种技术路线谁更将率先取代锂电池?

锂电网讯&#xff1a;近段时刻&#xff0c;钠离子电池遭到资本商场重视&#xff0c;不少公司公布了在钠电池范畴的最新进展。11月29日&#xff0c;中科海钠(阜阳)全球首条GWh级钠离子电池出产线产品下线。中科海钠总经理李树军透露&#xff0c;阜阳产线计划在下一年扩产至3GWh-…

大数据学习:shell基础(2)

文章目录tail命令选项参数任务一&#xff1a;显示文件最后4行内容任务二&#xff1a;显示文件最后4个字符内容任务三&#xff1a;显示文件修改行sort命令选项参数任务一&#xff1a;对文件按行排序任务二&#xff1a;对文件按第4节排序cut命令参数说明任务一&#xff1a;提取ip…

想要查询数据表中的前几名该怎么实现?看这篇文章吧

一. 需求分析 我们在学习数据库查询时&#xff0c;经常会遇到关于分组和聚合函数的查询&#xff0c;比如查询每门课程的最高分&#xff0c;每位同学的平均分&#xff0c;其实这些都是比较一般的问题。但如果遇到查询每门课程成绩的前几名问题&#xff0c;就会变的很棘手&#…