使用EasyExcel读取Excel数据上传数据库

1.功能需求

现有一张课程表(含二级分类),需要使用Excel表格上传数据至数据库。
难点:分类数据的重复性校验
表结构如下:
使用EasyExcel读取Excel数据上传数据库_第1张图片
ExcelDemo:
使用EasyExcel读取Excel数据上传数据库_第2张图片

  1. 第一行数据为分类层次
  2. 后面数据为实际数据

2.项目环境

SpirngBoot + MybatisPlus

3.功能实现

具体功能实现步骤

  1. 导入依赖
  2. 编写Controller层
  3. 编写Service层
  4. 编写EasyExcel的Linstener

3.1 EasyExcel介绍

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

3.2 导入依赖

<dependencies>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>easyexcelartifactId>
            <version>2.1.1version>
        dependency>
        
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poiartifactId>
                <version>3.17version>
            dependency>
            
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-ooxmlartifactId>
                <version>3.17version>
            dependency>
    dependencies>
    

3.3 Controller层

Controller层需要接收前端提交的表单文件,传给Service层
因为EasyExcel的Read方法需要new出SubjectExcelListener对象,所以Listener不能交给Spring管理,不能获得Service层的引用。解决方案:将Service引用从Controller层传入将Service交给Listener引用

/**
 * 

* 课程科目 前端控制器 *

* * @author testjava * @since 2020-05-13 */
@RestController @RequestMapping("/eduservice/subject") @CrossOrigin public class EduSubjectController { @Autowired private EduSubjectService eduSubjectService; /** * 添加课程分类 * 获取上传过来的文件,读取文件内容 */ @PostMapping("addSubject") public R addSubject(MultipartFile file){ //上传过来的文件 eduSubjectService.saveSubject(file, eduSubjectService); return R.ok(); } }

3.3 Service层

Service处理业务逻辑:读取上传的文件,上传至数据库
使用的read方法

参数名 具体作用
InputStream 使用流进行文件读取
Class Excel中对应字段的实体类
SubjectExcelListener 监听器,用于读取数据
/**
 * 

* 课程科目 服务实现类 *

* * @author testjava * @since 2020-05-13 */
@Service public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService { @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.4 Listener监听器

编写监听器,需要继承 AnalysisEventListener类,生成有参构造函数用于注入Service引用。
业务逻辑思路分析:

  • 添加数据库之前需要对该数据进行重复性校验
  • 首先校验一级分类,查询数据库中是否有同名字段且PID=0,如果存在说明数据重复,不进行添加
  • 然后校验二级分类,查询数据库中是否有同名字段且PID=本行一级分类的ID(在上面的校验中已经拿到一级分类的PID)
/**
 * @Author: LySong
 * @Date: 2020/5/13 20:44
 */
public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

    //因为不能交给Spring管理,需要自己new,不能注入其他对象
    //不能实现数据库操作

    public EduSubjectService eduSubjectService;

    public SubjectExcelListener(EduSubjectService eduSubjectService) {
        this.eduSubjectService = eduSubjectService;
    }

    public SubjectExcelListener() {}

    /**
     * 读取内容
     * @param subjectData
     * @param analysisContext
     */
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if(subjectData == null){
            throw new GuliException(20001,"文件数据为空");
        }
        //一行一行读取,每次读取两个值,第一个值为一级分类,第二个值为二级分类
        //判断一级分类是否重复
        EduSubject existOneEduSubject = this.existOneSubject(subjectData.getOneSubjectName(), eduSubjectService);
        if(existOneEduSubject == null){
            //没有相同的一级分类
            existOneEduSubject = new EduSubject();
            existOneEduSubject.setParentId("0");
            existOneEduSubject.setTitle(subjectData.getOneSubjectName());
            eduSubjectService.save(existOneEduSubject);
        }

        //判断二级分类是否重复
        String pid = existOneEduSubject.getId();
        EduSubject existTwoEduSubject = this.existTwoSubject(subjectData.getTwoSubjectName(), eduSubjectService, pid);
        if(existTwoEduSubject == null){
            existTwoEduSubject = new EduSubject();
            existTwoEduSubject.setParentId(pid);
            existTwoEduSubject.setTitle(subjectData.getTwoSubjectName());
            eduSubjectService.save(existTwoEduSubject);
        }


    }

    /**
     * 判断一级分类不能重复添加
     */
    private EduSubject existOneSubject(String name, EduSubjectService eduSubjectService){
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", "0");
        EduSubject oneSubject = eduSubjectService.getOne(wrapper);
        return oneSubject;
    }

    /**
     * 判断二级分类不能重复添加
     */
    private EduSubject existTwoSubject(String name, EduSubjectService eduSubjectService, String pid){
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title", name);
        wrapper.eq("parent_id", pid);
        EduSubject twoSubject = eduSubjectService.getOne(wrapper);
        return twoSubject;
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

使用Swagger进行测试,结果:
使用EasyExcel读取Excel数据上传数据库_第3张图片

你可能感兴趣的:(Spring全家桶)