- 引入依賴
<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>
- 創建與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;
}
- 使用代碼生成器快速構建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
中.
- 編寫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();
}
}
- 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();
}
}
}
- 書寫監聽器 , 比對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;