首页 > 文章列表 > SpringBoot怎么集成EasyExcel应用

SpringBoot怎么集成EasyExcel应用

springboot easyexcel
498 2023-05-11

SpringBoot怎么集成EasyExcel应用

1、介绍

特点:

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="课程科目";

转成->

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;



}