使用easyexcel进行分类存储数据库

  1. 引入依赖
<dependencies>
	<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>

    <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>
 </dependencies>
  1. 创建与Excel表格对应的实体类 , 通过@ExcelProperty(index = 0)注解中的index指定字段与Excel表中的哪儿列相对应
package com.starcpdk.edu.eduservice.entity.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@Data
public class SubjectData {
    @ExcelProperty(index = 0)
    private String oneSubjectName;

    @ExcelProperty(index = 1)
    private String twoSubjectName;
}

  1. 使用代码生成器快速构建service , controller , mapper层 , 具体使用方式参考这篇文章
package com.starcpdk.demo;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

/**
 * @author
 * @since 2018/12/13
 */
public class CodeGenerator {

    @Test
    public void run() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("I:\\Projects\\IND_Projects\\cpdkedu\\Back_End\\cpdkedu\\cpdkedu_parent\\service\\service_edu" + "/src/main/java/");
        gc.setAuthor("姚云峰");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/cpdkedu?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();

        //com.starcpdk.edu.eduservice
        pc.setParent("com.starcpdk.edu");
        pc.setModuleName("eduservice"); //模块名
        //com.starcpdk.edu.eduservice.controller
        pc.setController("controller");
        //com.starcpdk.edu.eduservice.entity
        pc.setEntity("entity");
        //com.starcpdk.edu.eduservice.service
        pc.setService("service");
        //com.starcpdk.edu.eduservice.mapper
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_subject");
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();
    }
}

由于使用easyExcel读操作需要使用到监听器 , 监听器是在service层new出来的 , 所以监听器SubjectExcelListener无法使用spring管理 , 因此无法使用@Autowired自动装配注入service层对象进行数据库的增删改查操作 , 那么我们该怎么解决呢?

解决方式如下:

那么我们就通过从controller传递注入的service层对象subjectService实现注入监听器中

controller层传递到service层 , service层new的监听器对象通过有参构造将subjectService传递到监听器SubjectExcelListener中.


  1. 编写controller内容 , 使用MultipartFile 上传文件 , 将上传的文件和service层的对象传到service层
package com.starcpdk.edu.eduservice.controller;


import com.starcpdk.edu.commonutils.R;
import com.starcpdk.edu.eduservice.service.EduSubjectService;
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 姚云峰
 * @since 2020-07-01
 */
@RestController
@RequestMapping("/eduservice/subject")
@CrossOrigin
public class EduSubjectController {

    @Autowired
    private EduSubjectService subjectService;

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

}


  1. service层书写saveSubject方法 , 通过file.getInputStream();方法获取文件的流 , 通过EasyExcel.read(in , SubjectData.class , new SubjectExcelListener(subjectService)).sheet().doRead();方法实现读excel表中数据。具体的逻辑处理在监听器中进行
package com.starcpdk.edu.eduservice.service.impl;

import com.alibaba.excel.EasyExcel;
import com.starcpdk.edu.eduservice.entity.EduSubject;
import com.starcpdk.edu.eduservice.entity.excel.SubjectData;
import com.starcpdk.edu.eduservice.listener.SubjectExcelListener;
import com.starcpdk.edu.eduservice.mapper.EduSubjectMapper;
import com.starcpdk.edu.eduservice.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 姚云峰
 * @since 2020-07-01
 */
@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {

    //添加课程分类
    @Override
    public void saveSubject(MultipartFile file , EduSubjectService subjectService) {
        try {
            //文件输入流
            InputStream in = file.getInputStream();
            //调用方法进行读取
            EasyExcel.read(in , SubjectData.class , new SubjectExcelListener(subjectService)).sheet().doRead();

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

  1. 书写监听器 , 比对excel表中的名字和级数是否存在表中进行筛选是否加入数据库 , 监听器是继承AnalysisEventListener类的 , 泛型是与excel表对应的实体类
package com.starcpdk.edu.eduservice.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.starcpdk.edu.eduservice.entity.EduSubject;
import com.starcpdk.edu.eduservice.entity.excel.SubjectData;
import com.starcpdk.edu.eduservice.service.EduSubjectService;
import com.starcpdk.edu.service_base.exceptionhandler.MyException;

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
    //因为SubjectExcelListener不能交给spring进行管理 , 需要自考管理 , 不能注入其他对象
    //不能用mapper实现数据库操作
    public EduSubjectService subjectService;
    public SubjectExcelListener() {}
    public SubjectExcelListener(EduSubjectService subjectService) {
        this.subjectService = subjectService;
    }

    //读取excel内容 , 一行一行读取
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
        if (subjectData == null){
            throw new MyException(20001 , "文件数据为空");
        }

        //一行一行读取 , 每次读取有两个值 , 第一个值以及分类 , 第二个值为二级分类
        //判断一级分类是否重复
        EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
        if (existOneSubject == null){//没有相同一级分类 , 进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0");
            existOneSubject.setTitle(subjectData.getOneSubjectName());//一级分类名称
            subjectService.save(existOneSubject);
        }

        //获取一级分类的id值
        String pid = existOneSubject.getId();
        //添加二级分类
        //判断二级分类是否存在
        EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
        if (existTwoSubject == null){
            existTwoSubject = new EduSubject();
            existTwoSubject.setParentId(pid);
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());//二级分类名称
            subjectService.save(existTwoSubject);
        }

    }

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

        EduSubject oneSubject = subjectService.getOne(wrapper);
        return oneSubject;
    }

    //判断二级分类不能重复添加
    private EduSubject existTwoSubject(EduSubjectService subjectService , String name , String pid){
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title" , name);
        wrapper.eq("parent_id" , pid);

        EduSubject twoSubject = subjectService.getOne(wrapper);
        return twoSubject;
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

具体思路:

Excel表中的数据分为两列 , 通过@ExcelProperty(index = 0)中的index与excel表中的列数相对应 , 下边的代码则表示excel表中的第一列的数据会赋值给oneSubjectName即以及分类中,同理二级分类也是如此

在数据库表中如何区分一级分类二级分类呢?如何让其想对应上呢?

通过id与parent_id两个字段所决定 , 一级分类的parent_id是0 , 二级分类的parent_id是一级分类相对应的id值

在监听器中通过读取excel表中数据 , 对应根据分类的名称和分类的级数去数据库查找数据 , 若查到 , 说明该分类在数据库中已存在 , 无需再次插入 , 若查询返回值为空 ,则将此条数据插入到数据库中

	@ExcelProperty(index = 0)
    private String oneSubjectName;

    @ExcelProperty(index = 1)
    private String twoSubjectName;

在这里插入图片描述
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值