IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot集成EasyExcel实现文件上传 -> 正文阅读

[Java知识库]SpringBoot集成EasyExcel实现文件上传

前言

前段时间刚刚在一个项目中集成EasyExcel实现了数据导出到Excel表中,“产品经理”突然又加了要求:“那个谁,这个项目好像还缺一个批量数据导入的功能,你去写一下”。我:“……😥😤”。生活所迫,只能“自愿”的去完成了这个功能。

image-20220503191202029

EasyExcel官网 – > https://www.yuque.com/easyexcel/doc/easyexcel

1、实体类准备

这里用一个简单的学生Student类进行演示

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @ExcelProperty(value = "学号")
    private String studentId;

    @ExcelProperty(value = "姓名")
    private String studentName;

    @ExcelProperty(value = "年级")
    private String studentGrade;

    @ExcelProperty(value = "专业")
    private String studentMajor;

    @ExcelProperty(value = "班级")
    private String studentClass;
}

2、自定义监听器

根据白嫖来的官网教学,我们还需要自定义一个Excel读的监听器。这里设定了每隔100条存储数据库,然后清理list,这是为了防止数据几万条数据在内存,从而造成OOM(OutOfMemory,内存溢出)。

这里使用到了泛型提高了这个监听器的复用性,也可以将下面的T换成自己指定的一个实体类

@Slf4j
@Setter
@EqualsAndHashCode(callSuper = true)
public class DataListener<T> extends AnalysisEventListener<T> {
    /** 每隔100条存储数据库,然后清理list ,方便内存回收*/
    private static final int BATCH_COUNT = 100;

    /** 需要传递一个service进来对业务逻辑进行操作,即存放数据进数据库中 */
    private IService<T> service;

    /** 每次创建Listener的时候把service传进来 */
    public DataListener(IService<T> service){
        this.service = service;
    }

    /** 缓存的数据 */
    List<T> list = new ArrayList<T>();

    /**
     * @description 读取数据所执行的逻辑
     * @author xBaozi
     * @date 17:14 2022/5/3
     **/
    @Override
    public void invoke(T instance, AnalysisContext analysisContext) {
        log.info("读取到了数据{}", instance);
        list.add(instance);
        // 达到BATCH_COUNT存储一次数据库,防止数据几万条数据在内存造成OOM
        if (list.size() >= BATCH_COUNT){
            this.saveData();
            list.clear();
        }
    }

    /**
     * @description 所有数据读取完毕之后将数据存放到数据库中
     * @author xBaozi
     * @date 17:15 2022/5/3
     **/
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 确保最后遗留的数据也存储到数据库
        this.saveData();
        log.info("所有数据导入成功");
    }

    /**
     * @description 将数据存放到数据库中
     * @author xBaozi
     * @date 17:09 2022/5/3
     **/
    private void saveData() {
        for (T data : list) {
            log.info("{}开始存放数据库……", data);
            try {
                this.service.save(data);
            } catch (Exception e) {
                log.info(e.getMessage());
            }
        }
    }
}

3、编写控制器

在上面的两个准备工作弄好之后,就可以编写控制器对其进行使用实现我们的需求了

/**
 * @description 实现数据批量导入
 * @author xBaozi
 * @date 19:27 2022/5/3
 * @param file  需要导入的文件
 **/
@PostMapping("/upload")
public Result<String>  upload(@RequestParam("files") MultipartFile file) throws IOException {
    // 获得上传文件的名称
    String filename = file.getOriginalFilename();
    // 获取源文件的后缀名
    int index = filename != null ? filename.lastIndexOf(".") : -1;
    // 对没有后缀名的文件进行判断
    if (index < 0) {
        return new Result.error("请选择正确的文件");
    }
    // 截取.点后面的内容,即后缀名
    String suffix = filename.substring(index + 1);
    log.info("获取后缀名为:{}", suffix);
    //判断是否为excel文档
    if (!"xlsx".equals(suffix) && !"xls".equals(suffix)) {
        return new Result.error("只支持Excel文档导入");
    }
    try {
        EasyExcel.read(file.getInputStream(), Student.class, new DataListener<Student>(studentService)).sheet().doRead();
    } catch (Exception e) {
        return new Result.error("导入失败,请重试");
    }
    return new Result.success("批量导入成功");
}

4、结果演示

  1. 根据实体类创建导入数据。

    这里可能有些伙伴有疑问,这里为什么会有一个序号呢?实体类里面没有需要这个属性啊,这是因为在编写实体类的时候是按照value进行匹配,而不是根据index进行匹配的,一次在导入时只会匹配实体类中存在的value。

image-20220503193322699

  1. 使用Postman或Apifox进行测试(这里使用的时Apifox)

image-20220503193857971

5、问题总结

狗子我在写这一个功能时遇到了一个bug,就是在读取Excel文件时,读取到的数据都是null,在排查了好一段时间的问题之后可算是给我找到了问题所在,原来是EasyExcel本身的问题,它与我使用的Lombok产生了冲突。

EasyExcel和Lombok会有一个冲突:当你尝试在用于接收Excel解析数据的Bean上面加上@Accessors(chain = true)注解时,你会发现该Bean接收不到数据,体现在String类型的字段总是为null,int类型的字段总是为0。

因此目前的解决办法就是,把@Accessors(chain = true)这个注解先给删掉,鱼与熊掌不可兼得,只能放弃其一了。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:04:09  更:2022-05-05 11:08:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:42:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码