使用EasyExcel添加多级分类功能

绪论

当面对很多数据要处理,并且需要导入导出Excel表格时。在使用POI时发现非常耗内存,这时GitHub上的阿里开源项目Easy Excel可以解决此类问题,它是基于java的读写Excel,十分省内存。本篇博文主要是总结其简单使用以及关于添加分类功能的实现。

快速入门

  1. 创建项目导入依赖(此依赖依靠PIO模块,项目还需要导入PIO模块)

    <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>easyexcel</artifactId>
           <version>2.1.4</version>
    </dependency>
    
  2. 创建测试的实体类DemoData

    @Data
    public class DemoData {
           
    
        //设置excel表头名称
        @ExcelProperty(value = "学生编号",index = 0)
        private Integer sno;
        @ExcelProperty(value = "学生姓名",index = 1)
        private String sname;
    }
    

    其中index对应excel表格中的列,value是列的名称

  3. 写操作

      public static void main(String[] args) {
           
            //实现excel写的操作
            //1 设置写入文件夹地址和excel文件名称
            String filename = "D:\\write.xlsx";
            //2 调用easyexcel里面的方法实现写操作
            //write方法两个参数:第一个参数文件路径名称,第二个参数实体类class
            EasyExcel.write(filename,DemoData.class).sheet("学生列表").doWrite(getData());
          
        }
        //创建方法返回list集合
        private static List<DemoData> getData() {
           
            List<DemoData> 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;
        }
    
  4. 读操作

        public static void main(String[] args) {
           
            //实现excel读操作
            String filename = "D:\\write.xlsx";
            EasyExcel.read(filename,DemoData.class,new ExcelListener()).sheet().doRead();
        }
    

    这里我们需要创建一个读取excel监听器:

    //创建读取excel监听器
    public class ExcelListener extends AnalysisEventListener<DemoData> {
           
    
        //一行一行读取excel内容
        @Override
        public void invoke(DemoData demoData, AnalysisContext analysisContext) {
           
            System.out.println("****"+demoData);
        }
        
        //读取表头内容
        @Override
        public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext analysisContext) {
           
            System.out.println("表头:"+headMap);
        }
        
        //读取完之后
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
           
    
        }
    }
    

    以上是EsayExcel的一些基本使用,具体可以去看官方的文档。

应用场景(课程多分类的添加)

  1. 表结构

    DROP TABLE IF EXISTS `edu_subject`;
    CREATE TABLE `edu_subject`  (
      `id` char(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '课程类别ID',
      `title` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类别名称',
      `parent_id` char(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '0' COMMENT '父ID',
      `sort` int(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '排序字段',
      `gmt_create` datetime(0) NOT NULL COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL COMMENT '更新时间',
      PRIMARY KEY (`id`) USING BTREE,
      INDEX `idx_parent_id`(`parent_id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '课程科目' ROW_FORMAT = Compact;
    
    
  2. 实体类EduSubject 和分类实体类SubjectData

    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    @ApiModel(value="EduSubject对象", description="课程科目")
    public class EduSubject implements Serializable {
           
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty(value = "课程类别ID")
        @TableId(value = "id", type = IdType.ID_WORKER_STR)
        private String id;
    
        @ApiModelProperty(value = "类别名称")
        private String title;
    
        @ApiModelProperty(value = "父ID")
        private String parentId;
    
        @ApiModelProperty(value = "排序字段")
        private Integer sort;
    
        @ApiModelProperty(value = "创建时间")
        private Date gmtCreate;
    
        @ApiModelProperty(value = "更新时间")
        private Date gmtModified;
    }
    
    @Data
    public class SubjectData {
           
    
        @ExcelProperty(index = 0)
        private String oneSubjectName;  //一级分类
        @ExcelProperty(index = 1)
        private String twoSubjectName;  //二级分类
    }
    
    
  3. 监听类SubjectExcelListener

    public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
           
    
        //因为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 eduOneSubject =  this.existOneSubject(subjectService,subjectData.getOneSubjectName());
            if(eduOneSubject == null){
            //没有相同的一级分类,进行添加
                eduOneSubject = new EduSubject();
                eduOneSubject.setParentId("0");
                eduOneSubject.setTitle(subjectData.getOneSubjectName());
                subjectService.save(eduOneSubject);
            }
    
            //获取一级分类id值
            String pid = eduOneSubject.getId();
    
            //添加二级分类
            //判断二级分类是否重复
            EduSubject eduTwoSubject = this.existTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);
            if(eduTwoSubject == null) {
           
                eduTwoSubject = new EduSubject();
                eduTwoSubject.setParentId(pid);
                eduTwoSubject.setTitle(subjectData.getTwoSubjectName());//二级分类名称
                subjectService.save(eduTwoSubject);
            }
        }
    
        //判断一级分类不能重复添加
        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) {
           
    
        }
    }
    
  4. 实现类EduSubjectServiceImpl

    @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 (IOException e) {
           
                e.printStackTrace();
            }
    
        }
    }
    
  5. Controller层EduSubjectController

    @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();
        }
    }
    
  6. 测试
    (1)excel表中信息:
    使用EasyExcel添加多级分类功能_第1张图片
    (2)运行项目,用Swagger测试
    使用EasyExcel添加多级分类功能_第2张图片
    (3)查看数据库中是否添加成功
    使用EasyExcel添加多级分类功能_第3张图片

课程多分类添加整合前端

这里用的是elementUI的一个后台管理模板,项目地址:element,把项目下载下来用npm 安装运行。

  1. 添加路由在index.js

     {
           
        path: '/subject',
        component: Layout,
        redirect: '/subject/list',
        name: '课程分类管理',
        meta: {
            title: '课程分类管理', icon: 'example' },
        children: [
          {
           
            path: 'list',
            name: '课程分类列表',
            component: () => import('@/views/edu/subject/list'),
            meta: {
            title: '课程分类列表', icon: 'table' }
          },
          {
           
            path: 'save',
            name: '添加课程分类',
            component: () => import('@/views/edu/subject/save'),
            meta: {
            title: '添加课程分类', icon: 'tree' }
          }
        ]
      }
    
  2. 创建路由对应的页面save.vue

    <template>
      <div class="app-container">
        <el-form label-width="120px">
          <el-form-item label="Excel模板描述">
            <el-tag type="info">excel模版说明</el-tag>
            <el-tag>
              <i class="el-icon-download"/>
              <a :href="'/static/01.xlsx'">点击下载模版</a>
            </el-tag>
    
          </el-form-item>
    
          <el-form-item label="选择Excel文件">
            <el-upload
              ref="upload"
              :auto-upload="false"
              :on-success="fileUploadSuccess"
              :on-error="fileUploadError"
              :disabled="importBtnDisabled"
              :limit="1"
              :action="BASE_API+'/eduservice/subject/addSubject'"
              name="file"
              accept="application/vnd.ms-excel">
              <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
              <el-button
                :loading="loading"
                style="margin-left: 10px;"
                size="small"
                type="success"
                @click="submitUpload">上传</el-button>
            </el-upload>
          </el-form-item>
        </el-form>
      </div>
    </template>
    
    <script>
    export default {
           
        data() {
           
            return {
           
                BASE_API: process.env.BASE_API, // 接口API地址
                importBtnDisabled: false, // 按钮是否禁用,
                loading: false
            }
        },
        created() {
           
    
        },
        methods:{
           
            //点击按钮上传文件到接口里面
            submitUpload() {
           
                this.importBtnDisabled = true
                this.loading = true
                // js: document.getElementById("upload").submit()
                this.$refs.upload.submit()
            },
            //上传成功
            fileUploadSuccess(response) {
           
                //提示信息
                this.loading = false
                this.$message({
           
                    type: 'success',
                    message: '添加课程分类成功'
                })
                //跳转课程分类列表
                //路由跳转
                this.$router.push({
           path:'/subject/list'})
            },
            //上传失败
            fileUploadError() {
           
                this.loading = false
                this.$message({
           
                    type: 'error',
                    message: '添加课程分类失败'
                })
            }
        }
    }
    </script>
    
  3. 展示
    使用EasyExcel添加多级分类功能_第4张图片

总节

EsayExcel在各方面性能还是很不错的,后期可以根据官方的API进行深入学习。

你可能感兴趣的:(excel,Java,excel)