SpringBoot集成EasyExcel的应用场景分析

作者:zhz小白弟弟 时间:2023-01-09 07:47:45 

1、介绍

官网地址:https://www.yuque.com/easyexcel
特点:

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

2、应用场景

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

3、要实现的效果

sql


CREATE TABLE `edu_subject` (
 `id` char(19) NOT NULL COMMENT '课程类别ID',
 `title` varchar(10) NOT NULL COMMENT '类别名称',
 `parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '父ID',
 `sort` int unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',
 `gmt_create` datetime NOT NULL COMMENT '创建时间',
 `gmt_modified` datetime NOT NULL COMMENT '更新时间',
 PRIMARY KEY (`id`),
 KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='课程科目';

SpringBoot集成EasyExcel的应用场景分析

转成->

SpringBoot集成EasyExcel的应用场景分析

3、使用

3.1、pom依赖导入

温馨提示:以下版本不能更换,换了可能会不行


<dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>easyexcel</artifactId>
           <version>2.1.1</version>
       </dependency>
<!--xls-->
       <dependency>
           <groupId>org.apache.poi</groupId>
           <artifactId>poi</artifactId>
           <version>3.17</version>
       </dependency>

<dependency>
           <groupId>org.apache.poi</groupId>
           <artifactId>poi-ooxml</artifactId>
           <version>3.17</version>
       </dependency>

3.2、controller


package com.zhz.serviceedu.controller;

import com.zhz.common.utils.R;
import com.zhz.serviceedu.service.EduSubjectService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
* <p>
* 课程科目 前端控制器
* </p>
*
* @author zhz
* @since 2021-07-03
*/
@RestController
@RequestMapping("/eduservice/subject")
@CrossOrigin
@Api(tags = "课程科目")
public class EduSubjectController {

@Autowired
   private EduSubjectService eduSubjectService;

/**
    * 添加课程分类,获取上传过来的文件,把文件内容读取出来
    */
   @PostMapping("/addSubject")
   @ApiOperation(value = "添加课程分类,获取上传过来的文件,把文件内容读取出来")
   public R addSubject(MultipartFile file){
       //上传过来的excel文件
       eduSubjectService.saveSubject(file,eduSubjectService);
       return R.ok();
   }
}

3.3、interface


package com.zhz.serviceedu.service;

import com.zhz.serviceedu.entity.EduSubject;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;

/**
* <p>
* 课程科目 服务类
* </p>
*
* @author zhz
* @since 2021-07-03
*/
public interface EduSubjectService extends IService<EduSubject> {

/**
    * 添加课程信息
    *
    * @author zhz
    * @date 2021/07/02 02:18
    * @param file 文件对象,用于获取excel文件
    * @param eduSubjectService 方便 * 部分引用
    */
   void saveSubject(MultipartFile file, EduSubjectService eduSubjectService);
}

3.4、impl


package com.zhz.serviceedu.service.impl;

import com.alibaba.excel.EasyExcel;
import com.zhz.serviceedu.entity.EduSubject;
import com.zhz.serviceedu.entity.excel.SubjectData;
import com.zhz.serviceedu.listener.SubjectExcelListener;
import com.zhz.serviceedu.mapper.EduSubjectMapper;
import com.zhz.serviceedu.service.EduSubjectService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

/**
* <p>
* 课程科目 服务实现类
* </p>
*
* @author zhz
* @since 2021-07-03
*/
@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {

/**
    * 添加课程信息
    *
    * @param file 文件对象,用于获取excel文件
    * @param eduSubjectService
    * @author zhz
    * @date 2021/07/02 02:18
    */
   @Override
   public void saveSubject(MultipartFile file, EduSubjectService eduSubjectService) {
       try {
           //文件输入流
           InputStream in = file.getInputStream();
           //调用方法进行读取
           EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(eduSubjectService)).sheet().doRead();
       }catch (Exception e){
           e.printStackTrace();
       }
   }
}

3.5、listener


package com.zhz.serviceedu.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhz.servicebase.execptionhandler.GuliException;
import com.zhz.serviceedu.entity.EduSubject;
import com.zhz.serviceedu.entity.excel.SubjectData;
import com.zhz.serviceedu.service.EduSubjectService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
* @author zhouhengzhe
* @Description: excel *
* @date 2021/7/3上午2:28
*/
@Slf4j
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

/**
    * 创建有参数构造,传递subjectService用于操作数据库
    * 因为SubjectExcelListener不能交给spring去管理,所以需要自己new,不能注入对象
    * 此处一定要是public,不然永远获取不到对象
    */
   public EduSubjectService eduSubjectService;
   public SubjectExcelListener() {
   }
   public SubjectExcelListener(EduSubjectService eduSubjectService) {
       this.eduSubjectService = eduSubjectService;
   }

/**
    * 读取excel内容,一行一行进行读取,此处全是业务处理
    * @param subjectData
    * @param analysisContext
    */
   @Override
   public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
       log.info("进入方法调用");
       if (StringUtils.isEmpty(subjectData)){
           throw new GuliException(20001,"文件数据为空");
       }
       //一行一行去读取excel内容,每次读取有两个值,第一个值为一级分类,第二个值为二级分类
       //判断一级分类是否重复
       EduSubject existOneSubject = this.existOneSubject(eduSubjectService, subjectData.getOneSubjectName());
       if (StringUtils.isEmpty(existOneSubject)){
           existOneSubject=new EduSubject();
           existOneSubject.setParentId("0");
           //一级分类名称
           existOneSubject.setTitle(subjectData.getOneSubjectName());
           eduSubjectService.save(existOneSubject);
       }
       //获取一级分类的pid值
       String pid=existOneSubject.getId();
       //添加二级分类
       // 判断二级分类是否重复
       EduSubject existTwoSubject = this.existTwoSubject(eduSubjectService, subjectData.getTwoSubjectName(), pid);
       if (StringUtils.isEmpty(existTwoSubject)){
           existTwoSubject=new EduSubject();
           existTwoSubject.setParentId(pid);
           //二级分类名称
           existTwoSubject.setTitle(subjectData.getTwoSubjectName());
           eduSubjectService.save(existTwoSubject);
       }

}

/**
    * 读取完成后执行
    */
   @Override
   public void doAfterAllAnalysed(AnalysisContext analysisContext) {

}

/**
    * 判断一级分类是否重复
    * 因为课程的的parent_id为0时,代表是一级分类,并且一级分类数据不重复
    * @param eduSubjectService
    * @param name
    * @return
    */
   private EduSubject existOneSubject(EduSubjectService eduSubjectService,String name){
       QueryWrapper<EduSubject> wrapper=new QueryWrapper<>();
       wrapper.eq("title",name);
       wrapper.eq("parent_id","0");
       EduSubject subject = eduSubjectService.getOne(wrapper);
       return subject;
   }
   /**
    * 判断二级分类是否重复
    *
    * @param eduSubjectService
    * @param name
    * @param pid
    * @return
    */
   private EduSubject existTwoSubject(EduSubjectService eduSubjectService,String name,String pid){
       QueryWrapper<EduSubject> wrapper=new QueryWrapper<>();
       wrapper.eq("title",name);
       wrapper.eq("parent_id",pid);
       EduSubject eduSubject = eduSubjectService.getOne(wrapper);
       return eduSubject;
   }
}

3.6、小细节,实体类pojo

因为mybatisplus生成的实体类的主键生成策略是IdType.ID_WORKER,所以需要修改成IdType.ID_WORKER_STR,否则会有转换问题


package com.zhz.serviceedu.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
* <p>
* 课程科目
* </p>
*
* @author zhz
* @since 2021-07-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="EduSubject对象", description="课程科目")
public class EduSubject implements Serializable {

private static final long serialVersionUID = 1L;

@ApiModelProperty(value = "课程类别ID")
   @TableId(value = "id", type = IdType.ID_WORKER_STR)
   private String id;

@ApiModelProperty(value = "类别名称")
   private String title;

@ApiModelProperty(value = "父ID")
   private String parentId;

@ApiModelProperty(value = "排序字段")
   private Integer sort;

@ApiModelProperty(value = "创建时间")
   @TableField(fill = FieldFill.INSERT)
   private Date gmtCreate;

@ApiModelProperty(value = "更新时间")
   @TableField(fill = FieldFill.INSERT_UPDATE)
   private Date gmtModified;

}

3.7、其余,swagger集成,R类统一返回,统一日志等,请看我其他博客

统一日志:https://blog.csdn.net/zhouhengzhe/article/details/118078080
统一返回值:https://blog.csdn.net/zhouhengzhe/article/details/118065066
统一异常:https://blog.csdn.net/zhouhengzhe/article/details/118064739
swagger集成:https://blog.csdn.net/zhouhengzhe/article/details/118063779

来源:https://blog.csdn.net/zhouhengzhe/article/details/118427902

标签:SpringBoot,EasyExcel
0
投稿

猜你喜欢

  • Android编程之防止反编译的实现方法

    2021-10-31 04:23:35
  • android实现文本复制到剪切板功能(ClipboardManager)

    2023-11-28 17:40:31
  • 教你在 Java 中实现 Dijkstra 最短路算法的方法

    2023-04-03 00:19:42
  • 对C#中public、private、protect的区别说明

    2021-05-30 22:11:21
  • Android编程之ProgressBar圆形进度条颜色设置方法

    2022-03-11 15:26:25
  • java HashMap和HashTable的区别详解

    2023-08-10 18:41:56
  • android实现线程间通信的四种常见方式

    2022-08-20 13:11:17
  • C#实现单位换算器

    2022-04-20 07:25:55
  • Spring Boot 工程的创建和运行(图文)

    2022-06-26 15:39:49
  • Spring boot 整合Logback过程示例解析

    2021-12-06 04:05:52
  • 详解spring cloud ouath2中的资源服务器

    2022-09-24 15:36:43
  • WPF ProgressBar实现实时进度效果

    2023-01-14 08:05:49
  • 关于Java8新特性Optional类的详细解读

    2023-12-06 00:38:53
  • Java数据结构及算法实例:朴素字符匹配 Brute Force

    2022-01-10 15:03:40
  • 利用Java简单实现一个代码行数统计器方法实例

    2023-01-12 10:50:25
  • mybatis的动态SQL和模糊查询实例详解

    2022-03-10 09:47:03
  • SpringBoot实现MapperScan添加动态配置(占位符)

    2023-11-26 05:08:06
  • Android 自定义View实现抽屉效果

    2022-08-03 01:27:00
  • 实例解析使用Java实现基本的音频播放器的编写要点

    2023-11-29 14:54:26
  • 手写Java LockSupport的示例代码

    2021-11-05 07:00:39
  • asp之家 软件编程 m.aspxhome.com