准备工作:采用阿里云OSS对象存储服务上传excel文件,ORM用Mybatis-plus
导入依赖:
com.alibaba easyexcel2.1.1
org.apache.poi poi
定义实体类SubjectData
@ExcelProperty(index = 0)表示第一列,类推
@Data
public class SubjectData {
@ExcelProperty(index = 0)
private String oneSubjectName;
@ExcelProperty(index = 1)
private String twoSubjectName;
}
接着创建两个实体类,分别表示一级目录和二级目录对应的实体类,一级分类包括二级分类,因此在一级分类中定义集合,存放二级分类。
//一级分类
//针对返回数据创建对应的实体类
@Data
public class oneSubject {
private String id;
private String title;//名称
//一个一级分类里面有多个二级分类
private List children=new ArrayList<>();
}
//二级分类
@Data
public class TwoSubject {
private String id;
private String title;//名称
}
接着写业务逻辑:
在控制器中定义接口,后期用Swagger测试
@RestController
@RequestMapping("/eduservice/subject")
@CrossOrigin
@Api(tags = "课程分类管理")
public class EduSubjectController {
@Autowired
private EduSubjectService subjectService;
//添加课程分类
//获取上传过来文件,把文件内容读取出来
@PostMapping("addSubject")
@ApiOperation("添加课程分类")
public R addSubject(MultipartFile file) {
//上传过来excel文件
subjectService.saveSubject(file,subjectService);
return R.ok();
}
项目数据流为,控制器调用service服务接口的方法,服务接口的实现类进行具体业务操作。
下面是service层接口信息:
第一个参数表示上传的文件流(这里采用文件流的方式上传文件),第二个参数表示在监听器中可以调用服务接口。
//添加课程分类
void saveSubject(MultipartFile file,EduSubjectService subjectService);
接着是接口实现类中的具体操作:
@Service public class EduSubjectServiceImpl extends ServiceImplimplements 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(); } } @Override public List getAlloneTwoSubject() { //1,查询出所有的一级分类 parent_id=0 QueryWrapper wrapperOne=new QueryWrapper<>(); wrapperOne.eq("parent_id","0"); List oneSubjectList = baseMapper.selectList(wrapperOne); //2,查询所有的二级分类 parent_id!=0 QueryWrapper wrapperTwo=new QueryWrapper<>(); wrapperOne.ne("parent_id","0"); List twoSubjectList = baseMapper.selectList(wrapperTwo); //创建lidt集合存储最终封装数据 List finalSubjectList=new ArrayList<>(); //3,封装一级分类 //查询出来的所有的一级分类list集合遍历,得到每一个一级分类对象,获取每个一级分类对象值 //封装到 finalSubjectList 里面 for (int i = 0; i < oneSubjectList.size(); i++) { //遍历oneSubjectList集合 //得到oneSubjectList每个eduSubject对象 EduSubject eduSubject=oneSubjectList.get(i); //把eduSubject里面的值获取出来放到OneSubject对象里面 //把多个OneSubject放到finalSubjectList中 oneSubject oneSubject=new oneSubject(); // oneSubject.setId(eduSubject.getId()); // oneSubject.setTitle(eduSubject.getTitle()); BeanUtils.copyProperties(eduSubject,oneSubject);//把一个对象中的值复制到另一个对象中,等同于上面两行 finalSubjectList.add(oneSubject); //在一级分类循环遍历查询所有的二级分类 //创建list集合封装每个一级分类的二级分类 List twoFinalSubjectList=new ArrayList<>(); //遍历二级分类list集合 for (int m = 0; m < twoSubjectList.size(); m++) { //获取每个二级分类2 EduSubject tSubject = twoSubjectList.get(m); //判断耳机分类的parentid是否与以及分类的id一样 if(tSubject.getParentId().equals(eduSubject.getId())){ //把tSubject值复制到TwoSubject里,放到twoFinalSubjectList里面 TwoSubject twoSubject=new TwoSubject(); BeanUtils.copyProperties(tSubject,twoSubject); twoFinalSubjectList.add(twoSubject); } } //把一级下面所有二级分类放到以及分类里面 oneSubject.setChildren(twoFinalSubjectList); } return finalSubjectList; } }
接着是监听器的编写,大多是固定的模板,自己改改参数,要和数据库对应。
public class SubjectExcelListener extends AnalysisEventListener{ //因为SubjectExcelListener不能交给spring进行管理,需要自己new,不能注入其他对象 //不能实现数据库操作 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 GuliException(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 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 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) { } }
其中监听器都不能直接加@Autowired引入服务类调用,因为自定义监听器不能被spring管理,需要自己创建对象再调用。
这是数据库的表结构:
我们先清空数据,方便测试。
下面是excel中输入的测试数据;
接着打开swagger进行测试:显示成功,没有爆出异常。
接着查看数据库是否更新:结果成功



