EasyExcel配置与应用

Excel导入导出的应用场景

1 、数据导入:减轻录入工作量
2 、数据导出:统计信息归档
3 、数据传输:异构系统之间数据传输

EasyExcel特点

  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.
  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
  • EasyExcel采用一行一行的解析模式(读),并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)

EayExcel的底层是直接和磁盘交互,并且一行一行读取表格,内存占用很小,下方有测试结果.

EasyExcel配置

pom中引入xml相关依赖

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

对照excel列属性创建实体类

设置表头和添加的数据字段和get,set方法

@Data
public class DemoData {
    //设置excel表头名称,index第几列
    @ExcelProperty(value = "学生编号",index = 0)
    private Integer sno;
    //设置表头名称
    @ExcelProperty(value = "学生姓名",index = 1)
    private String sname;
}

实现写操作(将数据写入excel)

请添加图片描述

        //实现excel写的操作
        //1 设置写入文件夹地址和excel文件名称
        String filename = "F:\\write.xlsx";
        //2 调用easyexcel里面的方法实现写操作
        //write方法两个参数:第一个参数文件路径名称,第二个参数实体类.class=实体类的路径,sheet是excel文件的下标,文件流会自动关闭
        EasyExcel.write(filename,DemoData.class).sheet("学生列表").doWrite(getData());

实现读操作(读出excel数据)

  • 读excel操作,主要是在设置的监听类中的invoke函数中的处理实体类参数,实现读数据和处理数据等功能(使用传入的service参数进行处理
  • 读取excel内容,一行一行读取excel内容,不读取表头,然后使用invoke函数通过实体类参数实现一行一行处理(若excel有多行数据,invoke会被调用多次,传递多次实体类参数(存储每行内容))
  • 因为读excel监听类AnalysisEventListener<实体类>不能交给spring进行管理(无法使用注解),需要自己new,不能注入其他对象,不能实现数据库操作,因为不能注入service,mapper等等,当然也可以直接自己用最原始的jdbc办法
  • 实例化监听类的时候将service作为构造函数参数传递
    new SubjectExcelListener(subjectService))
    请添加图片描述

操作代码

    //添加课程分类
    //获取上传过来文件,把文件内容读取出来
    @PostMapping("addSubject")
    public R addSubject(MultipartFile file) {
        //上传过来excel文件
        subjectService.saveSubject(file,subjectService);
        return R.ok();
    }
  try {
            //文件输入流
            InputStream in = file.getInputStream();
            //调用方法进行读取传入的excel和service对象
            EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(subjectService)).sheet().doRead();
        }catch(Exception e){
            e.printStackTrace();
        }

监听类

package com.qlugcl.eduservice.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qlugcl.eduservice.entity.EduSubject;
import com.qlugcl.eduservice.entity.excel.SubjectData;
import com.qlugcl.eduservice.service.EduSubjectService;
import com.qlugcl.servicebase.exceptionhandler.GCLException;

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

    //因为SubjectExcelListener不能交给spring进行管理(无法使用注解),需要自己new,不能注入其他对象
    //不能实现数据库操作,因为不能注入service,mapper等等,带参构造方法,当然也可以直接自己用最原始jdbc的办法
    public EduSubjectService subjectService;
    public SubjectExcelListener() {}
//    此处通过传递service参数,从而实现对于数据库的操作
    public SubjectExcelListener(EduSubjectService subjectService) {
        this.subjectService = subjectService;
    }
    //读取excel内容,一行一行进行读取
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if(subjectData == null) {
            throw new GCLException(20001,"文件数据为空");
        }

        //一行一行读取,每次读取有两个值,第一个值一级分类,第二个值二级分类
        //判断一级分类是否重复,是否存在
        EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
        if(existOneSubject == null) { //没有相同一级分类,进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0");
            existOneSubject.setTitle(subjectData.getOneSubjectName());//一级分类名称
            subjectService.save(existOneSubject);
        }

        //获取一级分类id值
        String pid = existOneSubject.getId();

        //添加二级分类
        //判断二级分类是否重复,是否存在
        EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
        if(existTwoSubject == null) {
            existTwoSubject = new EduSubject();
            existTwoSubject.setParentId(pid);
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());//二级分类名称
            subjectService.save(existTwoSubject);
        }
    }

    //判断一级分类不能重复添加
    private EduSubject existOneSubject(EduSubjectService subjectService,String name) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title",name);
        wrapper.eq("parent_id","0");
        EduSubject oneSubject = subjectService.getOne(wrapper);
        return oneSubject;
    }

    //判断二级分类不能重复添加
    private EduSubject existTwoSubject(EduSubjectService subjectService, String name, String pid) {
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title",name);
        wrapper.eq("parent_id",pid);
        EduSubject twoSubject = subjectService.getOne(wrapper);
        return twoSubject;
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }
}


EasyExcel读excel应用

请添加图片描述
读excel操作,主要是在设置的监听类中的invoke函数中实现读数据和处理数据等功能

package com.createcode.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.Date;
import java.util.Map;

//excel读的监听器,一旦产生读excel操作,那么就会触发读的对应配置
public class ExcelListener extends AnalysisEventListener<DemoData> {
    //一行一行读取excel内容,不读取表头,在invoke函数中实现对于读取出来的数据进行操作
    @Override
    public void invoke(DemoData data, AnalysisContext analysisContext) {
        System.out.println("****"+data+""+new Date());
        try {
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();

        }
    }
    //读取表头内容
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头:"+headMap);
    }
    //读取完成之后
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) { }
}




前端VUE界面

<template>
  <div class="app-container">
    <el-form label-width="120px">
      <el-form-item label="信息描述">
        <el-tag type="info">excel模版说明</el-tag>
        <el-tag>
          <i class="el-icon-download"/>
          <a :href="'/static/01.xlsx'">点击下载模版</a>
        </el-tag>

      </el-form-item>

      <el-form-item label="选择Excel">
        <el-upload
          ref="upload"
          :auto-upload="false"
          :on-success="fileUploadSuccess"
          :on-error="fileUploadError"
          :disabled="importBtnDisabled"
          :limit="1"
          :action="BASE_API+'/eduservice/subject/addSubject'"
          name="file"
          accept="application/vnd.ms-excel">
          <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
          <el-button
            :loading="loading"
            style="margin-left: 10px;"
            size="small"
            type="success"
            @click="submitUpload">上传到服务器</el-button>
        </el-upload>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
    data() {
        return {
            BASE_API: process.env.BASE_API, // 接口API地址
            importBtnDisabled: false, // 按钮是否禁用,
            loading: false
        }
    },
    created() {

    },
    methods:{
        //点击按钮上传文件到接口里面
        submitUpload() {
            this.importBtnDisabled = true
            this.loading = true
             if(this.$refs.upload.uploadFiles.length != 0)
            // js: document.getElementById("upload").submit()
            	this.$refs.upload.submit()
             	else {
              		 alert("文件不可为空")
              		 //重新加载
              		 location.reload()
               }
        },
        //上传成功
        fileUploadSuccess(response) {
            //提示信息
            this.loading = false
            this.$message({
                type: 'success',
                message: '添加课程分类成功'
            })
            //跳转课程分类列表
            //路由跳转
            this.$router.push({path:'/subject/list'})
        },
        //上传失败
        fileUploadError() {
            this.loading = false
            this.$message({
                type: 'error',
                message: '添加课程分类失败'
            })
        }
    }
}
</script>

总结

读操作:读出excel数据在监听类的invoke函数中进行处理逐行实体类参数并存入数据库等操作

如图所示:easyexcel就是处理excel和数据库之间数据交互,格式转化的
在这里插入图片描述
在这里插入图片描述
注意 invoke读取excel的时候第一行是默认不读取的(表头不读取)
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值