EasyExcel大大减少了内存占用的原因是,它会一行一行的解析Excel中的数据,从磁盘读到内存,并不会一次性加载到内存中。

一、引入依赖

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

二、创建实体

@Data
public class Stu {
    //设置表头名称
    @ExcelProperty("学生编号")
    private int sno;
    //设置表头名称
    @ExcelProperty("学生姓名")
    private String sname;
}

用来接收从数据库查出来的数据

三、实现写操作

public class WriteTest {
    public static void main(String[] args) {
        String fileName = "D:\\test\\220718\\a.xlsx";
        EasyExcel.write(fileName,Stu.class).sheet("学员信息")
                .doWrite(data());
    }

    //循环设置要添加的数据,最终封装到list集合中
    private static List<Stu> data() {
        List<Stu> list = new ArrayList<Stu>();
        for (int i = 0; i < 10; i++) {
            Stu data = new Stu();
            data.setSno(i);
            data.setSname("张三"+i);
            list.add(data);
        }
        return list;
    }
}

核心代码 就一行

EasyExcel.write(“文件名 or 输入流  or  文件”,"实体类的class").sheet("可以理解为表名").doWrite(数据集合)

四、实现读操作

1、改变实体类,实体类 注解上面要添加index属性   

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

读的时候 index的值就是 要读的Excel表的第几列 列名

2、需要写一个监听器

通过监听器来指定怎么读 (就是指定具体的操作)

public class ExcelListener extends AnalysisEventListener<Stu> {
    @Override
    public void invoke(Stu stu, AnalysisContext analysisContext) {
        System.out.println("stu = " + stu);
    }

    //读取excel表头信息
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头信息:"+headMap);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

关键继承 AnalysisEventListener<自己定义的实体类>   重写两个方法

在invoke方法中 可以将读到的一行数据 存到数据库中   在本文下面会有实例

五、读操作代码

public class ReadTest {
    public static void main(String[] args) {
        String fileName = "D:\\test\\220718\\a.xlsx";
        EasyExcel.read(fileName,Stu.class,new ExcelListener()).sheet().doRead();
    }
}

关键代码就一行

EasyExcel.read("文件名(路径)  or  输入流",实体类的class,new 一个监听器).sheet().doRead();

如此  一个简单的Demo就完成了

下面将在前后端实现业务

========================================================================

一、实现文件导出功能(从数据库查出来 写到本地Excel)

1、首先导入依赖

2、确认VO对象(也就是Excel表头)

3、实现controller

(1)分析接口

*参数:reponse

*返回值:无

(2)实现方法

@ApiOperation(value = "导出")
@GetMapping(value = "/exportData")
public void exportData(HttpServletResponse response){
    dictService.exportData(response);
}

实现service

4、实现service
//导出
@Override
public void exportData(HttpServletResponse response) {
    try {
        //1设置response基础参数
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("数据字典", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
        //2查询所有字典数据
        List<Dict> dictList = baseMapper.selectList(null);

        //3数据对象转型 Dict集合=>DictEeVo集合
        List<DictEeVo> dictEeVoList = new ArrayList<>();
        for (Dict dict : dictList) {
            DictEeVo dictEeVo = new DictEeVo();
            //dictEeVo.setId(dict.getId());
            BeanUtils.copyProperties(dict,dictEeVo);
            dictEeVoList.add(dictEeVo);
        }
        //4调用方法生成文件
        EasyExcel.write(response.getOutputStream(),DictEeVo.class)
                .sheet("数据字典").doWrite(dictEeVoList);
    } catch (IOException e) {
        e.printStackTrace();
        throw new YyghException(20001,"导出失败");
    }
}

实现逻辑:

从数据库查询出所有的数据 存到一个集合中(dictList)

创建出来VO的集合  用来保存将来Excel中的数据

遍历dictList集合   将每一个对象都复制到 VO的集合中

将来把这个VO集合作为写入数据导出到Excel

核心代码

        EasyExcel.write("文件目录 or  输出流",实体类的class).sheet("名字").doWrite();

4、对接前端

(2)添加页面元素

<div class="el-toolbar">

      <div class="el-toolbar-body" style="justify-content: flex-start;">

        <el-button type="text" @click="exportData">

          <i class="fa fa-plus"/> 导出

        </el-button>

      </div>

    </div>

(3)实现js

//导出

    exportData(){

      window.open(`${process.env.VUE_APP_BASE_API}admin/cmn/dict/exportData`)

    }

二、实现文件导入功能

1、创建controller

(1)接口分析

*参数:文件

*返回值:R.ok()

(2)实现方法

@ApiOperation(value = "导入")

@PostMapping("importData")

public R importData(MultipartFile file){

    dictService.importData(file);

    return R.ok();

}

2、创建监听器

@Component

public class DictListener extends AnalysisEventListener<DictEeVo> {

    @Autowired

    private DictMapper dictMapper;



    //手动注入,利用有参构造,new DictListener(dictMapper)

    //private DictMapper dictMapper;



    @Override

    public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {

        Dict dict = new Dict();

        BeanUtils.copyProperties(dictEeVo,dict);

        dict.setIsDeleted(0);

        dictMapper.insert(dict);

    }



    @Override

    public void doAfterAllAnalysed(AnalysisContext analysisContext) {



    }

}

注意使用注解@component的话  就是让spring来管理我们这个监听器了,在service想要使用的话  一定要提前@Autowired自动注入,要不然用不了

复制Excel中的数据的话  使用BeanUtils.copyProperties(dictEeVo,dict);

不要忘了在设置一下is_deleted=0

3、实现service

//导入

@Override

public void importData(MultipartFile file) {

    try {

        InputStream inputStream = file.getInputStream();

        EasyExcel.read(inputStream,DictEeVo.class,dictListener)

                .sheet().doRead();

    } catch (IOException e) {

        e.printStackTrace();

        throw new YyghException(20001,"导入失败");

    }



}

核心代码

EasyExcel.read(输入流,实体类的)

4、对接前端

(1)确认入口

正在上传…重新上传取消

(2)实现方案

正在上传…重新上传取消

(3)添加页面元素

*入口
<div class="el-toolbar">
<div class="el-toolbar-body" style="justify-content: flex-start;">
<el-button type="text" @click="exportData">
<i class="fa fa-plus"/> 导出
</el-button>
<el-button type="text" @click="importData">
<i class="fa fa-plus"/> 导入
</el-button>
</div>
</div>
*对话框
<el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px">
<el-form label-position="right" label-width="170px">
<el-form-item label="文件">
<el-upload
:multiple="false"
:on-success="onUploadSuccess"
:action="BASE_API"
class="upload-demo"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传xls文件,且不超过500kb</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogImportVisible = false">取消</el-button>
</div>
</el-dialog>

(4)实现js

data() {
return {
list: [],//表格数据
dialogImportVisible: false,//对话框是否显示
BASE_API:`${process.env.VUE_APP_BASE_API}admin/cmn/dict/importData`
    };
  },
methods: {
……
//打开上传对话框
importData(){
this.dialogImportVisible = true
    },
//上传成功后操作
onUploadSuccess(response,file){
//1成功提示
this.$message({
type: "success",
message: "上传成功!"
        });
//2关闭对话框
this.dialogImportVisible = false
//3刷新数据
this.getData(1)
    }
}