使用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;

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章