2.1.4 前端
- 创建路由模块
/** When your routing table is too long, you can split it into small modules **/importLayoutfrom'@/layout'constcourseRouter= { path: '/course', // 当前模块前缀路径,必须以/开头component: Layout, // 采用布局组件显示当前模块【默认】redirect: '/course/subjectList', // “教师管理”默认显示路由name: '课程管理', // 路由名称meta: { title: '课程管理', // 一级菜单名称,children.length==0 隐藏icon: 'table'// 一级菜单图标,children.length==0 隐藏 }, children: [ { path: 'subjectList', component: () =>import('@/views/edu/course/subjectList.vue'), name: '科目列表', meta: { title: '科目列表', icon: 'list' } //二级菜单名称 } ] } exportdefaultcourseRouter
2.2 查询所有
- 以树形table展示数据
2.2.1 后端实现
- 修改 EduSubjectController
packagecom.czxy.zx.course.controller; importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper; importcom.czxy.zx.course.service.EduSubjectService; importcom.czxy.zx.domain.EduSubject; importcom.czxy.zx.vo.BaseResult; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; importjavax.annotation.Resource; importjava.util.ArrayList; importjava.util.HashMap; importjava.util.List; importjava.util.Map; /*** @author 桐叔* @email liangtong@itcast.cn*/"/subject") (publicclassEduSubjectController { privateEduSubjectServiceeduSubjectService; publicBaseResultfindAll() { //1 查询所有QueryWrapperqueryWrapper=newQueryWrapper(); queryWrapper.orderByAsc("parent_id"); List<EduSubject>list=eduSubjectService.list(queryWrapper); //2 处理父子关系List<EduSubject>resultList=newArrayList<>(); Map<String,EduSubject>cache=newHashMap<>(); list.forEach(eduSubject-> { // 获得父EduSubjectparentEduSubject=cache.get(eduSubject.getParentId()); // 如果没有父表示第一层,如果有父追加if(parentEduSubject!=null) { // 如果有孩子,判断父对象的集合List<EduSubject>temp=parentEduSubject.getChildren(); if(temp==null) { parentEduSubject.setChildren(newArrayList<>()); } // 将孩子添加到父对象的集合中parentEduSubject.getChildren().add(eduSubject); } else { resultList.add(eduSubject); } // 缓存当前cache.put(eduSubject.getId(),eduSubject); }); returnBaseResult.ok("查询成功", resultList); } }
2.2.2 前端接口
importaxiosfrom'@/utils/request'// 查询所有课程科目exportfunctionfindAllSub() { returnaxios.get('/course-service/subject'); }
2.2.3 前端实现
- 修改
@/views/edu/course/subjectList.vue
<template><div><el-tablev-loading="listLoading" :data="subjectList"borderfithighlight-current-rowstyle="width: 100%;"row-key="title" :tree-props="{children: 'children'}"><el-table-columnlabel="科目名称"prop="title"align="center"width="200"></el-table-column><el-table-columnlabel="排序"prop="sort"width="80px"min-width="50px"></el-table-column><el-table-columnlabel="添加时间"width="200px"align="center"><templateslot-scope="{row}"><span>{{ row.gmtCreate|parseTime('{y}-{m}-{d} {h}:{i}') }}</span></template></el-table-column><el-table-columnlabel="更新时间"width="200px"align="center"><templateslot-scope="{row}"><span>{{ row.gmtModified|parseTime('{y}-{m}-{d} {h}:{i}') }}</span></template></el-table-column><el-table-columnlabel="操作"align="center"class-name="small-padding fixed-width"><templateslot-scope="{row,$index}"><el-buttontype="primary"size="mini">修改</el-button><el-buttonv-if="row.status!='deleted'"size="mini"type="danger">删除</el-button></template></el-table-column></el-table></div></template><script>import { findAllSub } from'@/api/edu/course'exportdefault { data() { return { subjectList: [] , listLoading: false, } }, methods: { asyncfindAllSubject() { // 查询所有this.listLoading=truelet { data } =awaitfindAllSub() this.subjectList=datathis.listLoading=false } }, mounted() { this.findAllSubject() }, } </script><style></style>
2.3 导入科目
2.3.1 需求
2.3.2 前端
使用upload组件<!--文件上传--><el-uploadclass="upload-demo" :action="updateUrl" :limit="1" :on-exceed="handleExceed" :before-upload="beforeUpload" :on-remove="handleRemove" :on-success="handleSuccess" :file-list="fileList"><el-buttonsize="small"type="primary">点击上传</el-button><divslot="tip"class="el-upload__tip">只能上传xls或xlsx文件,且不超过500kb</div></el-upload>声明变量data() { return { fileList: [], //上传文件列表updateUrl: process.env.VUE_APP_BASE_API+'/course-service/subject/upload', //上传路径 } }, 编写处理函数handleExceed(files, fileList) { // 超出个数限制this.$message.warning(`当前选择1个文件`); }, beforeUpload(file) { // 上传文件之前// 是否是 xlsx 文件(2003)constisXlsx=file.type==='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'// 是否是 xls 文件(2010)constisXls=file.type==='application/vnd.ms-excel'constisLt2M=file.size/1024/1024<2; if (!isXlsx&&!isXls) { this.$message.error('上传文件不是excel文件!'); } if (!isLt2M) { this.$message.error('上传文件大小不能超过 2MB!'); } return (isXlsx||isXls) &&isLt2M; }, handleRemove(file, fileList) { // 文件列表移除文件console.log(file, fileList); }, handleSuccess(response, file, fileList) { // 文件上传成功// 成功提示this.$message.success(response.message) // 刷新this.findAllSubject() }
2.3.2 前端:完整版
<template><div><el-tablev-loading="listLoading" :data="subjectList"borderfithighlight-current-rowstyle="width: 100%;"row-key="title" :tree-props="{children: 'children'}"><el-table-columnlabel="科目名称"prop="title"align="left"width="200"></el-table-column><el-table-columnlabel="排序"prop="sort"width="80px"min-width="50px"></el-table-column><el-table-columnlabel="添加时间"width="200px"align="center"><templateslot-scope="{row}"><span>{{ row.gmtCreate|parseTime('{y}-{m}-{d} {h}:{i}') }}</span></template></el-table-column><el-table-columnlabel="更新时间"width="200px"align="center"><templateslot-scope="{row}"><span>{{ row.gmtModified|parseTime('{y}-{m}-{d} {h}:{i}') }}</span></template></el-table-column><el-table-columnlabel="操作"align="center"class-name="small-padding fixed-width"><templateslot-scope="{row}"><el-buttontype="primary"size="mini">修改</el-button><el-buttonv-if="row.status!='deleted'"size="mini"type="danger">删除</el-button></template></el-table-column></el-table><!--文件上传--><el-uploadclass="upload-demo" :action="updateUrl" :limit="1" :on-exceed="handleExceed" :before-upload="beforeUpload" :on-remove="handleRemove" :on-success="handleSuccess" :file-list="fileList"><el-buttonsize="small"type="primary">点击上传</el-button><divslot="tip"class="el-upload__tip">只能上传xls或xlsx文件,且不超过500kb</div></el-upload></div></template><script>import { findAllSub } from'@/api/edu/course'exportdefault { data() { return { subjectList: [] , listLoading: false, fileList: [], //上传文件列表updateUrl: process.env.VUE_APP_BASE_API+'/course-service/subject/upload', //上传路径 } }, methods: { asyncfindAllSubject() { // 查询所有this.listLoading=truelet { data } =awaitfindAllSub() this.subjectList=datathis.listLoading=false }, handleExceed(files, fileList) { // 超出个数限制this.$message.warning(`当前选择1个文件`); }, beforeUpload(file) { // 上传文件之前// 是否是 xlsx 文件(2003)constisXlsx=file.type==='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'// 是否是 xls 文件(2010)constisXls=file.type==='application/vnd.ms-excel'constisLt2M=file.size/1024/1024<2; if (!isXlsx&&!isXls) { this.$message.error('上传文件不是excel文件!'); } if (!isLt2M) { this.$message.error('上传文件大小不能超过 2MB!'); } return (isXlsx||isXls) &&isLt2M; }, handleRemove(file, fileList) { // 文件列表移除文件console.log(file, fileList); }, handleSuccess(response, file, fileList) { // 文件上传成功// 成功提示this.$message.success(response.message) // 刷新this.findAllSubject() } }, mounted() { this.findAllSubject() }, } </script><style></style>
2.3.4 后端
1) 完善JavaBean
packagecom.czxy.zx.domain; importcom.baomidou.mybatisplus.annotation.*; importcom.fasterxml.jackson.annotation.JsonFormat; importlombok.Data; importorg.springframework.format.annotation.DateTimeFormat; importjava.util.ArrayList; importjava.util.Date; importjava.util.List; /*** 课程科目(EduSubject)表实体类** @author 桐叔*/"edu_subject") (publicclassEduSubject{ type=IdType.ASSIGN_UUID) (//课程科目IDprivateStringid; //科目名称privateStringtitle; //父IDprivateStringparentId; //排序字段privateIntegersort; //创建时间pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") (fill=FieldFill.INSERT) (privateDategmtCreate; //更新时间pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") (fill=FieldFill.INSERT) (privateDategmtModified; exist=false) (privateList<EduSubject>children=newArrayList<>(); }
packagecom.czxy.zx.course.handler; importcom.baomidou.mybatisplus.core.handlers.MetaObjectHandler; importorg.apache.ibatis.reflection.MetaObject; importorg.springframework.stereotype.Component; importjava.util.Date; /*** @author 桐叔* @email liangtong@itcast.cn*/publicclassSubjectMetaObjectHandlerimplementsMetaObjectHandler { publicvoidinsertFill(MetaObjectmetaObject) { // 创建时间this.setFieldValByName("gmtCreate",newDate(), metaObject); // 修改时间this.setFieldValByName("gmtModified",newDate() , metaObject); } publicvoidupdateFill(MetaObjectmetaObject) { // 修改时,填充的内容this.setFieldValByName("gmtModified",newDate() , metaObject); } }
接口packagecom.czxy.zx.course.service; importcom.baomidou.mybatisplus.extension.service.IService; importcom.czxy.zx.domain.EduSubject; /*** @author 桐叔* @email liangtong@itcast.cn*/publicinterfaceEduSubjectServiceextendsIService<EduSubject> { /*** 通过title查询* @param title* @return*/EduSubjectfindByTitle(Stringtitle); } 实现类packagecom.czxy.zx.course.service.impl; importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper; importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl; importcom.czxy.zx.course.mapper.EduSubjectMapper; importcom.czxy.zx.course.service.EduSubjectService; importcom.czxy.zx.domain.EduSubject; importorg.springframework.stereotype.Service; importorg.springframework.transaction.annotation.Transactional; /*** @author 桐叔* @email liangtong@itcast.cn*/publicclassEduSubjectServiceImplextendsServiceImpl<EduSubjectMapper, EduSubject>implementsEduSubjectService { publicEduSubjectfindByTitle(Stringtitle) { QueryWrapperqueryWrapper=newQueryWrapper(); queryWrapper.eq("title", title); EduSubjecteduSubject=baseMapper.selectOne(queryWrapper); returneduSubject; } } 4)controller:上传/*** 文件上传* @param file* @return*/"/upload") (publicBaseResultupload(MultipartFilefile) { try { // 解析excelEasyExcel.read(file.getInputStream(), UploadSubjectVo.class, eduSubjectListener).sheet(0).doRead(); returnBaseResult.ok("上传成功"); } catch (IOExceptione) { returnBaseResult.error("上传失败"); } }
packagecom.czxy.zx.course.upload; importcom.alibaba.excel.annotation.ExcelProperty; importlombok.Data; /*** @author 桐叔* @email liangtong@itcast.cn*/publicclassUploadSubjectVo { "一级分类") (privateStringoneLevel; "二级分类") (privateStringtwoLevel; }
packagecom.czxy.zx.course.upload; importcom.alibaba.excel.context.AnalysisContext; importcom.alibaba.excel.event.AnalysisEventListener; importcom.czxy.zx.course.service.EduSubjectService; importcom.czxy.zx.domain.EduSubject; importorg.springframework.stereotype.Component; importjavax.annotation.Resource; /*** @author 桐叔* @email liangtong@itcast.cn*/publicclassEduSubjectListenerextendsAnalysisEventListener<UploadSubjectVo> { privateEduSubjectServiceeduSubjectService; publicvoidinvoke(UploadSubjectVouploadSubjectVo, AnalysisContextanalysisContext) { // 1. 处理一级// 1.1 查询一级EduSubjectoneSubject=eduSubjectService.findByTitle(uploadSubjectVo.getOneLevel()); // 1.2 保存一级if(oneSubject==null) { oneSubject=newEduSubject(); oneSubject.setTitle(uploadSubjectVo.getOneLevel()); oneSubject.setSort(0); oneSubject.setParentId("0"); // 一级默认0eduSubjectService.save(oneSubject); } // 2. 处理二级// 2.1 查询二级EduSubjecttwoSubject=eduSubjectService.findByTitle(uploadSubjectVo.getTwoLevel()); // 2.2 保存二级if(twoSubject==null) { twoSubject=newEduSubject(); twoSubject.setTitle(uploadSubjectVo.getTwoLevel()); twoSubject.setSort(0); twoSubject.setParentId(oneSubject.getId()); //二级的父ID为一级的IDeduSubjectService.save(twoSubject); } } publicvoiddoAfterAllAnalysed(AnalysisContextanalysisContext) { } }