一、寫操作(將數據寫入到excel文件)
GitHub地址參照:https://github.com/alibaba/easyexcel
https://www.yuque.com/easyexcel/doc/fill
https://github.com/alibaba/easyexcel/blob/master/quickstart.md
https://github.com/oukele/EasyExcelDemo
1.引入依賴
<dependencies> <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --> <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> </dependencies>
2.創建實體類,這里用的lombok生成get和set。
package com.stu.codeGenerator.excel; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; @Data public class DemoDataExcel { //設置Excel表頭名稱 @ExcelProperty("學生編號") private Integer sno; @ExcelProperty("學生姓名") private String sname; }
3.測試方法(兩種方式都可以)
方法1
package com.stu.codeGenerator.excel; import com.alibaba.excel.EasyExcel; import java.util.ArrayList; import java.util.List; public class DemoEasyExcel { public static void main(String[] args) {
//寫法1 //實現excel寫的操作(生成一個excel文件,並且有內容) //1.設置寫入文件地址和excel文件名稱,如果路徑是C盤可能會報錯。 String fileName = "F:\\write.xlsx"; //2.調用easyexcel里面的方法實現寫操作 //write有兩個參數,第一個參數是文件路徑名稱,第二個參數是實體類class,doWrite里需要傳遞一個集合 EasyExcel.write(fileName,DemoDataExcel.class).sheet("學生列表").doWrite(getData()); } private static List<DemoDataExcel> getData(){ List<DemoDataExcel> list = new ArrayList<>(); for(int i = 0;i<10;i++){ DemoDataExcel data = new DemoDataExcel(); data.setSno(i); data.setSname("Excel"+i); list.add(data); } return list; } }
方法2
public static void main(String[] args) throws Exception { // 寫法2,方法二需要手動關閉流 String fileName = "F:\\112.xlsx"; // 這里 需要指定寫用哪個class去寫 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoDataExcel.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet("寫入方法二").build(); excelWriter.write(data(), writeSheet); /// 千萬別忘記finish關閉流 excelWriter.finish(); }
4.執行main方法,excel效果如下。
二、讀操作基本示例(從excel文件把數據讀出來)
1.創建實體類(注解多了一個value和index)
package com.stu.codeGenerator.excel; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; @Data public class DemoDataExcel { //設置Excel表頭名稱 //0表示第一列 @ExcelProperty(value = "學生編號",index = 0) private Integer sno; //1表示第二列 @ExcelProperty(value = "學生姓名",index = 1) private String sname; }
2.創建一個監聽器類繼承AnalysisEventListener,進行excel文件讀取,他是一行一行的讀取
package com.stu.codeGenerator.excel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import java.sql.SQLOutput; import java.util.Map; public class ExcelListener extends AnalysisEventListener<DemoDataExcel> { //一行一行讀取excel內容,第一行表頭不會讀取 @Override public void invoke(DemoDataExcel demoDataExcel, AnalysisContext analysisContext) { System.out.println("++++行內容++++="+demoDataExcel); } //讀取表頭內容 @Override public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { System.out.println("+++表頭+++++="+headMap); } //讀取完成之后 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("++++++++="+analysisContext); } }
3.測試方法(兩個方法)
方法1
package com.stu.codeGenerator.excel; import com.alibaba.excel.EasyExcel; import java.util.ArrayList; import java.util.List; public class DemoEasyExcel { public static void main(String[] args) { // //實現excel寫的操作(生成一個excel文件,並且有內容) // //1.設置寫入文件地址和excel文件名稱 // String fileName = "F:\\write.xlsx"; // // //2.調用easyexcel里面的方法實現寫操作 // //write有兩個參數,第一個參數是文件路徑名稱,第二個參數是實體類class // EasyExcel.write(fileName,DemoDataExcel.class).sheet("學生列表").doWrite(getData()); String fileName = "F:\\write.xlsx"; EasyExcel.read(fileName,DemoDataExcel.class,new ExcelListener()).sheet().doRead(); } private static List<DemoDataExcel> getData(){ List<DemoDataExcel> list = new ArrayList<>(); for(int i = 0;i<10;i++){ DemoDataExcel data = new DemoDataExcel(); data.setSno(i); data.setSname("Excel"+i); list.add(data); } return list; } }
方法2
public static void main(String[] args) throws Exception { // 寫法1: String fileName = "F:\\01.xlsx"; // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關閉 EasyExcel.read(fileName, ReadData.class, new ExcelListener()).sheet().doRead(); // 寫法2: InputStream in = new BufferedInputStream(new FileInputStream("F:\\01.xlsx")); ExcelReader excelReader = EasyExcel.read(in, ReadData.class, new ExcelListener()).build(); ReadSheet readSheet = EasyExcel.readSheet(0).build(); excelReader.read(readSheet); // 這里千萬別忘記關閉,讀的時候會創建臨時文件,到時磁盤會崩的 excelReader.finish(); }
控制台輸出:
+++表頭+++++={0=學生編號, 1=學生姓名} ++++行內容++++=DemoDataExcel(sno=0, sname=Excel0) ++++行內容++++=DemoDataExcel(sno=1, sname=Excel1) ++++行內容++++=DemoDataExcel(sno=2, sname=Excel2) ++++行內容++++=DemoDataExcel(sno=3, sname=Excel3) ++++行內容++++=DemoDataExcel(sno=4, sname=Excel4) ++++行內容++++=DemoDataExcel(sno=5, sname=Excel5) ++++行內容++++=DemoDataExcel(sno=6, sname=Excel6) ++++行內容++++=DemoDataExcel(sno=7, sname=Excel7) ++++行內容++++=DemoDataExcel(sno=8, sname=Excel8) ++++行內容++++=DemoDataExcel(sno=9, sname=Excel9) ++++++++=com.alibaba.excel.context.AnalysisContextImpl@491666ad Process finished with exit code 0
三、讀操作--保存到數據示例(從excel文件把數據讀出來,保存到數據庫)
1.SubJectData實體類封裝
package com.stu.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; }
2.controller層
package com.stu.eduservice.controller; import com.stu.commonutils.ResultData; import com.stu.eduservice.entity.EduSubject; import com.stu.eduservice.entity.subject.Subject; import com.stu.eduservice.service.IEduSubjectService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.List; /** * <p> * 課程科目 前端控制器 * </p> * * @author stu * @since 2021-05-24 */ @RestController @RequestMapping("/eduservice/subject") @CrossOrigin public class EduSubjectController { @Autowired private IEduSubjectService eduSubjectService; //添加課程分類 //獲取上傳的excel文件,把文件的內容讀取出來 @PostMapping("addSubJect") public ResultData addSubJect(MultipartFile file){ //上傳過來的excel文件 eduSubjectService.addSubJect(file,eduSubjectService); return ResultData.success(); } //課程分類列表(樹形) @GetMapping("getAllSubJect") public ResultData getAllSubJect(){ List<Subject> list = eduSubjectService.getAllSubJect(); return ResultData.success().data("list",list); } }
3.service接口
package com.stu.eduservice.service; import com.stu.eduservice.entity.EduSubject; import com.baomidou.mybatisplus.extension.service.IService; import com.stu.eduservice.entity.subject.Subject; import org.springframework.web.multipart.MultipartFile; import java.util.List; /** * <p> * 課程科目 服務類 * </p> * * @author stu * @since 2021-05-24 */ public interface IEduSubjectService extends IService<EduSubject> { void addSubJect(MultipartFile file,IEduSubjectService eduSubjectService); List<Subject> getAllSubJect(); }
4.service實現類
package com.stu.eduservice.service.impl; import com.alibaba.excel.EasyExcel; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.stu.eduservice.entity.EduSubject; import com.stu.eduservice.entity.excel.SubJectData; import com.stu.eduservice.entity.subject.Subject; import com.stu.eduservice.listener.SubJectExcelListener; import com.stu.eduservice.mapper.EduSubjectMapper; import com.stu.eduservice.service.IEduSubjectService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <p> * 課程科目 服務實現類 * </p> * * @author stu * @since 2021-05-24 */ @Service public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements IEduSubjectService { @Override public void addSubJect(MultipartFile file,IEduSubjectService eduSubjectService) { try { //文件輸入流 InputStream in = file.getInputStream(); //調用讀方法,通過監聽類把數據保存到數據庫 EasyExcel.read(in, SubJectData.class,new SubJectExcelListener(eduSubjectService)).sheet().doRead(); } catch (Exception e) { e.printStackTrace(); } } @Override public List<Subject> getAllSubJect() { List<Subject> root = new ArrayList<Subject>(); QueryWrapper<EduSubject> wrapper = new QueryWrapper<>(); List<EduSubject> permissionList = baseMapper.selectList(wrapper);//根菜單 List<Subject> subjectList = new ArrayList<>(); Map<String,Subject> map = new HashMap<String,Subject>(); for(EduSubject bean :permissionList){ Subject subject = new Subject(); BeanUtils.copyProperties(bean,subject); map.put(bean.getId(), subject); subjectList.add(subject); } for(Subject bean :subjectList){ Subject children = bean; if(bean.getParentId().equals("0")){ root.add(bean); }else{ Subject parent = map.get(children.getParentId()); parent.getChildren().add(children); } } return root; } }
5.監聽類繼承AnalysisEventListener,通過invoke方法把數據保存到數據庫
package com.stu.eduservice.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.stu.eduservice.entity.EduSubject; import com.stu.eduservice.entity.excel.SubJectData; import com.stu.eduservice.service.IEduSubjectService; import com.stu.servicebase.exceptionHandler.GuliException; public class SubJectExcelListener extends AnalysisEventListener<SubJectData> { //因為SubJectExcelListener不能交給spring進行管理,需要自己new,不能注入其他對象 //不能實現數據庫操作 new mapper public IEduSubjectService eduSubjectService; //讓對象可以使用start,創建一個有參構造和一個無參構造 public SubJectExcelListener(){} public SubJectExcelListener(IEduSubjectService eduSubjectService){ this.eduSubjectService = eduSubjectService; } //讓對象可以使用end @Override public void invoke(SubJectData subJectData, AnalysisContext analysisContext) { if(subJectData == null ){ throw new GuliException(20001,"數據為空"); } //一行一行讀取,每次讀取有兩個值,一級分類和二級分類 EduSubject eduSubjectOne =this.checkOne(eduSubjectService,subJectData.getOneSubjectName()); if(eduSubjectOne == null ){ eduSubjectOne = new EduSubject(); eduSubjectOne.setParentId("0"); eduSubjectOne.setTitle(subJectData.getOneSubjectName()); eduSubjectService.save(eduSubjectOne); } //取得一級分類的id,作為二級分類的父id,pid String pid = eduSubjectOne.getId(); EduSubject eduSubjectTwo =this.checkTwo(eduSubjectService,subJectData.getTwoSubjectName(),pid); if(eduSubjectTwo == null ){ eduSubjectTwo = new EduSubject(); eduSubjectTwo.setParentId(pid); eduSubjectTwo.setTitle(subJectData.getTwoSubjectName()); eduSubjectService.save(eduSubjectTwo); } } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { } //判斷一級分類不能重復 private EduSubject checkOne(IEduSubjectService eduSubjectService,String name){ QueryWrapper<EduSubject> wrapper = new QueryWrapper<>(); wrapper.eq("title",name); wrapper.eq("parent_id",0); EduSubject eduSubject = eduSubjectService.getOne(wrapper); return eduSubject; } //判斷二級分類不能重復 private EduSubject checkTwo(IEduSubjectService 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; } }
四、讀操作--保存到數據示例(從excel文件把數據讀出來,保存到數據庫)(和3基本一樣,版本和注入方式有區別)
1、pom依賴(2.2.6)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>service</artifactId> <groupId>com.stu</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>service_edu</artifactId> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> </dependency> </dependencies> </project>
2、實體類
package com.stu.service.edu.entity.excel; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; /****************************** * 用途說明:導入課程分類的excel類 * 作者姓名: Administrator * 創建時間: 2022-05-06 0:14 ******************************/ @Data public class SubjectExcelData { @ExcelProperty(value="一級分類") private String oneSubjectTitle; @ExcelProperty(value="二級分類") private String twoSubjectTitle; }
3、controller
package com.stu.service.edu.controller.admin; import com.stu.service.base.result.R; import com.stu.service.edu.service.SubjectService; 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 stu * @since 2022-05-06 */ @RestController @RequestMapping("/edu/subject") @CrossOrigin public class SubjectController { @Autowired private SubjectService subjectService; @PostMapping("batchImportExcel") public R batchImportExcel(MultipartFile file){ subjectService.batchImport(file); return R.ok(); } }
4、service
package com.stu.service.edu.service; import com.stu.service.edu.entity.Subject; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.web.multipart.MultipartFile; import java.io.InputStream; /** * <p> * 課程科目 服務類 * </p> * * @author stu * @since 2022-05-06 */ public interface SubjectService extends IService<Subject> { /*********************************** * 用途說明:批量導入 * 返回值說明: void ***********************************/ void batchImport(MultipartFile file); }
5、實現類
package com.stu.service.edu.service.impl; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.support.ExcelTypeEnum; import com.stu.service.edu.entity.Subject; import com.stu.service.edu.entity.excel.SubjectExcelData; import com.stu.service.edu.listener.SubJectExcelListener; import com.stu.service.edu.mapper.SubjectMapper; import com.stu.service.edu.service.SubjectService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; /** * <p> * 課程科目 服務實現類 * </p> * * @author stu * @since 2022-05-06 */ @Service public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService { @Autowired private SubjectMapper subjectMapper; @Override public void batchImport(MultipartFile file) { try { EasyExcel.read(file.getInputStream(), SubjectExcelData.class, new SubJectExcelListener(subjectMapper)).excelType(ExcelTypeEnum.XLS).sheet().doRead(); } catch (IOException e) { e.printStackTrace(); } } }
6、監聽器
package com.stu.service.edu.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.stu.service.base.exception.CustomException; import com.stu.service.base.result.ResultCodeEnum; import com.stu.service.edu.entity.Subject; import com.stu.service.edu.entity.excel.SubjectExcelData; import com.stu.service.edu.mapper.SubjectMapper; /****************************** * 用途說明:excel導入的listener * 作者姓名: Administrator * 創建時間: 2022-05-06 0:23 ******************************/ public class SubJectExcelListener extends AnalysisEventListener<SubjectExcelData> { //因為SubJectExcelListener不能交給spring進行管理,需要自己new,不能注入其他對象 //不能實現數據庫操作 new mapper private SubjectMapper subjectMapper; //讓對象可以使用start,創建一個有參構造和一個無參構造 public SubJectExcelListener() { } public SubJectExcelListener(SubjectMapper subjectMapper) { this.subjectMapper = subjectMapper; } //讓對象可以使用end /*********************************** * 用途說明:遍歷每一行數據 * 返回值說明: void ***********************************/ @Override public void invoke(SubjectExcelData subjectExcelData, AnalysisContext analysisContext) { if (subjectExcelData == null) { throw new CustomException(ResultCodeEnum.EXCEL_DATA_IMPORT_ERROR); } String oneSubjectTitle = subjectExcelData.getOneSubjectTitle(); String twoSubjectTitle = subjectExcelData.getTwoSubjectTitle(); //驗證是否已經存在一級分類 Subject oneSbuject = this.checkOneSubject(oneSubjectTitle); if (oneSbuject == null) { oneSbuject = new Subject(); oneSbuject.setTitle(oneSubjectTitle); oneSbuject.setParentId("0"); subjectMapper.insert(oneSbuject); } //取得二級分類的父id String pid = oneSbuject.getId(); //驗證是否已經存在二級分類 Subject twoSbuject = this.checkTwoSubject(twoSubjectTitle, pid); if (twoSbuject == null) { twoSbuject = new Subject(); twoSbuject.setTitle(twoSubjectTitle); twoSbuject.setParentId(pid); subjectMapper.insert(twoSbuject); } } /*********************************** * 用途說明:所有數據讀取之后的收尾工作 * 返回值說明: void ***********************************/ @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { } /*********************************** * 用途說明:驗證是否已經存在一級分類 * 返回值說明: com.stu.service.edu.entity.Subject ***********************************/ private Subject checkOneSubject(String title) { QueryWrapper<Subject> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("title", title); return subjectMapper.selectOne(queryWrapper); } /*********************************** * 用途說明:驗證是否已經存在二級分類 * 返回值說明: com.stu.service.edu.entity.Subject ***********************************/ private Subject checkTwoSubject(String title, String pid) { QueryWrapper<Subject> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("title", title); queryWrapper.eq("parent_id", pid); return subjectMapper.selectOne(queryWrapper); } }
7、vue(包含下載和導入)
<template> <dev class="app-container"> <el-form label-width="120px" v-loading="loading"> <el-form-item label="信息描述"> <el-tag type="info"> excel模板說明 </el-tag> <el-tag ><i class="el-icon-download" /> <a :href="defaultExcelTemplate">點擊下載模板</a> </el-tag> </el-form-item> <el-form-item label="選擇Excel"> <el-upload ref="upload" :action="BASE_API + '/admin/edu/subject/batchImportExcel'" :auto-upload="false" :on-exceed="fileUploadExceed" :on-success="uploadExcelSuccess" :on-error="uploadExcelError" :on-change="checkUploadExcel" :file-list="fileList" :limit="1" name="file" accept="application/vnd.ms-excel" > <el-button size="small" type="primary" slot="trigger" >選取文件</el-button > <el-button size="small" type="succcess" style="margin-left: 10px" @click="uploadFile" :disabled="importBtnDisabled" >{{ fileUploadBtnText }}</el-button > </el-upload> </el-form-item> </el-form> </dev> </template> <script> // import { defineComponent } from '@vue/composition-api' export default { name: "subjectForm", data() { return { BASE_API: process.env.BASE_API, //接口地址 defaultExcelTemplate: "/static/excel/excelTemple.xls", //默認的模板 importBtnDisabled: false, //是否可以點擊導入, fileList: [], //上傳的文件集合, loading: false, fileUploadBtnText: "導入", }; }, methods: { //excel上傳的文件限制和大小限制 checkUploadExcel(file) { if (Array.isArray(file)) { this.fileList = file; } else { this.fileList.push(file); } let testFile = file.name .substring(file.name.lastIndexOf(".") + 1) .toLowerCase(); const extension = testFile === "xlsx" || testFile === "xls"; const isLt10M = file.size / 1024 / 1024 < 10; if (!extension) { this.$message({ message: "上傳文件只能是xls/xlsx!", type: "warning", }); this.fileList = []; this.$refs.upload.clearFiles(); this.$refs.upload.abort(); return false; } if (!isLt10M) { this.$message({ message: "文件大小不可以超過10M", type: "warning", }); this.fileList = []; this.$refs.upload.clearFiles(); this.$refs.upload.abort(); return false; } return extension && isLt10M; }, //文件上傳數多於約定數量是觸發 fileUploadExceed() { this.$message.warning("只能選取一個文件"); }, uploadFile() { //this.importBtnDisabled = true; //等同於js:document.getElementById("upload").submit(); //ref="upload"相當於唯一id if (this.fileList.length > 0) { this.$refs.upload.submit(); //提交上傳請求 this.fileUploadBtnText = "正在上傳..."; this.loading = true; } else { this.fileList = []; this.$refs.upload.abort(); this.$message({ type: "warning", message: "請先上傳文件!", }); } }, // uploadExcelSuccess(res) { this.loading = false; // this.importBtnDisabled = false; this.fileUploadBtnText = "導入"; this.$message.success(res.message); this.fileList = []; //清空文件列表 }, // uploadExcelError(res) { this.loading = false; // this.importBtnDisabled = false; this.fileUploadBtnText = "導入"; this.$message.console.error(res.message); this.fileList = []; }, }, }; </script>
8、數據庫
9、上傳的文件
10、頁面效果
作者:明
出處:https://www.cnblogs.com/konglxblog//
版權:本文版權歸作者和博客園共有
轉載:歡迎轉載,文章中請給出原文連接,此文章僅為個人知識學習分享,否則必究法律責任