您现在的位置是:首页 > 正文

使用EasyExcel实现上传解析与导出下载

2024-01-30 20:27:57阅读 0

本文分享Java后台使用EasyExcel解析上传excel文件并导出下载功能。

        使用指南:https://www.yuque.com/easyexcel/doc/easyexcel

        环境:jdk1.8、SpringBoot 2.2.2

        准备工作:

                pom.xml 添加依赖jar包 com.alibaba.easyexcel 2.1.6 

                https://mvnrepository.com/artifact/com.alibaba/easyexcel

使用EasyExcel导入文件:

1、为准备接收的Excel文件创建对应实体类:

import com.alibaba.excel.annotation.ExcelProperty;

public class ExcelMeterData implements Comparable<ExcelMeterData>{
    @ExcelProperty("数据日期")
    private String inforDate;
    @ExcelProperty("A相电流")
    private String phaseACurrent;
    @ExcelProperty("B相电流")
    private String phaseBCurrent;
    @ExcelProperty("C相电流")
    private String phaseCCurrent;
    
    //...
}

        使用@ExcelProperty注解是为了从Excel文件中对应的列标题提取数据并组装成ExcelMeterData对象,Excel中的每一行数据对应一个ExcelMeterData对象。

2、Controller层接收文件:

@PostMapping("/recieveFile")
@ResponseBody
public Result recieveTerminalFile(@RequestParam("uploadFiles") MultipartFile[] uploadFiles) {
    System.out.println("上传文件数量"+uploadFiles.length);
    for(int i = 0;i<uploadFiles.length;i++){
        System.out.println(uploadFiles[i].getOriginalFilename());
    }
    //...
}

3、处理文件 

使用EasyExcel处理文件我了解的有两种方式。

        第一种:一次性全部读取存储到集合中:

List<ExcelMeterData> allList = new ArrayList<>();
//从多个文件中提取数据并进行解析,都存储到allList集合中。
for(int i=0;i<uploadFiles.length;i++){
    try{
        List<ExcelMeterData> list = EasyExcel.read(uploadFiles[i].getInputStream()).head(ExcelMeterData.class).sheet().doReadSync();
        allList.addAll(list);
    }catch (Exception e){
        e.printStackTrace();
    }
}

        第二种:读一条处理一条

                第一步:创建ExcelDataListener

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
public class ExcelDataListener extends AnalysisEventListener {
    private static final int BATCH_COUNT = 3000; //读取暂存数量上限
    List<MeterData> list = new ArrayList<MeterData>();
    @Override
    public void invoke(Object object, AnalysisContext analysisContext) {
        //每读取一条数据,invoke会执行一次
        JSONObject jsonObject = (JSONObject) JSON.toJSON(object);
        //使用fastjson依赖包
        String dataDate = jsonObject.getString("inforDate");
        String AUserCurrent = jsonObject.getString("phaseACurrent");
        String BUserCurrent = jsonObject.getString("phaseBCurrent");
        String CUserCurrent = jsonObject.getString("phaseCCurrent");
        //get方法与上文ExcelMeterData中的属性相对应
        
        //获得参数信息,组装对象
        MeterData temp = new MeterData(...);
        //在此先存储到集合中,一个对象一存储数据库不合适,使用批量存储
        list.add(temp);
        if(list.size()>=BATCH_COUNT){
            //...存储方法
            list.clear(); //存储完成清空集合
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        //读取完成会执行的方法
        //集合中对象数量不满BATCH_COUNT,把剩余的对象存储起来
        //...存储方法
        list.clear();
    }
    //...
}

                第二步:使用ExcelDataListener进行解析

EasyExcel.read(uploadFiles[i].getInputStream(),ExcelMeterData.class,new ExcelDataListener().sheet().doRead();

使用EasyExcel导出文件

        创建导出对象对应的实体类 ExcelHistoryData

public class ExcelHistoryData {
    @ExcelProperty("编号")
    private long id;
    @ExcelProperty("时间点")
    private String xPoint;
    @ExcelProperty("电流数据")
    private String yPoint;
    @ExcelProperty("电流类型")
    private String yType;
    @ExcelProperty("终端地址")
    private String terminalAddr;
    @ExcelProperty("表计资产号")
    private String meterBarcode;
    @ExcelProperty("相线类型")
    private String phaseType;
    @ExcelProperty("数据点类型")
    private String pointType;
    //...省略构造和get set方法
}

        @ExcelProperty注解是导出Excel文件的列标题,属性与实体类相同,注解其实直接加在数据库对应实体类上就可以。

        将文件流写入到httpServletResponse中

@GetMapping("/exportHistoryData")
@ResponseBody
public Result exportHistoryData(HttpServletResponse httpServletResponse, @RequestParam("userCode") String userCode){
    List<HistoryData> list = new ArrayList<>();
    //...查库并赋值给list集合
    if(list.size()!=0){
        String fileName = userCode;
        ServletOutputStream out = null;
        try {
            out = httpServletResponse.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        ExcelWriterBuilder builder = new ExcelWriterBuilder();
        builder.file(out).excelType(ExcelTypeEnum.XLSX).autoCloseStream(true).head(ExcelHistoryData.class);
        ExcelWriter writer = builder.build();
        WriteSheet sheet = EasyExcel.writerSheet().build();
        writer.write(list,sheet);
        httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        try {
            httpServletResponse.setHeader("content-Disposition","attachment;filename="+ URLEncoder.encode(fileName+".xlsx","UTF-8"));
            httpServletResponse.setHeader("Pragma", "public");
            httpServletResponse.setHeader("Cache-Control", "no-store");
            httpServletResponse.addHeader("Cache-Control", "max-age=0");
            out.flush();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.finish();
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ResultUtil.success();
    }

前端上传和导出下载功能:

        上传:

        

        下载:

网站文章

  • AF_INET 和PF_INET区别;AF_LOCAL PF_LOCAL 区别.

    从字面理解: AF_INET = Address Format, Internet = IP Addresses PF_INET = Packet Format, Internet = IP, TCP/IP or UDP 从linux的定义来看,两者无区别。 /* Supported address families. */#define AF_UNSPEC 0#define AF_UNI...

    2024-01-30 20:27:55
  • springboot和vue前后端分离部署微信公众号

    网上已经有很多vue打包后放到resources目录的解决方案,也有vue前台微信插件然后请求后台方案,我就不Ctrl+C加Ctrl+V了。说说我的分离部署的解决方案:nginx反响代理后台路径,后端验证通过后跳转前端路径通过response.sendRedirect("前台的路径"),如/api,原来http://localhost:8080/user/login,变成http://xx...

    2024-01-30 20:27:49
  • 负数在计算机中怎样存储

    负数在计算机中怎样存储

    一、什么是原码、反码、补码?分为:正数 和负数(包括正浮点数,和负浮点数)规定最高位位符号位正数为0,负数为1(原因下文解释)原码:10进制转换成2进制是原码,只不过正数的原码是本身符号位为0,负数的原码符号位为1(以下篇幅均以单字节为例:10进制1的原码是0000 0001,10进制-1的原码是1000 0001)。反码: 正数的反码是本身,负数的反码是负数的原码0变为1,1变为0 &...

    2024-01-30 20:27:16
  • php create_function()产生的漏洞

    create_function(‘参数’,’函数体’):官方example:

    2024-01-30 20:27:10
  • leetcode解题思路分析(一百二十三)1018 - 1024 题

    代码】leetcode解题思路分析(一百二十三)1018-1024题。

    2024-01-30 20:26:36
  • 新书推荐 |《工业机器人系统及应用》

    新书推荐 |《工业机器人系统及应用》

    新书推荐《工业机器人系统及应用》点击上图了解及购买本书由机器人领域的两位技术专家和资深教授联袂撰写,聚焦于工业机器人,涵盖其组成结构、电气控制及实践应用,为机器人的设计、生产、布置、操作...

    2024-01-30 20:26:29
  • Linux/Ubuntu下使用命令开放端口的办法

    Linux/Ubuntu下使用命令开放端口的办法

    一.安装iptables:一般情况下,Ubuntu安装好的时候,iptables会被安装上。如果没有,执行下面命令$ sudo apt-get update$ sudo apt-get install iptables二.安装完后,开放8000端口,使用下面命令:$ sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT三.保存规...

    2024-01-30 20:26:02
  • js中两个等号(==)和三个等号(===)的区别

    1. &quot;==&quot;表示:equality -&gt; 等同 的意思,&quot;==&quot;使用两个等号时,如果两边值的类型不同的时候,是要先先进行类型转换后,才能做比较。2. &quot;===&quot;表示:identity -&gt; 恒等 的意思,&quot;===&quot;使用三个等号时,是不需要做类型转换的,如果两边值的类型不同,就表示一定是不等的。...

    2024-01-30 20:25:55
  • skywalking系列-nacos配置

    动态配置nacos配置 可动态配置skywalking服务端配置信息 key==Nacos DataId在开启nacos为 configuration配置中心时必须配置以下key,如果没有以下配置oa...

    2024-01-30 20:25:48
  • 微信小程序分页加载数据~上拉加载更多~小程序云数据库的分页加载

    我们在开发小程序时,一个列表里难免会有很多条数据,比如我们一个列表有1000条数据,我们一下加载出来,而不做分页,将会严重影响性能。所以这一节,我们来讲讲小程序分页加载数据的实现。老规矩,先看效果图可以看到我们每页显示10条数据,当滑动到底部时,会加载第二页的数据,再往下滑动,就加载第三页的数据。由于我们一共21条数据,所以第三页加载完以后,会有一个“已加载全部数据”的提示。本节知识点...

    2024-01-30 20:25:42