目录
场景
当我们导入课程信息,直接导入Excel文件即可录入所有课程信息,它是行模式读取文件信息,节省内存,效率较高;
预热测试
- <dependencies>
-
- <dependency>
- <groupId>com.alibabagroupId>
- <artifactId>easyexcelartifactId>
- <version>2.1.1version>
- dependency>
- dependencies>
2.创建实体类
一个是一级
- package com.atguigu.demo.excel;
-
- import com.alibaba.excel.annotation.ExcelProperty;
- import lombok.Data;
-
- @Data
- public class DemoData {
- //设置表头名称
- @ExcelProperty(value = "学生编号",index = 0)
- private Integer sno;
-
- @ExcelProperty(value = "学生姓名",index = 1)
- private String sname;
-
-
- }

指定文件名,在文件中write(),并且封装data数据
- public static void main(String[] args) throws Exception {
- // 写法1
- String fileName = "F:\\11.xlsx";
- // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
- // 如果这里想使用03 则 传入excelType参数即可
- EasyExcel.write(fileName, DemoData.class).sheet("写入方法一").doWrite(data());
- }
- //循环设置要添加的数据,最终封装到list集合中
- private static List
data() { - List
list = new ArrayList(); - for (int i = 0; i < 10; i++) {
- DemoData data = new DemoData();
- data.setSno(i);
- data.setSname("张三"+i);
- list.add(data);
- }
- return list;
- }
主要是通过ExcelListener监听器从Excel中获取行数据
- package com.atguigu.demo.excel;
-
- import com.alibaba.excel.EasyExcel;
-
- import java.util.ArrayList;
- import java.util.List;
-
- public class TestEasyExcel {
- public static void main(String[] args) {
-
- String filename="D:\\write.xlsx";
-
-
- // EasyExcel.write(filename,DemoData.class).sheet("学生列表").doWrite(getData());
-
- /**
- * 4.读取excel
- * 读取filename,利用监听器,把每行内容输出
- */
- EasyExcel.read(filename,DemoData.class,new ExcelListener()).sheet().doRead();
- }
-
- /**
- * 3.返回含有数据的list
- */
- private static List
getData(){ - ArrayList
list = new ArrayList<>(); - for (int i = 0; i < 10; i++) {
- DemoData data = new DemoData();
- data.setSno(i);
- data.setSname("Lucy"+i);
- list.add(data);
- }
- return list;
- }
- }
读取Excel文件的监听器,监听我们的fileName
- package com.atguigu.demo.excel;
-
- import com.alibaba.excel.context.AnalysisContext;
- import com.alibaba.excel.event.AnalysisEventListener;
- import org.springframework.stereotype.Component;
-
- import java.util.Map;
- @Component
- public class ExcelListener extends AnalysisEventListener
{ -
- /**
- * 1.一行一行读取数据
- * @param demoData
- * @param analysisContext
- */
- @Override
- public void invoke(DemoData demoData, AnalysisContext analysisContext) {
- System.out.println("****"+demoData);
- }
-
- /**
- * 2.去读表头中信息
- * @param
- */
- @Override
- public void invokeHeadMap(Map
headMap, AnalysisContext context) { - System.out.println("表头:"+headMap);
- }
-
- /**
- * 3.读完之后干的事情
- * @param analysisContext
- */
- @Override
- public void doAfterAllAnalysed(AnalysisContext analysisContext) {
-
- }
- }
项目结合
一级分类
- package com.atguigu.eduservice.entity.subject;
-
- import lombok.Data;
-
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.List;
-
- //一级分类
- @Data
- public class OneSubject implements Serializable {
- private String id;
- private String title;
-
- /**
- * 一个一级分类里面有多个二级分类(用集合表示)
- */
- private List
children=new ArrayList<>(); -
- }
- package com.atguigu.eduservice.entity.subject;
-
- import lombok.Data;
-
- import java.io.Serializable;
-
- //二级分类
- @Data
- public class TwoSubject implements Serializable {
- private String id;
- private String title;
-
- }
- @RestController
- @RequestMapping("/eduservice/subject")
- @CrossOrigin
- public class EduSubjectController {
-
- @Autowired
- private EduSubjectService subjectService;
-
- /**
- * 1.添加课程分类
- * 获取用户上传过来的文件然后进行读取
- * @Param: MultipartFile
- */
- @PostMapping("addSubject")
- public R addSubject(MultipartFile file){
- //1.1上传过来的excel文件
- subjectService.saveSubject(file,subjectService);
-
- return R.ok();
- }
-
- }
注意:这里需要注意我们的控制层传入了subjectService,然后业务层中ExcelListener监听器封装了subejectService,需要注意这里出现了相互调用的情况,所以不能都给Spring管理,所以我们没有@AutoWired注入subjectService,而是通过传参的形式
这里再普及一下课程信息展示的流程(树形):
1.首先Wrapper封装父id=0的所有数据,也就是一级分类,然后我们再查询父id!=1的分类也就是二级分类——>2.然后我们对一级分类进行封装,将一级分类转为我们封装的OneSubject——>3.然后我们的封装的一级分类集合遍历,每一个一级分类下有一个二级分类集合属性,将二级分类集合遍历,如果二级id为一级父id,就将当前二级分类加入二级分类集合中——>4.最后一级分类添加这个集合,返回一级分类集合
- package com.atguigu.eduservice.service.impl;
-
- import com.alibaba.excel.EasyExcel;
- import com.atguigu.eduservice.R;
- import com.atguigu.eduservice.entity.EduSubject;
- import com.atguigu.eduservice.entity.excel.SubjectData;
- import com.atguigu.eduservice.entity.subject.OneSubject;
- import com.atguigu.eduservice.entity.subject.TwoSubject;
- import com.atguigu.eduservice.listener.SubjectExcelListener;
- import com.atguigu.eduservice.mapper.EduSubjectMapper;
- import com.atguigu.eduservice.service.EduSubjectService;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import org.springframework.beans.BeanUtils;
- import org.springframework.stereotype.Service;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.multipart.MultipartFile;
-
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.stream.Collectors;
-
- /**
- *
- * 课程科目 服务实现类
- *
- *
- * @author testjava
- * @since 2022-07-11
- */
- @Service
- public class EduSubjectServiceImpl extends ServiceImpl
implements EduSubjectService { -
- /**
- * 1.添加课程分类,需要读取excel文件
- *
- * @param file 注意这里new的listener,我们传入service目的是自动注入会造成循环依赖,listener调用service,service调用listener,所以不能使用同一个service
- */
- @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();
- }
- }
-
- /**
- * 2.获取课程信息
- *
- * @return
- */
- @Override
- public List
getAllOneTwoSubject() { - //1.查询所有的一级分类
- QueryWrapper
wrapper = new QueryWrapper<>(); - wrapper.eq("parent_id", "0");
- List
oneSubjectList = this.list(wrapper); -
- //2.查询所有的二级分类
- QueryWrapper
wrapperTwo = new QueryWrapper<>(); - wrapperTwo.ne("parent_id", "0");
- List
twoSubjectList = this.list(wrapperTwo); -
- //3.封装所有的一级分类
- /**
- * 查询出来所有的一级分类list集合遍历得到每个一级对象,获取每个一级分类对象值
- * 然后封装到List
中 - */
- List
finalSubjectList = oneSubjectList.stream().map(eduSubject -> { - OneSubject oneSubject = new OneSubject();
- BeanUtils.copyProperties(eduSubject, oneSubject);
-
- return oneSubject;
- }).collect(Collectors.toList());
-
-
- //4.一级分类封装所有的二级分类
- for (OneSubject oneSubject : finalSubjectList) {
- ArrayList
twoFinalSubjectList = new ArrayList<>(); - for (EduSubject subject : twoSubjectList) {
- if(subject.getParentId().equals(oneSubject.getId())){
- TwoSubject twoSubject = new TwoSubject();
- BeanUtils.copyProperties(subject,twoSubject);
- twoFinalSubjectList.add(twoSubject);
- }
- }
- oneSubject.setChildren(twoFinalSubjectList);
- }
-
- return finalSubjectList;
- }
-
-
- }
1.首先,是两个分类的判断方法,判断两个分类是否存在,并且返回——>2.如果不为空就返回,如果为空就进行添加——>3.ExcelEasy是一行一行读取,传入SubjectData实体类,里面封装了一级分类和二级分类
- package com.atguigu.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;
-
- }
- package com.atguigu.eduservice.listener;
-
- import com.alibaba.excel.context.AnalysisContext;
- import com.alibaba.excel.event.AnalysisEventListener;
- import com.atguigu.eduservice.entity.EduSubject;
- import com.atguigu.eduservice.entity.excel.SubjectData;
- import com.atguigu.eduservice.exceptionHandler.GuliException;
- import com.atguigu.eduservice.service.EduSubjectService;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-
- /**
- * 通过监听器来进行读和存储
- */
- public class SubjectExcelListener extends AnalysisEventListener
{ -
- /**
- * 1.SubjectExcelListener不能交给Spring管理,不然会造成循环依赖
- */
- public EduSubjectService subjectService;
-
- //手动传subjectService
- public SubjectExcelListener() {}
-
- public SubjectExcelListener(EduSubjectService subjectService) {
- this.subjectService = subjectService;
- }
-
- /**
- * 2.监听获取excel中一行行数据
- * @param subjectData
- * @param analysisContext
- */
- @Override
- public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
- //2.1判断数据是否为空
- if(subjectData==null){
- throw new GuliException(20001,"文件数据为空");
- }
-
- //2.2一行行读取(一行一列:一级分类),每次读取两个值,一个一级分类,一个二级分类
- EduSubject existOneSubject = this.existOneSubject(subjectService, subjectData.getOneSubjectName());
- if(existOneSubject==null){
- //没有相同的一级分类,我们添加新的一级分类
- existOneSubject = new EduSubject();
- existOneSubject.setParentId("0");
- existOneSubject.setTitle(subjectData.getOneSubjectName());
- subjectService.save(existOneSubject);
- }
-
- //2.3获取一级分类id
- String pid = existOneSubject.getId();
-
- //2.4添加二级分类,需要判断二级分类是否重复
- EduSubject existTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
- if(existTwoSubject==null){
- existTwoSubject=new EduSubject();
- existTwoSubject.setParentId(pid);
- existTwoSubject.setTitle(subjectData.getTwoSubjectName());
- subjectService.save(existTwoSubject);
- }
- }
-
- /**
- * 3.一级title的判断
- * 这里用subjectService目的可能其他地方还需要调用
- * @param
- */
- private EduSubject existOneSubject(EduSubjectService subjectService,String name){
- QueryWrapper
wrapper = new QueryWrapper<>(); - wrapper.eq("title",name);
- wrapper.eq("parent_id","0");
-
- EduSubject oneSubject = subjectService.getOne(wrapper);
- return oneSubject;
- }
-
- /**
- * 3.二级分类的判断,得到二级标签
- * @param subjectService
- * @param name:课程名称
- * @param pid:课程号
- */
- private EduSubject existTwoSubject(EduSubjectService subjectService,String name,String pid){
- QueryWrapper
wrapper = new QueryWrapper<>(); - wrapper.eq("title",name);
- wrapper.eq("parent_id",pid);
-
- EduSubject oneSubject = subjectService.getOne(wrapper);
- return oneSubject;
- }
-
-
-
-
- @Override
- public void doAfterAllAnalysed(AnalysisContext analysisContext) {
-
- }
- }
