springboot实现EasyExcel对Excel读和写操作
一、写操作(将数据写入到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//
版权:本文版权归作者和博客园共有
转载:欢迎转载,文章中请给出原文连接,此文章仅为个人知识学习分享,否则必究法律责任