课程分类管理【添加分类前端】

一、配置路由

1. 添加路由

src/router/index.js 中添加路由:

  {// 地址输入path: '/subject',component: Layout,// redirect: 重定向地址redirect: '/subject/list',name: '课程分类管理',// title:显示标签  icon:显示图标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. 添加vue组件


二、表单组件save.vue

1. js定义数据

<script>
export default {data() {return {BASE_API: process.env.BASE_API, // 接口API地址importBtnDisabled: false,  // 按钮是否禁用loading: false}},created() {},methods: {}
}</script>

2. template

<template><div class="app-container"><el-form label-width="120px"><el-form-item label="信息描述"><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-uploadref="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>

3. js上传方法

methods: {// 点击按钮上传文件到接口里面submitUpload() {this.importBtnDisabled = truethis.loading = truethis.$refs.upload.submit()},// 上传成功fileUploadSuccess(response) {},// 上传失败fileUploadError() { }}

4. 回调函数

 // 上传成功fileUploadSuccess(response) {// 提示信息this.loading = falsethis.$message({type: 'success',message: '添加课程分类成功'})// 跳转到课程分类列表},// 上传失败fileUploadError() { this.loading = falsethis.$message({type: 'error',message: '添加课程 分类失败'})}

5. 测试


 

 


课程分类管理【课程分类列表】

一、后端实现

1. 创建实体类

entity 包下创建 Subject 包用于封装树形数据结构。

  • 一级分类
@Data
public class OneSubject {private String id;private String title;//一个一级分类有多个二级分类private List<TwoSubject> children = new ArrayList<>();}
  • 二级分类
//二级分类
@Data
public class TwoSubject {private String id;private String title;
}

2. controller层

// 课程分类列表(树形)@ApiOperation(value = "嵌套数据列表")@GetMapping("getAllSubject")public R getAllSubject() {// list集合泛型是一级分类,一级分类中本身含有二级分类List<OneSubject> list = eduSubjectService.getAllOneTwoSubject();return R.ok().data("list", list);}

3. service层

EduSubjectService 接口中添加方法:

public interface EduSubjectService extends IService<EduSubject> {// 添加课程分类void addSubject(MultipartFile file, EduSubjectService eduSubjectService);// 课程分类列表(树形)List<OneSubject> getAllOneTwoSubject();
}

EduSubjectServiceImpl实现类中添加方法:

// 课程分类列表(树形)@Overridepublic List<OneSubject> getAllOneTwoSubject() {// 1. 查询所有的一级分类 parent_id = 0QueryWrapper<EduSubject> wrapperOne = new QueryWrapper<>();wrapperOne.eq("parent_id", 0);List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne);// 2. 查询所有的二级分类 parent_id != 0QueryWrapper<EduSubject> wrapperTwo = new QueryWrapper<>();wrapperTwo.ne("parent_id", 0);List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo);// 创建list集合,用于封装最终数据List<OneSubject> finalSubjectList = new ArrayList<>();// 3. 封装一级分类// 查询出来所有的一级分类list集合遍历,得到每一个一级分类对象,获取每个一级分类对象值// 封装到要求的最终list集合里面 List<OneSubject> finalSubjectListfor (int i = 0; i < oneSubjectList.size(); i ++ ) { // 遍历oneSubjectList集合// 得到oneSubjectList每个eduSubject对象EduSubject eduSubject = oneSubjectList.get(i);// 把eduSubject里面的值获取出来,放到oneSubject对象中去OneSubject oneSubject = new OneSubject();//            oneSubject.setId(eduSubject.getId());
//            oneSubject.setTitle(eduSubject.getTitle());// 把eduSubject值复制到oneSubject中去【要求两个类的复制注入的属性名一致】BeanUtils.copyProperties(eduSubject, oneSubject);// 多个oneSubject放到finalSubject里面finalSubjectList.add(oneSubject);// 4. 封装二级分类// 在一级分类循环遍历查询所有的二级分类// 创建list集合封装每个一级分类的二级分类ArrayList<TwoSubject> twoFinalSubjectList = new ArrayList<>();// 遍历二级list集合for (int j = 0; j < twoSubjectList.size(); j++) {// 获取每个二级分类EduSubject tSubject = twoSubjectList.get(j);// 判断二级分类parent_id 和一级分类的id是否一样if (tSubject.getParentId().equals(oneSubject.getId())) {// 把tSubject的值复制到TwoSubject,最终放到twoSubjectList里面TwoSubject twoSubject = new TwoSubject();BeanUtils.copyProperties(tSubject, twoSubject);twoFinalSubjectList.add(twoSubject);}}// 把一级下面所有二级分类放到oneSubject里面oneSubject.setChildren(twoFinalSubjectList);}return finalSubjectList;}

二、前端实现

1. 参考 views/tree/index.vue

2. 创建api

api/edu/subject.js

import request from '@/utils/request' // 引入已经封装好的axios 和 拦截器export default {// 课程分类列表getSubjectList() {return request({url: `/eduservice/subject/getAllSubject`,method: 'get'})}}

3. list.vue

<template><div class="app-container"><el-input v-model="filterText" placeholder="Filter keyword" style="margin-bottom:30px;" /><el-treeref="tree2":data="data2":props="defaultProps":filter-node-method="filterNode"class="filter-tree"default-expand-all/></div>
</template><script>
import subject from '@/api/edu/subject.js'
export default {data() {return {filterText: '',data2: [],  // 返回所有分类数据defaultProps: {children: 'children',label: 'title'}}},created() {this.getAllSubjectList()},watch: {filterText(val) {this.$refs.tree2.filter(val)}},methods: {getAllSubjectList(){subject.getSubjectList().then(resp=>{this.data2 = resp.data.list})},filterNode(value, data) {if (!value) return truereturn data.title.indexOf(value) !== -1;}}
}
</script>

4. 优化前端过滤功能

 filterNode(value, data) {if (!value) return truereturn data.title.toLowerCase().indexOf(value.toLowerCase()) !== -1}

5. 测试


课程管理【课程发布流程说明】


 

 

 


课程管理【课程相关表关系】


课程管理【添加课程分析】

一、设计数据库

edu_teacher、edu_subject 数据库表在之前的功能中已经添加过了。

  • edu_course_description课程简介表

    CREATE TABLE `edu_course_description` (`id` char(19) NOT NULL COMMENT '课程ID',`description` text COMMENT '课程简介',`gmt_create` datetime NOT NULL COMMENT '创建时间',`gmt_modified` datetime NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程简介';#
    # Data for table "edu_course_description"
    #INSERT INTO `edu_course_description` VALUES ('1104870479077879809','<p>11</p>','2019-03-11 06:23:44','2019-03-11 06:23:44'),('1192252213659774977','<p>测试</p>','2019-11-07 09:27:33','2019-11-13 16:21:28'),('14','','2019-03-13 06:04:43','2019-03-13 06:05:33'),('15','','2019-03-13 06:03:33','2019-03-13 06:04:22'),('18','<p>本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。</p>\n<p>------------------------------------</p>\n<p>视频特点:</p>\n<p>通过学习本Java视频教程,大家能够真正将Java基础知识学以致用、活学活用,构架Java编程思想,牢牢掌握\"源码级\"的Javase核心技术,并为后续JavaWeb等技术的学习奠定扎实基础。<br /><br />1.通俗易懂,细致入微:每个知识点高屋建瓴,深入浅出,简洁明了的说明问题<br />2.具实战性:全程真正代码实战,涵盖上百个企业应用案例及练习<br />3.深入:源码分析,更有 Java 反射、动态代理的实际应用等<br />4.登录尚硅谷官网,技术讲师免费在线答疑</p>','2019-03-06 18:06:36','2019-10-30 19:58:36');
  • edu_video课程小节表
    CREATE TABLE `edu_video` (`id` char(19) NOT NULL COMMENT '视频ID',`course_id` char(19) NOT NULL COMMENT '课程ID',`chapter_id` char(19) NOT NULL COMMENT '章节ID',`title` varchar(50) NOT NULL COMMENT '节点名称',`video_source_id` varchar(100) DEFAULT NULL COMMENT '云端视频资源',`video_original_name` varchar(100) DEFAULT NULL COMMENT '原始文件名称',`sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',`play_count` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '播放次数',`is_free` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否可以试听:0收费 1免费',`duration` float NOT NULL DEFAULT '0' COMMENT '视频时长(秒)',`status` varchar(20) NOT NULL DEFAULT 'Empty' COMMENT 'Empty未上传 Transcoding转码中  Normal正常',`size` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '视频源文件大小(字节)',`version` bigint(20) unsigned NOT NULL DEFAULT '1' COMMENT '乐观锁',`gmt_create` datetime NOT NULL COMMENT '创建时间',`gmt_modified` datetime NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`),KEY `idx_course_id` (`course_id`),KEY `idx_chapter_id` (`chapter_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程视频';#
    # Data for table "edu_video"
    #INSERT INTO `edu_video` VALUES ('1182499307429339137','18','32','第一节','','',0,0,0,0,'',0,1,'2019-10-11 11:32:59','2019-10-11 11:57:38'),('1185312444399071234','14','1','12','','',0,0,0,0,'Empty',0,1,'2019-10-19 05:51:23','2019-10-19 05:51:33'),('1189434737808990210','18','44','测试','','',1,0,0,0,'Empty',0,1,'2019-10-30 14:51:55','2019-10-30 14:51:55'),('1189471423678939138','18','1181729226915577857','test','2b887dc9584d4dc68908780ec57cd3b9','视频',1,0,0,0,'Empty',0,1,'2019-10-30 17:17:41','2019-10-30 17:17:41'),('1189476403626409986','18','1181729226915577857','22','5155c73dc112475cbbddccf4723f7cef','视频.mp4',0,0,0,0,'Empty',0,1,'2019-10-30 17:37:29','2019-10-30 17:37:29'),('1192252824606289921','1192252213659774977','1192252428399751169','第一课时','756cf06db9cb4f30be85a9758b19c645','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,'Empty',0,1,'2019-11-07 09:29:59','2019-11-07 09:29:59'),('1192628092797730818','1192252213659774977','1192252428399751169','第二课时','2a02d726622f4c7089d44cb993c531e1','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,1,0,'Empty',0,1,'2019-11-08 10:21:10','2019-11-08 10:21:22'),('1192632495013380097','1192252213659774977','1192252428399751169','第三课时','4e560c892fdf4fa2b42e0671aa42fa9d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,1,0,'Empty',0,1,'2019-11-08 10:38:40','2019-11-08 10:38:40'),('1194117638832111617','1192252213659774977','1192252428399751169','第四课时','4e560c892fdf4fa2b42e0671aa42fa9d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,'Empty',0,1,'2019-11-12 13:00:05','2019-11-12 13:00:05'),('1196263770832023554','1192252213659774977','1192252428399751169','第五课时','27d21158b0834cb5a8d50710937de330','eae2b847ef8503b81f5d5593d769dde2.mp4',5,0,0,0,'Empty',0,1,'2019-11-18 11:08:03','2019-11-18 11:08:03'),('17','18','15','第一节:Java简介','196116a6fee742e1ba9f6c18f65bd8c1','1',1,1000,1,100,'Draft',0,1,'2019-01-01 13:08:57','2019-10-11 11:26:39'),('18','18','15','第二节:表达式和赋值语句','2d99b08ca0214909899910c9ba042d47','7 - How Do I Find Time for My ',2,999,1,100,'Draft',0,1,'2019-01-01 13:09:02','2019-03-08 03:30:27'),('19','18','15','第三节:String类','51120d59ddfd424cb5ab08b44fc8b23a','eae2b847ef8503b81f5d5593d769dde2.mp4',3,888,0,100,'Draft',0,1,'2019-01-01 13:09:05','2019-11-12 12:50:45'),('20','18','15','第四节:程序风格','2a38988892d84df598752226c50f3fa3','00-day10总结.avi',4,666,0,100,'Draft',0,1,'2019-01-01 13:09:05','2019-10-11 09:20:09');
  • edu_course课程基本信息
    CREATE TABLE `edu_course` (`id` char(19) NOT NULL COMMENT '课程ID',`teacher_id` char(19) NOT NULL COMMENT '课程讲师ID',`subject_id` char(19) NOT NULL COMMENT '课程专业ID',`subject_parent_id` char(19) NOT NULL COMMENT '课程专业父级ID',`title` varchar(50) NOT NULL COMMENT '课程标题',`price` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '课程销售价格,设置为0则可免费观看',`lesson_num` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '总课时',`cover` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '课程封面图片路径',`buy_count` bigint(10) unsigned NOT NULL DEFAULT '0' COMMENT '销售数量',`view_count` bigint(10) unsigned NOT NULL DEFAULT '0' COMMENT '浏览数量',`version` bigint(20) unsigned NOT NULL DEFAULT '1' COMMENT '乐观锁',`status` varchar(10) NOT NULL DEFAULT 'Draft' COMMENT '课程状态 Draft未发布  Normal已发布',`is_deleted` tinyint(3) DEFAULT NULL COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',`gmt_create` datetime NOT NULL COMMENT '创建时间',`gmt_modified` datetime NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`),KEY `idx_title` (`title`),KEY `idx_subject_id` (`subject_id`),KEY `idx_teacher_id` (`teacher_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程';#
    # Data for table "edu_course"
    #INSERT INTO `edu_course` VALUES ('1192252213659774977','1189389726308478977','1178214681139539969','1178214681118568449','java基础课程:test',0.01,2,'https://guli-file-190513.oss-cn-beijing.aliyuncs.com/cover/default.gif',4,387,1,'Normal',0,'2019-11-07 09:27:33','2019-11-18 13:35:03'),('14','1189389726308478977','1101348944971091969','1101348944920760321','XHTML CSS2 JS整站制作教程课程学习',0.00,3,'http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/13/d0086eb0-f2dc-45f7-bba1-744d95e5be0f.jpg',3,44,15,'Normal',0,'2018-04-02 18:33:34','2019-11-16 21:21:45'),('15','1189389726308478977','1101348944971091969','1101348944920760321','HTML5入门课程学习',0.00,23,'http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/13/22997b8e-3606-4d2e-9b4f-09f48418b6e4.jpg',0,51,17,'Normal',0,'2018-04-02 18:34:32','2019-11-12 10:19:20'),('18','1189389726308478977','1178214681139539969','1178214681118568449','Java精品课程',0.01,20,'http://guli-file.oss-cn-beijing.aliyuncs.com/cover/2019/03/06/866e9aca-b530-4f71-a690-72d4a4bfd1e7.jpg',151,737,6,'Normal',0,'2018-04-02 21:28:46','2019-11-18 11:14:52');
  • edu_chapter课程章节表
    CREATE TABLE `edu_chapter` (`id` char(19) NOT NULL COMMENT '章节ID',`course_id` char(19) NOT NULL COMMENT '课程ID',`title` varchar(50) NOT NULL COMMENT '章节名称',`sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '显示排序',`gmt_create` datetime NOT NULL COMMENT '创建时间',`gmt_modified` datetime NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`),KEY `idx_course_id` (`course_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程';#
    # Data for table "edu_chapter"
    #INSERT INTO `edu_chapter` VALUES ('1','14','第一章:HTML',0,'2019-01-01 12:27:40','2019-01-01 12:55:30'),('1181729226915577857','18','第七章:I/O流',70,'2019-10-09 08:32:58','2019-10-09 08:33:20'),('1192252428399751169','1192252213659774977','第一章节',0,'2019-11-07 09:28:25','2019-11-07 09:28:25'),('15','18','第一章:Java入门',0,'2019-01-01 12:27:40','2019-10-09 09:13:19'),('3','14','第二章:CSS',0,'2019-01-01 12:55:35','2019-01-01 12:27:40'),('32','18','第二章:控制台输入和输出',0,'2019-01-01 12:27:40','2019-01-01 12:27:40'),('44','18','第三章:控制流',0,'2019-01-01 12:27:40','2019-01-01 12:27:40'),('48','18','第四章:类的定义',0,'2019-01-01 12:27:40','2019-01-01 12:27:40'),('63','18','第五章:数组',0,'2019-01-01 12:27:40','2019-01-01 12:27:40'),('64','18','第六章:继承',61,'2019-01-01 12:27:40','2019-10-09 08:32:47');

二、使用代码生成器生成课程相关代码

只需要在 CodeGenerator 类中修改数据库表即可,即 strategy.setInclude("edu_course", "edu_course_description", "edu_chapter", "edu_video")

public class CodeGenerator {@Testpublic void run() {// 1、创建代码生成器AutoGenerator mpg = new AutoGenerator();// 2、全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");gc.setOutputDir("D:\\IDEA\\guli_parent\\service\\service_edu" + "/src/main/java"); //输出目录gc.setAuthor("jyu_zwy"); //作者名gc.setOpen(false); //生成后是否打开资源管理器gc.setFileOverride(false); //重新生成时文件是否覆盖gc.setServiceName("%sService"); //去掉Service接口的首字母Igc.setIdType(IdType.ID_WORKER_STR); //主键策略gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型gc.setSwagger2(true);//开启Swagger2模式mpg.setGlobalConfig(gc);// 3、数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("abc123");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);// 4、包配置PackageConfig pc = new PackageConfig();//生成包:com.atguigu.eduservicepc.setModuleName("eduservice"); //模块名pc.setParent("com.atguigu");//生成包:com.atguigu.controllerpc.setController("controller");pc.setEntity("entity");pc.setService("service");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 5、策略配置StrategyConfig strategy = new StrategyConfig();strategy.setInclude("edu_course", "edu_course_description", "edu_chapter", "edu_video");//根据数据库哪张表生成,有多张表就加逗号继续填写strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作strategy.setRestControllerStyle(true); //restful api风格控制器strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符mpg.setStrategy(strategy);// 6、执行mpg.execute();}
}

因为课程简介是依赖于课程的,所以删掉EduCourseDescriptionController 类。


课程管理【添加课程信息】

一、后端实现

1. 实体类

vo 包下创建 CourseInfoVo 类封装表单提交数据。

@ApiModel(value = "课程基本信息", description = "编辑课程基本信息的表单对象")
@Data
public class CourseInfoVo {@ApiModelProperty(value = "课程ID")private String id;@ApiModelProperty(value = "课程讲师ID")private String teacherId;@ApiModelProperty(value = "课程专业ID")private String subjectId;@ApiModelProperty(value = "课程标题")private String title;@ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")private BigDecimal price;@ApiModelProperty(value = "总课时")private Integer lessonNum;@ApiModelProperty(value = "课程封面图片路径")private String cover;@ApiModelProperty(value = "课程简介")private String description;
}

2. controller层

@RestController
@CrossOrigin
@RequestMapping("/eduservice/course")
public class EduCourseController {@Autowiredprivate EduCourseService courseService;// 添加课程基本信息方法@PostMapping("addCourseInfo")public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo) {courseService.saveCourseInfo(courseInfoVo);return R.ok();}
}

3. service层

EduCourseService:

public interface EduCourseService extends IService<EduCourse> {// 添加课程基本信息void saveCourseInfo(CourseInfoVo courseInfoVo);
}

EduCourseServiceImpl:

@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {// 课程描述的注入@Autowiredprivate EduCourseDescriptionService courseDescriptionService;// 添加课程基本信息@Overridepublic void saveCourseInfo(CourseInfoVo courseInfoVo) {// 1.向课程表中添加课程基本信息// CourseInfo 对象 转换成 EduCourse对象EduCourse eduCourse = new EduCourse();BeanUtils.copyProperties(courseInfoVo, eduCourse);int result = baseMapper.insert(eduCourse);if (result <= 0) { // 表示添加失败throw new GuliException(20001, "添加课程信息失败");}// 2.向课程简介表添加课程简介// edu_course_descriptionEduCourseDescription eduCourseDescription = new EduCourseDescription();eduCourseDescription.setDescription(courseInfoVo.getDescription());courseDescriptionService.save(eduCourseDescription);}
}

4. 测试

防止测试报错,需要提前做一下操作:

  1. EntityEduCourseEduCourseDescription 中的创建时间和更新时间中加入对应的注解。
    EduCourse:

    @ApiModelProperty(value = "创建时间")@TableField(fill = FieldFill.INSERT)private Date gmtCreate;@ApiModelProperty(value = "更新时间")@TableField(fill = FieldFill.INSERT_UPDATE)private Date gmtModified;
    

    EduCourseDescription:

    @ApiModelProperty(value = "创建时间")@TableField(fill = FieldFill.INSERT)private Date gmtCreate;@ApiModelProperty(value = "更新时间")@TableField(fill = FieldFill.INSERT_UPDATE)private Date gmtModified;
    
  2. 把数据库表 edu_coursesubject_parent_id 字段设置为可以为 null

  3. 启动项目后,访问http://localhost:8001/swagger-ui.html

     

     
    edu_course:

     
    edu_course_description:

5. 优化

  1. 问题
    edu_course 课程信息表 和 edu_course_description 课程描述表之间没有关联。
    添加进去的数据 id 不一样,没有进行一对一的关联。

  2. 修改 EduCourseServiceImpl 代码

    @Service
    public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {// 课程描述的注入@Autowiredprivate EduCourseDescriptionService courseDescriptionService;// 添加课程基本信息@Overridepublic void saveCourseInfo(CourseInfoVo courseInfoVo) {// 1.向课程表中添加课程基本信息// CourseInfo 对象 转换成 EduCourse对象EduCourse eduCourse = new EduCourse();BeanUtils.copyProperties(courseInfoVo, eduCourse);int result = baseMapper.insert(eduCourse);if (result <= 0) { // 表示添加失败throw new GuliException(20001, "添加课程信息失败");}// 获取添加之后课程信息的idString cid = eduCourse.getId();// 2.向课程简介表添加课程简介// edu_course_descriptionEduCourseDescription eduCourseDescription = new EduCourseDescription();eduCourseDescription.setDescription(courseInfoVo.getDescription());// 手动设置描述课程表的id,与上面的课程信息表id关联eduCourseDescription.setId(cid);courseDescriptionService.save(eduCourseDescription);}
    }

  3. 修改 EduCourseDescriptionid 生成策略,设置为 手动输入

  4. 修改controller,添加返回课程id

    @RestController
    @CrossOrigin
    @RequestMapping("/eduservice/course")
    public class EduCourseController {@Autowiredprivate EduCourseService courseService;// 添加课程基本信息方法@PostMapping("addCourseInfo")public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo) {// 返回添加之后课程id,为了后面的添加大纲使用String id = courseService.saveCourseInfo(courseInfoVo);return R.ok().data("courseId", id);}
    }
    
  5. 修改service,返回String

    public interface EduCourseService extends IService<EduCourse> {// 添加课程基本信息String saveCourseInfo(CourseInfoVo courseInfoVo);
    }
  6. 测试

     

     


二、前端实现

1. 添加路由

 {// 地址输入path: '/course',component: Layout,// redirect: 重定向地址redirect: '/course/list',name: '课程管理',// title:显示标签  icon:显示图标meta: { title: '课程管理', icon: 'example' },children: [{path: 'list',name: '课程列表',component: () => import('@/views/edu/course/list'),meta: { title: '课程列表', icon: 'table' }},{path: 'info',name: '添加课程',component: () => import('@/views/edu/course/info'),meta: { title: '添加课程', icon: 'tree' }},{path: 'info/:id',name: 'EduCourseInfoEdit',component: () => import('@/views/edu/course/info'),meta: { title: '编辑课程基本信息', noCache: true },hidden: true},{path: 'chapter/:id',name: 'EduCourseChapterEdit',component: () => import('@/views/edu/course/chapter'),meta: { title: '编辑课程大纲', noCache: true },hidden: true},{path: 'publish/:id',name: 'EduCoursePublishEdit',component: () => import('@/views/edu/course/publish'),meta: { title: '发布课程', noCache: true },hidden: true}]},

2. 添加vue组件

3. 整合步骤条组件

  1. 课程信息页面 info.vue
<template><div class="app-container"><h2 style="text-align: center">发布新课程</h2><el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;"><el-step title="填写课程基本信息" /><el-step title="创建课程大纲" /><el-step title="最终发布" /></el-steps><el-form label-width="120px"><el-form-item><el-button :disabled="saveBtnDisabled" type="primary" @click="next">保存并下一步</el-button></el-form-item></el-form></div>
</template><script>
export default {data() {return {saveBtnDisabled:false,};},created(){},methods: {next() {//跳转到第二步this.$router.push({path:'/course/chapter/1'})},}
};
</script><style></style>
  1. 课程大纲页面 chapter.vue
.<template><div class="app-container"><h2 style="text-align: center">发布新课程</h2><el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;"><el-step title="填写课程基本信息" /><el-step title="创建课程大纲" /><el-step title="最终发布" /></el-steps><el-form label-width="120px"><el-form-item><el-button @click="previous">上一步</el-button><el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button></el-form-item></el-form></div>
</template><script>
export default {data() {return {saveBtnDisabled: false,};},created() {},methods: {//跳转到上一步previous() {this.$router.push({ path: "/course/info/1" });},next() {//跳转到第三步this.$router.push({ path: "/course/publish/1" });},}};
</script><style>
</style>
  1. 课程发布页面 publish.vue
.<template><div class="app-container"><h2 style="text-align: center">发布新课程</h2><el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;"><el-step title="填写课程基本信息" /><el-step title="创建课程大纲" /><el-step title="最终发布" /></el-steps><el-form label-width="120px"><el-form-item><el-button @click="previous">返回修改</el-button><el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button></el-form-item></el-form></div>
</template><script>
export default {data() {return {saveBtnDisabled: false,};},methods: {//跳转到上一步previous() {    this.$router.push({ path: "/course/chapter/1" });},publish(){this.$router.push({ path: "/course/list" });}},};
</script><style>
</style>


 

 


课程管理【编辑课程基本信息】

一、前端实现

1. 定义api

import request from '@/utils/request' // 引入已经封装好的axios 和 拦截器export default {// 添加课程信息addCourseInfo(courseInfo) {return request({url: `/eduservice/course/addCourseInfo`,method: 'post', data: courseInfo})}
}

2. 组件模板

<template><div class="app-container"><h2 style="text-align: center">发布新课程</h2><el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;"><el-step title="填写课程基本信息" /><el-step title="创建课程大纲" /><el-step title="最终发布" /></el-steps><el-form label-width="120px"><el-form-item label="课程标题"><el-inputv-model="courseInfo.title"placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/></el-form-item><!-- 所属分类 TODO --><!-- 课程讲师 TODO --><el-form-item label="总课时"><el-input-number:min="0"v-model="courseInfo.lessonNum"controls-position="right"placeholder="请填写课程的总课时数"/></el-form-item><!-- 课程简介 TODO --><el-form-item label="课程简介"><el-input v-model="courseInfo.description" placeholder="" /></el-form-item><!-- 课程封面 TODO --><el-form-item label="课程价格"><el-input-number:min="0"v-model="courseInfo.price"controls-position="right"placeholder="免费课程请设置为0元"/>元</el-form-item><el-form-item><el-button:disabled="saveBtnDisabled"type="primary"@click="saveOrUpdate">保存并下一步</el-button></el-form-item></el-form></div>
</template><script>import course from "@/api/edu/course"export default {data() {return {saveBtnDisabled:false,courseInfo: {title: "",subjectId: "",teacherId: "",lessonNum: 0,description: "",cover: "",price: 0,},};},created(){},methods: {saveOrUpdate() {course.addCourseInfo(this.courseInfo).then(response => {// 提示this.$message({message: "添加课程信息成功",type: "success",})//跳转到第二步this.$router.push({ path: "/course/chapter/"+response.data.courseId})})}}
};
</script><style></style>

3. 测试


 


二、讲师下拉列表实现

1. 组件模板

src\views\edu\course\info.vue

      <!--课程讲师--><el-form-item label="课程讲师"><el-select v-model="courseInfo.teacherId" placeholder="请选择"><el-optionv-for="teacher in teacherLists":key="teacher.id":label="teacher.name":value="teacher.id"></el-option></el-select></el-form-item>

2. 定义api

src\api\edu\course.js

   // 查询所有讲师getListTeacher(){return request({url:"/eduservice/edu-teacher/findAll",method: 'get',})}

3. 组件js

<script>import course from "@/api/edu/course"export default {data() {return {saveBtnDisabled:false,courseInfo: {title: "",subjectId: "",teacherId: "",lessonNum: 0,description: "",cover: "",price: 0,},teacherList:[] // 封装所有讲师数据};},created(){// 初始化所有讲师this.getListTeacher()},methods: {// 查询所有的讲师getListTeacher() {course.getListTeacher().then(response => {this.teacherList = response.data.items})},saveOrUpdate() {course.addCourseInfo(this.courseInfo).then(response => {// 提示this.$message({message: "添加课程信息成功",type: "success",})//跳转到第二步this.$router.push({ path: "/course/chapter/"+response.data.courseId})})}}
};
</script>

4. 测试


 


三、课程分类多级联动的实现

1. 级联显示一级分类

  1. 组件数据定义
    定义在 data 中:

    subjectOneList: [], //封装所以一级分类数据
    subjectTwoList: [], //封装二级分类数据  
  2. 组件模板

    <el-form-item label="课程分类"><el-selectv-model="courseInfo.subjectParentId"placeholder="一级分类"@change="subjectLevelOneChanged"><el-optionv-for="subject in subjectOneList":key="subject.id":label="subject.title":value="subject.id"></el-option></el-select>
    </el-form-item>
    
  3. 组件js

    <script>import course from "@/api/edu/course"
    import subject from "@/api/edu/subject"export default {data() {........subjectOneList:[], // 一级分类subjectTwoList:[], // 二级分类};},created(){.....// 初始化一级分类this.getOneSubject()},methods: {// 查询所有的一级分类getOneSubject() {subject.getSubjectList() .then(response => {this.subjectOneList = response.data.list})},.......}}
    };
    </script>
    
  4. 测试


1. 级联显示二级分类

  1. 组件模板

    <el-select v-model="courseInfo.subjectId" placeholder="二级分类"><el-optionv-for="subject in subjectTwoList":key="subject.id":label="subject.title":value="subject.id"></el-option></el-select>
    
  2. 注册change事件
    在一级分类的 < el-select > 组件中注册 change 事件:

  3. 定义change事件方法

     // 点击某一级分类,触发change,显示对应的二级分类subjectLevelOneChanged(value) {// value就是一级分类的id值// 遍历所有的分类,包含一级和二级for  (let i = 0; i < this.subjectOneList.length; i ++ ) {// subjectOneList[i]: 每个一级分类// 判断:所有一级分类id 和 点击一级分类id是否一样if (this.subjectOneList[i].id === value) {// 从一级分类获取里面所有的二级分类this.subjectTwoList = this.subjectOneList[i].children;// 把二级分类id值清空this.courseInfo.subjectId = "";}}},
    
  4. 测试


四、课程封面

1. 定义data数据

BASE_API: process.env.BASE_API, // 接口API地址

2. 组件模板

<!-- 课程封面 --><el-form-item label="课程封面"><el-upload:show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload":action="BASE_API + '/eduoss/fileoss'"class="avatar-uploader"><img :src="courseInfo.cover" style="width: 200px; height: 150px"/></el-upload></el-form-item>

3. 结果回调

    // 上传封面成功调用的方法handleAvatarSuccess(res, file) {this.courseInfo.cover = res.data.url},// 上转之前调用的方法beforeAvatarUpload(file) {const isJPG = file.type === "image/jpeg";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上传头像图片只能是 JPG 格式!");}if (!isLt2M) {this.$message.error("上传头像图片大小不能超过 2MB!");}return isJPG && isLt2M;},

4. 测试


 

 
 
创作不易,如果有帮助到你,请给文章点个赞和收藏,让更多的人看到!!!
关注博主不迷路,内容持续更新中。

谷粒学院——Day07【课程发布-添加课程信息】相关推荐

  1. 课程发布-添加课程信息

    一.需求 01-课程发布表单-步骤导航 二.配置路由 1.添加路由 // 课程管理 {path: '/edu/course',component: Layout,redirect: '/edu/cou ...

  2. 谷粒学苑 —— 8、课程管理:课程发布页面3 —— 信息确认及发布

    目录 1.确认信息的显示 1.1.后端 1.1.1.定义确认信息 VO 1.1.2.根据课程 ID 获取确认信息 1.1.3.测试异常:Invalid bound statement (not fou ...

  3. 谷粒学院(九)EasyExcel | 课程分类模块

    文章目录 一.EasyExcel 简介 1.Excel导入导出的应用场景 2.EasyExcel特点 3.案例1:EasyExcel进行Excel写操作 4.案例2:EasyExcel进行Excel读 ...

  4. 课程分类管理-添加课程分类

    业务处理 SubjectAdminController @Api(description="课程分类管理") @CrossOrigin //跨域 @RestController @ ...

  5. 【谷粒学院项目开发44】课程大纲——小节的添删

    1.后端 2.前端 2.1"添加小节"按钮 2.2点击"添加小节"按钮,弹出表单 2.3 api 2.4 chapter.vue 2.5 "删除小节& ...

  6. 课程管理---添加课程分类 --后端

    先用代码生成器生成 subject 的代码层 创建方法然后再 service 和impl中实现 读取文件 添加监听器

  7. Day206.课程分类【导入功能】前端实现、 课程分类列表【显示功能】、课程管理【模块需求、添加课程功能】 -谷粒学院

    谷粒学院 [课程分类]-导入前端实现 一.配置路由 1.添加路由 src/router/index.js //课程分类{path: 'subject',component: Layout,redire ...

  8. 谷粒学院(十)课程管理模块 | 课程大纲列表 | 二级联动 | 富文本编辑器

    一.课程添加分析 发布流程图 数据表对应 课程相关表的关系 二.课程管理–添加课程后端 1.使用代码生成器生成相关课程相关的代码 CodeGenerator类中生成 2.细节问题 (1)创建vo实体类 ...

  9. 学成在线--16.添加课程计划

    文章目录 一.需求分析 二.API接口 三.后端 1.Dao 2.Service 3.Controller 4.测试 四.前端 1.页面原型说明 1)添加按钮 2)视图部分 3)在数据模型中添加如下变 ...

最新文章

  1. 看完秒懂大数据用户画像!
  2. Js实现点击超链接弹出层,效果仿Discuz登录!
  3. “火柴棍式”程序员面试题
  4. markdownpad2 html渲染组件出错_Day68 Django forms组件
  5. bootstrap-关闭按钮
  6. Matlab:成功解决 Inner matrix dimension must agree
  7. P2756 飞行员配对方案问题【网络流24题】
  8. Unity加载本地图片的2种方式
  9. IOException: Broken pipe
  10. [论文翻译]NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE
  11. 人工智能写诗全程测试输出的诗句
  12. springboot ---微信ocr身份证识别
  13. 微商怎么引流被加精准粉?微商有效引流被加方法
  14. 固建机器人钢结构智能生产线 改善钢结构行业品质
  15. 分位数回归模型学习笔记
  16. 如何打开usb计算机连接打印机驱动,打印机USB连接安装设置及常见问题处理
  17. Windows如何设置右键快捷键
  18. 国家也补贴?有华为认证证书的你,就能拿它(附详细操作)
  19. POJ 图论---1_Uriel's Corner Uriel's Coding Learning Cubing Zone
  20. 墙裂推荐6本适用于所有Java程序员阅读书籍

热门文章

  1. git push时需要账号密码
  2. Clang-format 配置文件
  3. 说说 df.describe(include=‘all‘)
  4. ppt复制切片器_攻略|致敬20个可以提升效率的PPT操作技巧
  5. 手机进程设置多少个最好_iPhone耗电快别怪电池不行,简单设置这4个开关,手机省电又流畅...
  6. redis缓存命中率
  7. TIA博途SCL编程学习2_sin(x)
  8. wps如何只让他显示3级标题_如何在WPS word中设置多级标题
  9. Java的特点与特性
  10. 业内资深运营整理的自媒体短视频运营问题汇总