Spring Boot集成EasyExcel实现excel导入导出操作

文章目录

  • Spring Boot集成EasyExcel实现excel导入导出操作
    • 0 简要说明
    • 简单使用
      • 读操作
        • excel源文件
        • 实体类
        • 监听器
        • 业务代码
      • 写操作
        • *实体类*
        • excel示例
        • 业务代码
        • 根据参数指定列导出
        • 指定哪几列导出
        • 复杂头导出
      • 关于数值型,日期型,浮点型数据解决方案
        • 实体类接收字符串获取

Easy Excel 官网

Spring Boot集成EasyExcel实现excel导入导出操作

0 简要说明

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。

Spring Boot集成EasyExcel实现excel导入导出操作_第1张图片

简单使用

引入依赖

        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>easyexcelartifactId>
            <version>3.1.1version>
        dependency>

读操作

excel源文件

Spring Boot集成EasyExcel实现excel导入导出操作_第2张图片

实体类


@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TempData {

    private Long id;

    /**
     * 用户名
     */

    private String userName;
    /**
     * 生日
     */

    private Date birthday;
    /**
     * 性别
     */

    private String sex;
    /**
     * 地址
     */

    private String address;

}

监听器

在这里插入图片描述

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去

package com.geekmice.springbootselfexercise;

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.geekmice.springbootselfexercise.dao.UserDao;
import com.geekmice.springbootselfexercise.domain.TempData;
import com.geekmice.springbootselfexercise.service.UserService;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @BelongsProject: spring-boot-self-exercise
 * @BelongsPackage: com.geekmice.springbootselfexercise
 * @Author: pingmingbo
 * @CreateTime: 2023-08-07  10:19
 * @Description: easyexcel读操作监听器
 * @Version: 1.0
 */
@Slf4j
public class UserListener  implements ReadListener<TempData> {
    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<TempData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private UserService userService;

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param demoDAO
     */
    public UserListener(UserService userService) {
        this.userService = userService;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(TempData data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        cachedDataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        // this.s(cachedDataList);
        // userService.saveBatch(cachedDataList);
        log.info("存储数据库成功!");
    }
}

业务代码

//userService业务service,也可以是dao,如果是多个mapper或者service,通过构造方法或者set方法传递
也可以使用工具类getBean获取,不需要通过构造方法,这种方式主要是多个mapper或者service进行业务操作

  @Override
    public void uploadFileByEasyExcel(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), TempData.class, new UserListener(userService)).sheet().doRead();
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
    }

写操作

实体类

名称 默认值 备注
value 用于匹配excel中的头,必须全匹配,如果有多行头,会匹配最后一行头
order Integer.MAX_VALUE 优先级高于value,会根据order的顺序来匹配实体和excel中数据的顺序
index -1 优先级高于valueorder,会根据index直接指定到excel中具体的哪一列
converter 自动选择 指定当前字段用什么转换器,默认会自动选择。读的情况下只要实现com.alibaba.excel.converters.Converter#convertToJavaData(com.alibaba.excel.converters.ReadConverterContext) 方法即可

ExcelIgnore

默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

ExcelIgnore

默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

package com.geekmice.springbootselfexercise.domain;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @BelongsProject: spring-boot-self-exercise
 * @BelongsPackage: com.geekmice.springbootselfexercise.domain
 * @Author: pingmingbo
 * @CreateTime: 2023-08-07  09:53
 * @Description: TODO
 * @Version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TempData {
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private Long id;

    /**
     * 用户名
     */
    @ExcelProperty(value = "用户名")
    private String userName;
    /**
     * 生日
     */
    @ExcelProperty(value ="生日",format = "yyyy-MM-dd")
    private Date birthday;
    /**
     * 性别
     */
    @ExcelProperty(value ="性别")
    private String sex;
    /**
     * 地址
     */
    @ExcelProperty(value = "地址")
    private String address;

}

excel示例

Spring Boot集成EasyExcel实现excel导入导出操作_第3张图片

业务代码

    @Override
    public void downloadFileByEasyExcel() {
         EasyExcel.write("D:\\easyexcel.xls", TempData.class)
                 .sheet()
                 .doWrite(data());
                     }

根据参数指定列导出

Spring Boot集成EasyExcel实现excel导入导出操作_第4张图片

    /**
     * 根据参数指定列导出
     */
    @Test
    public void t2(){
        List<String> list = new ArrayList(16);
        list.add("sex");
        list.add("userName");
        EasyExcel.write("D://easyexcel_by_columns.xlsx", TempData.class)
                .excludeColumnFieldNames(null)
                .sheet()
                .includeColumnFieldNames(list)
                .doWrite(data());
        log.info("导出结束 [{}]", DateFormatUtils.format(new Date(), DateUtils.DATE_FORMAT_19));
    }

指定哪几列导出

使用index属性,index=2空余出来,这样一来第二列为空
Spring Boot集成EasyExcel实现excel导入导出操作_第5张图片
Spring Boot集成EasyExcel实现excel导入导出操作_第6张图片

复杂头导出

Spring Boot集成EasyExcel实现excel导入导出操作_第7张图片
Spring Boot集成EasyExcel实现excel导入导出操作_第8张图片

    /**
     * 用户名
     */
    @ExcelProperty(value = {"父级","用户名"},index = 0)
    private String userName;
    /**
     * 生日
     */
    @ExcelProperty(value ={"父级","生日"},format = "yyyy-MM-dd",index = 1)
    private Date birthday;
    /**
     * 性别
     */
    @ExcelProperty(value ={"父级","性别"},index = 2)
    private String sex;
    /**
  List list = new ArrayList(16);
        list.add("sex");
        list.add("userName");
        list.add("birthday");
        EasyExcel.write("D://easyexcel_by_columns.xlsx", TempData.class)
                .excludeColumnFieldNames(null)
                .sheet()
                .includeColumnFieldNames(list)
                .doWrite(data());
        log.info("导出结束 [{}]", DateFormatUtils.format(new Date(), DateUtils.DATE_FORMAT_19));

关于数值型,日期型,浮点型数据解决方案

Spring Boot集成EasyExcel实现excel导入导出操作_第9张图片

实体类接收字符串获取

package com.geekmice.springbootselfexercise.domain;

import cn.afterturn.easypoi.excel.annotation.Excel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import com.geekmice.springbootselfexercise.utils.CustomStringStringConverter;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @BelongsProject: spring-boot-self-exercise
 * @BelongsPackage: com.geekmice.springbootselfexercise.domain
 * @Author: pingmingbo
 * @CreateTime: 2023-08-07  14:04
 * @Description: TODO
 * @Version: 1.0
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ConverterData {
    /**
     * 生日
     */
    @ExcelProperty(value = "生日")
    private String birthday;
    /**
     * 性别
     */
    @ExcelProperty(value = "性别")
    private String sex;

    /**
     * 分数
     */
    @ExcelProperty(value = "分数")
    private String score;
}

你可能感兴趣的:(问题汇总,spring,boot,excel,后端)