• Java项目硅谷课堂学习笔记-P7点播模块管理-后台-管理员端


    P7点播模块管理 后台-管理员端-发布新课程

    1.后台-管理员端发布新课程

    请添加图片描述

    1.1功能介绍

    管理员,添加课程基本信息
    用户,在公众号端可以看到信息
    在这里插入图片描述分为三个部分去实现

    1. 填写课程基本信息
    2. 创建课程大纲
    3. 发布课程

    1.2所涉及的数据库表

    请添加图片描述

    • 一个课程中对应多个章节表
    • 一个章节表对应多个小节和视频
    • 课程描述和课程基本信息表一一对应
    • 讲师表 一个讲师可讲多门课
    • 课程分类表 包含多个课程

    在这里插入图片描述

    /*
    SQLyog Ultimate - MySQL GUI v8.2 
    MySQL - 5.7.29-32-log : Database - glkt_vod
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    CREATE DATABASE /*!32312 IF NOT EXISTS*/`glkt_vod` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
    
    USE `glkt_vod`;
    
    /*Table structure for table `chapter` */
    
    DROP TABLE IF EXISTS `chapter`;
    
    CREATE TABLE `chapter` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `course_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程ID',
      `title` varchar(50) NOT NULL COMMENT '章节名称',
      `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '显示排序',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      KEY `idx_course_id` (`course_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程';
    
    /*Data for the table `chapter` */
    
    insert  into `chapter`(`id`,`course_id`,`title`,`sort`,`create_time`,`update_time`,`is_deleted`) values (1,18,'第七章:I/O流',7,'2021-11-05 03:05:51','2021-12-01 05:48:44',0),(2,2,'第一章节',0,'2021-11-05 03:05:51','2021-11-05 03:38:14',0),(3,3,'第一章',0,'2021-11-05 03:05:51','2021-11-05 03:38:24',0),(4,4,'第一章',0,'2021-11-05 03:05:51','2021-11-05 03:38:34',0),(5,14,'第一章:HTML',0,'2021-11-05 03:05:51','2021-11-05 03:05:51',0),(6,14,'第二章:CSS',0,'2021-11-05 03:05:51','2021-11-05 03:05:51',0),(7,5,'第一章',0,'2021-11-05 03:05:51','2021-11-05 03:38:50',0),(8,15,'第一章',0,'2021-11-05 03:05:51','2021-11-05 03:39:03',0),(9,6,'数据仓库基础',0,'2021-11-05 03:05:51','2021-11-05 03:39:14',0),(10,7,'课程基础',0,'2021-11-05 03:05:51','2021-11-05 03:39:26',0),(11,8,'介绍及原理',0,'2021-11-05 03:05:51','2021-11-05 03:39:38',0),(12,1,'spark介绍',0,'2021-11-05 03:05:51','2021-11-05 03:39:50',0),(15,18,'第一章:Java入门',1,'2021-11-05 03:05:51','2021-12-01 05:48:35',0),(16,18,'第二章:控制台输入和输出',2,'2021-11-05 03:05:51','2021-12-01 05:48:36',0),(17,18,'第三章:控制流',3,'2021-11-05 03:05:51','2021-12-01 05:48:36',0),(18,18,'第四章:类的定义',4,'2021-11-05 03:05:51','2021-12-01 05:48:38',0),(19,18,'第五章:数组',5,'2021-11-05 03:05:51','2021-12-01 05:48:41',0),(20,18,'第六章:继承',6,'2021-11-05 03:05:51','2021-12-01 05:48:42',0),(65,19,'入门及安装配置',0,'2021-11-22 11:10:56','2021-11-22 11:10:56',0),(66,19,'mysql原理',1,'2021-11-22 11:11:17','2021-11-22 11:11:17',0);
    
    /*Table structure for table `comment` */
    
    DROP TABLE IF EXISTS `comment`;
    
    CREATE TABLE `comment` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `course_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程id',
      `teacher_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '讲师id',
      `user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '会员id',
      `nickname` varchar(50) DEFAULT NULL COMMENT '会员昵称',
      `avatar` varchar(255) DEFAULT NULL COMMENT '会员头像',
      `content` varchar(500) DEFAULT NULL COMMENT '评论内容',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      KEY `idx_course_id` (`course_id`),
      KEY `idx_teacher_id` (`teacher_id`),
      KEY `idx_member_id` (`user_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评论';
    
    /*Data for the table `comment` */
    
    /*Table structure for table `course` */
    
    DROP TABLE IF EXISTS `course`;
    
    CREATE TABLE `course` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `teacher_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程讲师ID',
      `subject_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程专业ID',
      `subject_parent_id` bigint(20) NOT NULL DEFAULT '0' 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 '总课时',
      `duration_sum` int(11) 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 '浏览数量',
      `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '课程状态 0未发布 1已发布',
      `publish_time` datetime DEFAULT NULL COMMENT '课程发布时间',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      KEY `idx_title` (`title`),
      KEY `idx_subject_id` (`subject_id`),
      KEY `idx_teacher_id` (`teacher_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程';
    
    /*Data for the table `course` */
    
    insert  into `course`(`id`,`teacher_id`,`subject_id`,`subject_parent_id`,`title`,`price`,`lesson_num`,`duration_sum`,`cover`,`buy_count`,`view_count`,`status`,`publish_time`,`create_time`,`update_time`,`is_deleted`) values (1,1,16,14,'Spark','21800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/10/39e51c23-e2fa-4a8a-9239-3c0d5268f34d.jpg',1679,34634,1,'2021-11-05 11:30:14','2021-11-05 03:05:16','2021-11-24 06:37:39',0),(2,1,2,1,'java基础课程','19800.00',2,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/bd89ae0b-e660-47fd-9ed7-ad8733a46c65.jpg',5999,10048,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:37',0),(3,1,15,14,'尚硅谷大数据技术之Flume(2019新版)','20800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/806572e0-6d85-485e-8784-d2cb4716a881.jpg',4234,23780,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:36',0),(4,2,15,14,'尚硅谷大数据技术之HBase(2019新版)','19800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/a16c5694-3037-4330-b1c5-438052081fcb.jpg',6675,90383,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:34',0),(5,1,1,2,'尚硅谷大数据技术之Kafka(2019新版)','22800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/f5ada6ba-8d12-4c00-8ad9-6a521f71b0da.jpg',2349,13546,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:33',0),(6,2,15,14,'尚硅谷大数据项目之电商数仓','21800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/10/dd2da284-b37f-4818-ba9a-c55667837f5a.jpg',898,8977,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:32',0),(7,2,15,14,'尚硅谷大数据技术之Sqoop','23800.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/10/9452b057-6ad6-4600-891e-b168083fee4d.jpg',1286,45695,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:31',0),(8,1,16,14,'大数据Scala入门到精通(新版)','0.00',0,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/10/f2cd321f-6378-4e92-8515-0b8f42f2770b.jpg',900,15496,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:13',0),(14,1,4,3,'XHTML CSS2 JS整站制作教程课程学习','21800.00',3,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/2829c8d1-f16f-44a4-96cd-d13b451a8d56.jpg',3452,21010,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:28',0),(15,2,2,1,'  14417人 分享 收藏 SpringMVC','22800.00',23,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/273ddd90-5ef7-40e5-9ffd-86e8175fc229.jpg',892,9107,0,NULL,'2021-11-05 03:05:16','2021-11-24 06:37:24',0),(18,2,2,1,'Java精品课程','22800.00',20,100000,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/cover/2021/08/09/e4ee03d7-52bd-41ca-99f9-04dc23250a71.jpg',6784,67629,1,'2021-11-19 14:16:19','2021-11-05 03:05:16','2021-11-24 06:37:25',0),(19,1,2,1,'JAVA之Mysql基础','1000.00',10,100201,'http://47.93.148.192:9000/gmall/20211122/1504320cbe2b246514.jpg',0,155,1,'2021-11-25 09:57:42','2021-11-22 11:09:22','2021-11-25 01:57:39',0);
    
    /*Table structure for table `course_collect` */
    
    DROP TABLE IF EXISTS `course_collect`;
    
    CREATE TABLE `course_collect` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `course_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程讲师ID',
      `user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '会员ID',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程收藏';
    
    /*Data for the table `course_collect` */
    
    /*Table structure for table `course_description` */
    
    DROP TABLE IF EXISTS `course_description`;
    
    CREATE TABLE `course_description` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
      `course_id` bigint(20) DEFAULT NULL,
      `description` text COMMENT '课程简介',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COMMENT='课程简介';
    
    /*Data for the table `course_description` */
    
    insert  into `course_description`(`id`,`course_id`,`description`,`create_time`,`update_time`,`is_deleted`) values (1,1,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:29:33','2021-11-08 11:27:01',0),(2,2,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:30:07','2021-11-08 11:27:04',0),(3,3,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:30:47','2021-11-08 11:27:07',0),(4,4,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    \n

    ------------------------------------

    \n

    视频特点:

    \n

    通过学习本Java视频教程,大家能够真正将Java基础知识学以致用、活学活用,构架Java编程思想,牢牢掌握\"源码级\"的Javase核心技术,并为后续JavaWeb等技术的学习奠定扎实基础。

    1.通俗易懂,细致入微:每个知识点高屋建瓴,深入浅出,简洁明了的说明问题
    2.具实战性:全程真正代码实战,涵盖上百个企业应用案例及练习
    3.深入:源码分析,更有 Java 反射、动态代理的实际应用等
    4.登录尚硅谷官网,技术讲师免费在线答疑

    \n'
    ,'2021-11-05 03:33:18','2021-11-08 11:25:23',0),(5,5,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:41:05','2021-11-08 11:27:10',0),(6,6,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:41:27','2021-11-08 11:27:12',0),(7,7,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:41:43','2021-11-08 11:27:22',0),(8,8,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    \n

    ------------------------------------

    \n

    视频特点:

    \n

    通过学习本Java视频教程,大家能够真正将Java基础知识学以致用、活学活用,构架Java编程思想,牢牢掌握\"源码级\"的Javase核心技术,并为后续JavaWeb等技术的学习奠定扎实基础。

    1.通俗易懂,细致入微:每个知识点高屋建瓴,深入浅出,简洁明了的说明问题
    2.具实战性:全程真正代码实战,涵盖上百个企业应用案例及练习
    3.深入:源码分析,更有 Java 反射、动态代理的实际应用等
    4.登录尚硅谷官网,技术讲师免费在线答疑

    '
    ,'2021-11-05 03:42:01','2021-11-08 11:25:30',0),(9,14,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:42:16','2021-11-08 11:27:24',0),(10,15,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:42:32','2021-11-08 11:27:26',0),(11,18,'

    本套Java视频完全针对零基础学员,课堂实录,自发布以来,好评如潮!Java视频中注重与学生互动,讲授幽默诙谐、细致入微,覆盖Java基础所有核心知识点,同类Java视频中也是代码量大、案例多、实战性强的。同时,本Java视频教程注重技术原理剖析,深入JDK源码,辅以代码实战贯穿始终,用实践驱动理论,并辅以必要的代码练习。

    '
    ,'2021-11-05 03:42:51','2021-11-08 11:27:28',0),(12,19,' 数据库就像一棵常青的技能树,无论是初级程序员还是CTO、首席架构师都能从中汲取足够的技术养料。菜鸟往往积累单点技术,如 DML、DDL、存储过程和函数、约束、索引的数据结构,老鸟则需要吃透底层原理,数据库事务ACID如何实现?锁机制与MVCC又是怎么回事?分布式场景下数据库怎么优化保持高性能?\n 知道怎么用是一方面,知道为什么则是更为稀缺的能力。程序员核心能力中至关重要的一点:精通数据库。精通意味着:第一,形成知识网,更灵活地应对突发问题;第二,懂底层原理,更自由地应对复杂多变的业务场景。','2021-11-22 11:09:22','2021-11-22 11:09:22',0); /*Table structure for table `subject` */ DROP TABLE IF EXISTS `subject`; CREATE TABLE `subject` ( `id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '主键', `title` varchar(10) NOT NULL COMMENT '类别名称', `parent_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '父ID', `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程科目'; /*Data for the table `subject` */ insert into `subject`(`id`,`title`,`parent_id`,`sort`,`create_time`,`update_time`,`is_deleted`) values (1,'后端开发',0,1,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(2,'Java',1,1,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(3,'前端开发',0,3,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(4,'JavaScript',3,4,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(5,'云计算',0,5,'2019-09-29 15:47:25','2021-11-12 07:13:22',1),(6,'Docker',5,5,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(7,'Linux',5,6,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(8,'系统/运维',0,7,'2019-09-29 15:47:25','2021-11-12 07:12:54',1),(9,'Linux',8,7,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(10,'Windows',8,8,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(11,'数据库',0,9,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(12,'MySQL',11,9,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(13,'MongoDB',11,10,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(14,'大数据',0,11,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(15,'Hadoop',14,11,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(16,'Spark',14,12,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(17,'人工智能',0,13,'2019-09-29 15:47:25','2021-11-12 03:30:34',1),(18,'Python',17,13,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(19,'编程语言',0,14,'2019-09-29 15:47:25','2021-11-12 03:29:04',1),(20,'Java',19,14,'2019-09-29 15:47:25','2019-09-29 15:47:25',0),(21,'Python',19,2,'2019-09-30 16:19:22','2019-09-30 16:19:22',0),(22,'HTML/CSS',19,3,'2019-09-30 16:19:22','2019-09-30 16:19:22',0); /*Table structure for table `teacher` */ DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(20) NOT NULL COMMENT '讲师姓名', `intro` varchar(500) NOT NULL DEFAULT '' COMMENT '讲师简介', `career` varchar(500) DEFAULT NULL COMMENT '讲师资历,一句话说明讲师', `level` int(10) unsigned NOT NULL COMMENT '头衔 1高级讲师 2首席讲师', `avatar` varchar(255) DEFAULT NULL COMMENT '讲师头像', `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序', `join_date` date DEFAULT NULL COMMENT '入驻时间', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `uk_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='讲师'; /*Data for the table `teacher` */ insert into `teacher`(`id`,`name`,`intro`,`career`,`level`,`avatar`,`sort`,`join_date`,`create_time`,`update_time`,`is_deleted`) values (1,'张老师','高级讲师','高级讲师',1,'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIB1WtJibSTqXvnJccFhOR1cSpVpdQ3BP5eTPCUO9CyI1feDefMoUFyA4E2C1oe2j8VMLrtAyBricvA/132',0,'2021-11-02','2021-11-05 03:18:36','2021-11-08 01:50:46',0),(2,'李老师','高级讲师','高级讲师',1,'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIB1WtJibSTqXvnJccFhOR1cSpVpdQ3BP5eTPCUO9CyI1feDefMoUFyA4E2C1oe2j8VMLrtAyBricvA/132',0,'2021-11-02','2021-11-05 03:18:51','2021-11-08 01:50:49',0),(4,'钟老师','高级讲师','高级讲师',1,'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIB1WtJibSTqXvnJccFhOR1cSpVpdQ3BP5eTPCUO9CyI1feDefMoUFyA4E2C1oe2j8VMLrtAyBricvA/132',0,'2021-11-02','2021-11-08 05:51:21','2021-11-08 06:24:28',0),(5,'钱老师','钱老师','钱老师',1,'https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eo8uwBUP6f5JtibWlkmpPAVjsSsibMaFupwFRyo2Vr5Gkc33uctiasfOFgZADd5X1NYP82bKYjMDbFnA/132',3,'2021-11-01','2021-11-22 13:26:58','2021-11-23 10:26:54',0),(6,'宋老师','宋老师','宋老师',1,'https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eo8uwBUP6f5JtibWlkmpPAVjsSsibMaFupwFRyo2Vr5Gkc33uctiasfOFgZADd5X1NYP82bKYjMDbFnA/132',4,'2021-11-02','2021-11-23 10:25:58','2021-11-23 10:26:53',0); /*Table structure for table `video` */ DROP TABLE IF EXISTS `video`; CREATE TABLE `video` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `course_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '课程ID', `chapter_id` bigint(20) NOT NULL DEFAULT '0' 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 '视频时长(秒)', `size` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '视频源文件大小(字节)', `version` bigint(20) unsigned NOT NULL DEFAULT '1' COMMENT '乐观锁', `status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '状态', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `idx_course_id` (`course_id`), KEY `idx_chapter_id` (`chapter_id`) ) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程视频'; /*Data for the table `video` */ insert into `video`(`id`,`course_id`,`chapter_id`,`title`,`video_source_id`,`video_original_name`,`sort`,`play_count`,`is_free`,`duration`,`size`,`version`,`status`,`create_time`,`update_time`,`is_deleted`) values (1,18,16,'第一节','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:54',0),(2,14,5,'html基础','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:55',0),(4,18,26,'IO高级','3b71d85d93554e7dbb59becdf823f63d','视频',1,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:56',0),(5,18,16,'IO流基础','3b71d85d93554e7dbb59becdf823f63d','视频.mp4',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:56',0),(6,2,2,'第一课时','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:58',0),(7,2,2,'第二课时','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:17:57',0),(8,2,2,'第三课时','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:20',0),(9,2,2,'第四课时','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:20',0),(10,2,2,'第五课时','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',5,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:19',0),(11,3,3,'01-尚硅谷-Flume(课程介绍)','3b71d85d93554e7dbb59becdf823f63d','01-尚硅谷-Flume(课程介绍).avi',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:21',0),(12,3,3,'02-尚硅谷-Flume(概念)','3b71d85d93554e7dbb59becdf823f63d','02-尚硅谷-Flume(概念).avi',1,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:21',0),(13,3,3,'03-尚硅谷-Flume(概念)','3b71d85d93554e7dbb59becdf823f63d','03-尚硅谷-Flume(架构).avi',2,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:22',0),(14,4,4,'01_尚硅谷_HBase_课程介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:23',0),(15,4,4,'02_尚硅谷_HBase_介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:23',0),(16,4,4,'03_尚硅谷_HBase_特点','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:24',0),(17,5,7,'01_尚硅谷_Kafka_课程介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:16',0),(18,5,7,'02_尚硅谷_Kafka_消息队列介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:15',0),(19,5,7,'03_尚硅谷_Kafka_概念','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:14',0),(20,14,6,'CSS基础','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:14',0),(21,15,8,'spring mvc基础','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:13',0),(22,15,8,'spring mvc集成','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:13',0),(23,6,9,'01_数仓项目_课程介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:12',0),(24,6,9,'02_数仓项目_采集课程介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:12',0),(25,6,9,'03_数仓项目_数仓概念_业务数据','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:11',0),(26,7,10,'01_尚硅谷_Sqoop_课程介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:10',0),(27,7,10,'02_尚硅谷_Sqoop_安装','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:10',0),(28,7,10,'03_尚硅谷_Sqoop_原理','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:09',0),(29,8,11,'01 - Scala - 语言介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:09',0),(30,8,11,'02 - Scala - map集合','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:08',0),(31,1,12,'01_Spark之课程体系介绍','3b71d85d93554e7dbb59becdf823f63d','',0,0,1,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:08',0),(32,1,12,'02_Spark之课程原理','3b71d85d93554e7dbb59becdf823f63d','',0,0,0,0,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:07',0),(33,18,15,'第一节:Java简介','3b71d85d93554e7dbb59becdf823f63d','1',1,1000,1,100,0,1,0,'2021-11-05 03:06:04','2021-12-01 05:45:14',0),(34,18,15,'第二节:表达式和赋值语句','3b71d85d93554e7dbb59becdf823f63d','7 - How Do I Find Time for My ',2,999,1,100,0,1,0,'2021-11-05 03:06:04','2021-12-03 10:18:06',0),(35,18,15,'第三节:String类','3b71d85d93554e7dbb59becdf823f63d','eae2b847ef8503b81f5d5593d769dde2.mp4',3,888,0,100,0,1,0,'2021-11-05 03:06:04','2021-12-01 05:45:16',0),(36,18,15,'第四节:程序风格','3b71d85d93554e7dbb59becdf823f63d','00-day10总结.avi',4,666,0,100,0,1,0,'2021-11-05 03:06:04','2021-12-01 05:45:17',0),(37,19,65,'mysql安装','3b71d85d93554e7dbb59becdf823f63d',NULL,0,0,1,0,0,1,0,'2021-11-22 11:12:11','2021-12-03 10:18:02',0),(38,19,65,'mysql配置','3b71d85d93554e7dbb59becdf823f63d','3.msyql配置.avi',1,0,1,0,0,1,0,'2021-11-22 11:15:52','2021-12-03 10:18:03',0),(39,19,66,'mysql内部结构','3b71d85d93554e7dbb59becdf823f63d','4.mysql的内部结构.avi',0,0,1,0,0,1,0,'2021-11-22 11:17:34','2021-12-03 10:18:04',0),(40,19,66,'认识索引','3b71d85d93554e7dbb59becdf823f63d','8.认识索引.avi',1,0,0,0,0,1,0,'2021-11-22 11:18:45','2021-12-03 10:18:05',0),(41,19,66,'导入测试数据','a4b66c13cfaf4071bdb7ce988e7d7444','13.导入50w条记录.avi',0,0,0,201.2,0,1,0,'2021-12-16 16:15:59','2021-12-16 16:15:59',0); /*Table structure for table `video_visitor` */ DROP TABLE IF EXISTS `video_visitor`; CREATE TABLE `video_visitor` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `course_id` bigint(20) DEFAULT NULL COMMENT '课程id', `video_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '视频id', `user_id` varchar(50) NOT NULL DEFAULT '0' COMMENT '来访者用户id', `nick_name` varchar(100) DEFAULT NULL COMMENT '昵称', `join_time` varchar(30) DEFAULT NULL COMMENT '进入时间', `leave_time` varchar(30) DEFAULT NULL COMMENT '离开的时间', `duration` bigint(20) DEFAULT NULL COMMENT '用户停留的时间(单位:秒)', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_deleted` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COMMENT='视频来访者记录表'; /*Data for the table `video_visitor` */ insert into `video_visitor`(`id`,`course_id`,`video_id`,`user_id`,`nick_name`,`join_time`,`leave_time`,`duration`,`create_time`,`update_time`,`is_deleted`) values (1,19,37,'1','晴天','2021-11-22 21:39:27.089',NULL,4,'2021-11-22 13:39:27','2021-11-22 13:39:27',0),(2,19,38,'1','晴天','2021-11-20 21:39:32.071','2021-11-22 21:44:24.026',696,'2021-11-22 13:39:32','2021-11-25 02:12:41',0),(3,7,26,'1','晴天','2021-11-23 18:09:46.899','2021-11-23 18:10:13.004',5,'2021-11-23 10:09:47','2021-11-23 10:09:47',0),(4,19,38,'24','简','2021-11-23 18:14:53.542',NULL,2,'2021-11-23 10:14:53','2021-11-23 10:14:53',0),(5,19,37,'27','******','2021-11-23 18:54:29.848','2021-11-23 18:54:34.864',3,'2021-11-23 10:54:29','2021-11-23 10:54:29',0),(6,19,37,'1','晴天','2021-11-21 18:55:12.082','2021-11-23 18:56:16.536',33,'2021-11-23 10:55:12','2021-11-25 02:02:25',0),(7,19,38,'1','晴天','2021-11-22 18:55:13.395','2021-11-23 18:56:45.709',706,'2021-11-23 10:55:13','2021-11-25 02:02:31',0),(8,19,37,'1','晴天','2021-11-23 18:56:13.368','2021-11-23 18:58:18.665',13,'2021-11-23 10:56:13','2021-11-23 10:56:13',0),(9,19,39,'1','晴天','2021-11-23 18:56:21.513','2021-11-23 18:56:43.032',313,'2021-11-23 10:56:21','2021-11-25 02:02:12',0),(10,19,40,'1','晴天','2021-11-21 18:56:32.061','2021-11-23 18:56:37.113',202,'2021-11-23 10:56:32','2021-11-25 02:02:55',0),(11,19,40,'1','晴天','2021-11-23 18:58:23.67','2021-11-23 19:38:19.261',114,'2021-11-23 10:58:23','2021-11-23 10:58:23',0),(12,19,40,'1','晴天','2021-11-24 10:11:44.531','2021-11-24 10:11:44.531',115,'2021-11-24 02:11:58','2021-11-25 02:03:06',0),(13,19,38,'1','晴天','2021-11-26 09:11:55.905','2021-11-26 21:05:35.152',943,'2021-11-26 01:12:12','2021-11-26 01:37:30',0),(14,4,15,'1','晴天','2021-11-26 17:07:25.349','2021-11-26 17:07:45.149',304,'2021-11-26 09:07:25','2021-11-26 09:07:25',0),(15,8,30,'1','晴天','2021-11-26 17:14:35.189',NULL,2,'2021-11-26 09:14:35','2021-11-26 09:14:35',0),(16,19,37,'29',NULL,'2021-11-26 18:38:39.719',NULL,3,'2021-11-26 10:38:39','2021-11-26 10:38:39',0),(17,19,38,'1','晴天','2021-11-27 08:02:41.382',NULL,944,'2021-11-27 00:02:41','2021-11-27 00:02:41',0),(18,18,33,'1','晴天','2021-12-01 13:49:37.599',NULL,11,'2021-12-01 05:49:36','2021-12-01 05:49:36',0),(19,18,33,'1','晴天','2021-12-01 13:49:32.6',NULL,6,'2021-12-01 05:49:36','2021-12-01 05:49:36',0),(20,18,33,'1','晴天','2021-12-01 13:49:27.665',NULL,1,'2021-12-01 05:49:37','2021-12-01 05:49:37',0),(21,18,34,'1','晴天','2021-12-01 13:52:02.601','2021-12-01 13:52:14.295',13,'2021-12-01 05:52:02','2021-12-01 05:52:02',0),(22,19,38,'1','晴天','2021-12-16 09:26:31.258',NULL,1,'2021-12-16 09:26:31','2021-12-16 09:26:31',0),(23,19,37,'27','我是','2021-12-28 11:42:31.06',NULL,95,'2021-12-28 11:42:31','2021-12-28 11:42:31',0); /*Table structure for table `video_visitor_max_view` */ DROP TABLE IF EXISTS `video_visitor_max_view`; /*!50001 DROP VIEW IF EXISTS `video_visitor_max_view` */; /*!50001 DROP TABLE IF EXISTS `video_visitor_max_view` */; /*!50001 CREATE TABLE `video_visitor_max_view`( `max_id` bigint(20) unsigned , `course_id` bigint(20) , `video_id` bigint(20) , `user_id` varchar(50) )*/; /*View structure for view video_visitor_max_view */ /*!50001 DROP TABLE IF EXISTS `video_visitor_max_view` */; /*!50001 DROP VIEW IF EXISTS `video_visitor_max_view` */; /*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`shangguigu`@`%` SQL SECURITY DEFINER VIEW `video_visitor_max_view` AS select max(`video_visitor`.`id`) AS `max_id`,`video_visitor`.`course_id` AS `course_id`,`video_visitor`.`video_id` AS `video_id`,`video_visitor`.`user_id` AS `user_id` from `video_visitor` group by `video_visitor`.`course_id`,`video_visitor`.`video_id`,`video_visitor`.`user_id` */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249

    1.3使用代码生成器生成对应表的代码

    package com.jq;
    
    
    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.generator.AutoGenerator;
    import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
    import com.baomidou.mybatisplus.generator.config.GlobalConfig;
    import com.baomidou.mybatisplus.generator.config.PackageConfig;
    import com.baomidou.mybatisplus.generator.config.StrategyConfig;
    import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    
    public class CodeGet {
    
        public static void main(String[] args) {
    
            // 1、创建代码生成器
            AutoGenerator mpg = new AutoGenerator();
    
            // 2、全局配置
            // 全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            //gc.setOutputDir(projectPath + "/src/main/java");
            gc.setOutputDir("F:\\JavaCode\\ggkt_parent\\service\\service_vod"+"/src/main/java");
    
            gc.setServiceName("%sService");	//去掉Service接口的首字母I
            gc.setAuthor("CJQ");
            gc.setOpen(false);
            mpg.setGlobalConfig(gc);
    
            // 3、数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/glkt_vod");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("123456");
            dsc.setDbType(DbType.MYSQL);
            mpg.setDataSource(dsc);
    
            // 4、包配置
            PackageConfig pc = new PackageConfig();
            pc.setModuleName("vod"); //模块名
            pc.setParent("com.jq");
    
            pc.setController("controller");
            pc.setEntity("entity");
            pc.setService("service");
            pc.setMapper("mapper");
            mpg.setPackageInfo(pc);
    
            // 5、策略配置
            StrategyConfig strategy = new StrategyConfig();
    
            strategy.setInclude("course","course_description","chapter","video");
    
            strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
    
            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();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    1.4课程列表接口

    在这里插入图片描述

    1.4.1点播课程列表controller

    package com.jq.vod.controller;
    
    
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.jq.model.vod.Course;
    import com.jq.result.Result;
    import com.jq.vo.vod.CourseQueryVo;
    import com.jq.vod.service.CourseService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.Map;
    
    /**
     * 

    * 课程 前端控制器 *

    * * @author CJQ * @since 2022-08-11 */
    @RestController @RequestMapping("/admin/vod/course") @CrossOrigin public class CourseController { @Autowired private CourseService courseService; /** * 点播课程列表 * 条件分页带查询 * @param page * @param limit * @param courseQueryVo * @return */ @ApiOperation("点播课程列表") @GetMapping("{page}/{limit}") public Result courseResult(@PathVariable Long page, @PathVariable Long limit, CourseQueryVo courseQueryVo){ Page<Course>pageParam =new Page<>(page,limit); Map<String,Object> map=courseService.findPageCourse(pageParam,courseQueryVo); return Result.ok(map); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    1.4.2点播课程列表Service

    package com.jq.vod.service;
    
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.jq.model.vod.Course;
    import com.jq.vo.vod.CourseQueryVo;
    
    import java.util.Map;
    
    /**
     * 

    * 课程 服务类 *

    * * @author CJQ * @since 2022-08-11 */
    public interface CourseService extends IService<Course> { Map<String, Object> findPageCourse(Page<Course> pageParam, CourseQueryVo courseQueryVo); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    1.4.3点播课程列表serviceImpl

    package com.jq.vod.service.impl;
    
    import com.alibaba.excel.util.StringUtils;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.jq.model.vod.Course;
    import com.jq.model.vod.Subject;
    import com.jq.model.vod.Teacher;
    import com.jq.vo.vod.CourseQueryVo;
    import com.jq.vod.mapper.CourseMapper;
    import com.jq.vod.service.CourseService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.jq.vod.service.SubjectService;
    import com.jq.vod.service.TeacherService;
    import org.apache.ibatis.logging.stdout.StdOutImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 

    * 课程 服务实现类 *

    * * @author CJQ * @since 2022-08-11 */
    @Service public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService { @Autowired private TeacherService teacherService; @Autowired private SubjectService subjectService; /** * 点播课程列表 * @param pageParam * @param courseQueryVo * @return */ @Override public Map<String, Object> findPageCourse(Page<Course> pageParam, CourseQueryVo courseQueryVo) { //获取条件值 String title = courseQueryVo.getTitle(); Long subjectId = courseQueryVo.getSubjectId(); //一层分类 Long subjectParentId = courseQueryVo.getSubjectParentId(); //二层分类 Long teacherId = courseQueryVo.getTeacherId(); //判断条件值是否为空,封装条件 QueryWrapper<Course>wrapper =new QueryWrapper<>(); if(!StringUtils.isEmpty(title)){ wrapper.like("title",title); } if(!StringUtils.isEmpty(subjectId)) { wrapper.eq("subject_id",subjectId); } if(!StringUtils.isEmpty(subjectParentId)) { wrapper.eq("subject_parent_id",subjectParentId); } if(!StringUtils.isEmpty(teacherId)) { wrapper.eq("teacher_id",teacherId); } //调用方法实现条件查询分页 Page<Course> pages = baseMapper.selectPage(pageParam, wrapper); long totalCount = pages.getTotal();//总记录数 long totalPage = pages.getPages();//总页数 List<Course> records = pages.getRecords();//每页数据集合 System.out.println(records); //查询数据里面有几个id //讲师id ,课程分类id (一层和二层) //获取这些id 对应的名称,进行封装,最终显示 records.stream().forEach(item->{ this.getNameByID(item); }); //封装数据 Map<String,Object> map=new HashMap<>(); map.put("totalCount",totalCount); map.put("totalPage",totalPage); map.put("records",records); return map; } //获取这些id 对应的名称,进行封装,最终显示 private Course getNameByID(Course course) { //根据讲师的id获取讲师的名称 Teacher teacher = teacherService.getById(course.getTeacherId()); if (teacher!=null){ String name = teacher.getName(); course.getParam().put("teacherName",name); } //根据课程分类的id获取课程分类的名称 Subject subjectOne = subjectService.getById(course.getSubjectParentId()); if (subjectOne!=null){ course.getParam().put("subjectParentTitle",subjectOne.getTitle()); } Subject subjectTwo = subjectService.getById(course.getSubjectId()); if(subjectTwo != null) { course.getParam().put("subjectTitle",subjectTwo.getTitle()); } return course; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    1.4.4 前端添加 路由

    // 课程管理
      {
        path: '/vod',
        component: Layout,
        redirect: '/vod/course/list',
        name: 'Vod',
        meta: {
          title: '点播管理',
          icon: 'el-icon-bank-card'
        },
        alwaysShow: true,
        children: [
          {
            path: 'course/list',
            name: 'CourseList',
            component: () => import('@/views/vod/course/list'),
            meta: { title: '课程列表' }
          },
          {
            path: 'course/info',
            name: 'CourseInfo',
            component: () => import('@/views/vod/course/form'),
            meta: { title: '发布课程' },
            hidden: true
          },
          {
            path: 'course/info/:id',
            name: 'CourseInfoEdit',
            component: () => import('@/views/vod/course/form'),
            meta: { title: '编辑课程' },
            hidden: true
          },
          {
            path: 'course/chapter/:id',
            name: 'CourseChapterEdit',
            component: () => import('@/views/vod/course/form'),
            meta: { title: '编辑大纲' },
            hidden: true
          },
          {
            path: 'course/chart/:id',
            name: 'CourseChart',
            component: () => import('@/views/vod/course/chart'),
            meta: { title: '课程统计' },
            hidden: true
          }
        ]
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    1.4.5创建前端页面

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

    list.vue

    <template>
      <div class="app-container">
        <!--查询表单-->
        <el-card class="operate-container" shadow="never">
        <el-form :inline="true" class="demo-form-inline">
    
          <!-- 所属分类:级联下拉列表 -->
          <!-- 一级分类 -->
          <el-form-item label="课程类别">
            <el-select
              v-model="searchObj.subjectParentId"
              placeholder="请选择"
              @change="subjectLevelOneChanged">
              <el-option
                v-for="subject in subjectList"
                :key="subject.id"
                :label="subject.title"
                :value="subject.id"/>
            </el-select>
    
            <!-- 二级分类 -->
            <el-select v-model="searchObj.subjectId" placeholder="请选择">
              <el-option
                v-for="subject in subjectLevelTwoList"
                :key="subject.id"
                :label="subject.title"
                :value="subject.id"/>
            </el-select>
          </el-form-item>
    
          <!-- 标题 -->
          <el-form-item label="标题">
            <el-input v-model="searchObj.title" placeholder="课程标题"/>
          </el-form-item>
          <!-- 讲师 -->
          <el-form-item label="讲师">
            <el-select
              v-model="searchObj.teacherId"
              placeholder="请选择讲师">
              <el-option
                v-for="teacher in teacherList"
                :key="teacher.id"
                :label="teacher.name"
                :value="teacher.id"/>
            </el-select>
          </el-form-item>
    
          <el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
          <el-button type="default" @click="resetData()">清空</el-button>
        </el-form>
        </el-card>
    
        <!-- 工具按钮 -->
        <el-card class="operate-container" shadow="never">
          <i class="el-icon-tickets" style="margin-top: 5px"></i>
          <span style="margin-top: 5px">数据列表</span>
          <el-button class="btn-add" @click="add()">添加</el-button>
        </el-card>
    
        <!-- 表格 -->
        <el-table :data="list" border stripe>
            <el-table-column label="#" width="50">
            <template slot-scope="scope">
              {{ (page - 1) * limit + scope.$index + 1 }}
            </template>
          </el-table-column>
    
          <el-table-column label="封面" width="200" align="center">
            <template slot-scope="scope">
              <img :src="scope.row.cover" alt="scope.row.title" width="100%">
            </template>
          </el-table-column>
          <el-table-column label="课程信息">
            <template slot-scope="scope">
              <a href="">{{ scope.row.title }}</a>
              <p>
                分类:{{ scope.row.param.subjectParentTitle }} > {{ scope.row.param.subjectTitle }}
              </p>
              <p>
                课时:{{ scope.row.lessonNum }} /
                浏览:{{ scope.row.viewCount }} /
                付费学员:{{ scope.row.buyCount }}
              </p>
            </template>
          </el-table-column>
          <el-table-column label="讲师" width="100" align="center">
            <template slot-scope="scope">
              {{ scope.row.param.teacherName }}
            </template>
          </el-table-column>
          <el-table-column label="价格(元)" width="100" align="center" >
            <template slot-scope="scope">
              <!-- {{ typeof '0' }}  {{ typeof 0 }} {{ '0' == 0 }} -->
              <!-- {{ typeof scope.row.price }}
              {{ typeof Number(scope.row.price) }}
              {{ typeof Number(scope.row.price).toFixed(2) }} -->
    
              <el-tag v-if="Number(scope.row.price) === 0" type="success">免费</el-tag>
    
              <!-- 前端解决保留两位小数的问题 -->
              <!-- <el-tag v-else>{{ Number(scope.row.price).toFixed(2) }}</el-tag> -->
    
              <!-- 后端解决保留两位小数的问题,前端不用处理 -->
              <el-tag v-else>{{ scope.row.price }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="status" label="课程状态" width="100" align="center" >
            <template slot-scope="scope">
              <el-tag :type="scope.row.status === 0 ? 'warning' : 'success'">{{ scope.row.status === 0 ? '未发布' : '已发布' }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="发布时间" width="140" align="center">
            <template slot-scope="scope">
              {{ scope.row.createTime ? scope.row.createTime.substr(0, 16) : '' }}
            </template>
          </el-table-column>
    
          <el-table-column label="操作" width="210" align="center">
            <template slot-scope="scope">
              <router-link :to="'/vodcourse/course/info/'+scope.row.id">
                <el-button type="text" icon="el-icon-edit" >修改</el-button>
              </router-link>
              <router-link :to="'/vodcourse/course/chapter/'+scope.row.id">
                <el-button type="text" icon="el-icon-edit" >编辑大纲</el-button>
              </router-link>
              <router-link :to="'/vodcourse/course/chart/'+scope.row.id">
                <el-button type="text" icon="el-icon-edit">课程统计</el-button>
              </router-link>
              <el-button type="text" icon="el-icon-delete" @click="removeById(scope.row.id)" >删除</el-button>
            </template>
          </el-table-column>
        </el-table>
    
        <!-- 分页组件 -->
        <el-pagination
          :current-page="page"
          :total="total"
          :page-size="limit"
          :page-sizes="[5, 10, 20, 30, 40, 50, 100]"
          style="padding: 30px 0; text-align: center;"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="changePageSize"
          @current-change="changeCurrentPage"
        />
      </div>
    </template>
    
    <script>
    import courseApi from '@/api/vod/course'
    import teacherApi from '@/api/vod/teacher'
    import subjectApi from '@/api/vod/subject'
    
    export default {
    
      data() {
        return {
          list: [], // 课程列表
          total: 0, // 总记录数
          page: 1, // 页码
          limit: 10, // 每页记录数
          searchObj: {
            subjectId: ''// 解决查询表单无法选中二级类别
          }, // 查询条件
          teacherList: [], // 讲师列表
          subjectList: [], // 一级分类列表
          subjectLevelTwoList: [] // 二级分类列表,
        }
      },
    
      created() {
        this.fetchData()
        // 初始化分类列表
        this.initSubjectList()
        // 获取讲师列表
        this.initTeacherList()
      },
    
      methods: {
        fetchData() {
          courseApi.getPageList(this.page, this.limit, this.searchObj).then(response => {
            this.list = response.data.records
            console.log(this.list)
            this.total = response.data.totalCount
          })
        },
    
        initTeacherList() {
          teacherApi.list().then(response => {
            this.teacherList = response.data
          })
        },
    
        initSubjectList() {
          subjectApi.getChildList(0).then(response => {
            this.subjectList = response.data
          })
        },
    
        subjectLevelOneChanged(value) {
          subjectApi.getChildList(value).then(response => {
            this.subjectLevelTwoList = response.data
            this.searchObj.subjectId = ''
          })
        },
    
        add() {
          this.$router.push({ path: '/vod/course/info' })
        },
    
        // 每页记录数改变,size:回调参数,表示当前选中的“每页条数”
        changePageSize(size) {
          this.limit = size
          this.fetchData()
        },
    
        // 改变页码,page:回调参数,表示当前选中的“页码”
        changeCurrentPage(page) {
          this.page = page
          this.fetchData()
        },
    
        // 重置表单
        resetData() {
          this.searchObj = {}
          this.subjectLevelTwoList = [] // 二级分类列表
          this.fetchData()
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230

    1.4.6 前端接口定义 js文件

    在这里插入图片描述

    import request from '@/utils/request'
    
    const api_name = '/admin/vod/course'
    
    export default {
      //课程列表
      getPageList(page, limit, searchObj) {
        return request({
          url: `${api_name}/${page}/${limit}`,
          method: 'get',
          params: searchObj
        })
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.填写基本信息

    2.1基本信息包括

    • 课程名称
    • 讲师
    • 描述等

    2.2添加课程基本信息controller

    2.2.1接收传递过来的数据封装类

    package com.jq.vo.vod;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import java.math.BigDecimal;
    
    /**
     * @author helen
     * @since 2020/6/6
     */
    @ApiModel("课程基本信息")
    @Data
    public class CourseFormVo {
    
        @ApiModelProperty(value = "课程ID")
        private Long id;
    
        @ApiModelProperty(value = "课程讲师ID")
        private Long teacherId;
    
        @ApiModelProperty(value = "课程专业ID")
        private Long subjectId;
    
        @ApiModelProperty(value = "课程专业父级ID")
        private Long subjectParentId;
    
        @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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    2.2.2controller实现

    /**
         * 添加课程基本信息
         * @param courseFormVo
         * @return
         */
        @ApiOperation("添加课程基本信息")
        @PostMapping("save")
        public Result save(@RequestBody CourseFormVo courseFormVo){
            Long courseID=courseService.saveCourseInfo(courseFormVo);
            return Result.ok(courseID);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.3添加课程基本信息serviceImpl层

    //添加课程基本信息
        @Override
        public Long saveCourseInfo(CourseFormVo courseFormVo) {
            //添加课程的基本信息,操作course表
            Course course =new Course();
            BeanUtils.copyProperties(courseFormVo,course);
            baseMapper.insert(course);
            
            //添加课程的描述信息,操作course_description
            CourseDescription courseDescription = new CourseDescription();
            courseDescription.setDescription(courseFormVo.getDescription());
            //设置课程id
            courseDescription.setId(course.getId());
            descriptionService.save(courseDescription);
            
            return course.getId();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.4前端

    在这里插入图片描述

    2.4.1前端按钮

        <!-- 工具按钮 -->
        <el-card class="operate-container" shadow="never">
          <i class="el-icon-tickets" style="margin-top: 5px"></i>
          <span style="margin-top: 5px">数据列表</span>
          <el-button class="btn-add" @click="add()">添加</el-button>
        </el-card>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对应 add方法

    
     add() {
       this.$router.push({ path: '/vodcourse/course/info' })
     },
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.4.1js接口方法

    //添加课程基本信息
    saveCourseInfo(courseInfo) {
      return request({
        url: `${api_name}/save`,
        method: 'post',
        data: courseInfo
      })
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.4.2创建课程基本信息添加页面

    form.vue

    <template>
      <div class="app-container">
        <h2 style="text-align: center;">发布新课程</h2>
        <el-steps :active="active" finish-status="success" simple style="margin-bottom: 40px">
          <el-step title="填写课程基本信息" />
          <el-step title="创建课程大纲" />
          <el-step title="发布课程" />
        </el-steps>
        <!-- 填写课程基本信息 -->
        <info v-if="active === 0" />
        <!-- 创建课程大纲 -->
        <chapter v-if="active === 1" />
        <!-- 发布课程 -->
        <Publish v-if="active === 2 || active === 3" />
      </div>
    </template>
    
    <script>
    // 引入子组件
    import Info from '@/views/vod/course/components/Info'
    import Chapter from '@/views/vod/course/components/Chapter'
    import Publish from '@/views/vod/course/components/Publish'
    
    export default {
      components: { Info, Chapter, Publish }, // 注册子组件
      data() {
        return {
          active: 0,
          courseId: null
        }
      },
      created() {
        // 获取路由id
        if (this.$route.params.id) {
          this.courseId = this.$route.params.id
        }
        if (this.$route.name === 'CourseInfoEdit') {
          this.active = 0
        }
        if (this.$route.name === 'CourseChapterEdit') {
          this.active = 1
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2.4.3创建以下目录结构

    在这里插入图片描述

    // 引入子组件
    import Info from '@/views/vod/course/components/Info'
    import Chapter from '@/views/vod/course/components/Chapter'
    import Publish from '@/views/vod/course/components/Publish'
    
    • 1
    • 2
    • 3
    • 4

    2.4.4 Info页面

    <template>
      <div class="app-container">
        <!-- 课程信息表单 -->
        <el-form label-width="120px">
          <el-form-item label="课程标题">
            <el-input v-model="courseInfo.title" placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/>
          </el-form-item>
          <!-- 课程讲师 -->
          <el-form-item label="课程讲师">
            <el-select
              v-model="courseInfo.teacherId"
              placeholder="请选择">
              <el-option
                v-for="teacher in teacherList"
                :key="teacher.id"
                :label="teacher.name"
                :value="teacher.id"/>
            </el-select>
          </el-form-item>
          <!-- 所属分类:级联下拉列表 -->
          <el-form-item label="课程类别">
            <!-- 一级分类 -->
            <el-select
              v-model="courseInfo.subjectParentId"
              placeholder="请选择"
              @change="subjectChanged">
              <el-option
                v-for="subject in subjectList"
                :key="subject.id"
                :label="subject.title"
                :value="subject.id"/>
            </el-select>
            <!-- 二级分类 -->
            <el-select v-model="courseInfo.subjectId" placeholder="请选择">
              <el-option
                v-for="subject in subjectLevelTwoList"
                :key="subject.id"
                :label="subject.title"
                :value="subject.id"/>
            </el-select>
          </el-form-item>
          <el-form-item label="总课时">
            <el-input-number :min="0" v-model="courseInfo.lessonNum" controls-position="right" placeholder="请填写课程的总课时数"/>
          </el-form-item>
          <!-- 课程简介-->
          <el-form-item label="课程简介">
            <el-input v-model="courseInfo.description" type="textarea" rows="5"/>
          </el-form-item>
          <!-- 课程封面 -->
          <el-form-item label="课程封面">
            <el-upload
              :show-file-list="false"
              :on-success="handleCoverSuccess"
              :before-upload="beforeCoverUpload"
              :on-error="handleCoverError"
              :action="BASE_API+'/admin/vod/file/upload?module=cover'"
              class="cover-uploader">
              <img v-if="courseInfo.cover" :src="courseInfo.cover">
              <i v-else class="el-icon-plus avatar-uploader-icon"/>
            </el-upload>
          </el-form-item>
          <el-form-item label="课程价格">
            <el-input-number :min="0" v-model="courseInfo.price" controls-position="right" placeholder="免费课程请设置为0元"/></el-form-item>
        </el-form>
    
        <div style="text-align:center">
          <el-button :disabled="saveBtnDisabled" type="primary" @click="saveAndNext()">保存并下一步</el-button>
        </div>
      </div>
    </template>
    <script>
    import courseApi from '@/api/vod/course'
    import teacherApi from '@/api/vod/teacher'
    import subjectApi from '@/api/vod/subject'
    
    export default {
      data() {
        return {
          BASE_API: 'http://localhost:8301',
          saveBtnDisabled: false, // 按钮是否禁用
          courseInfo: {// 表单数据
            price: 0,
            lessonNum: 0,
            // 以下解决表单数据不全时insert语句非空校验
            teacherId: '',
            subjectId: '',
            subjectParentId: '',
            cover: '',
            description: ''
          },
          teacherList: [], // 讲师列表
          subjectList: [], // 一级分类列表
          subjectLevelTwoList: []// 二级分类列表
        }
      },
      created() {
        // 初始化分类列表
        this.initSubjectList()
        // 获取讲师列表
        this.initTeacherList()
      },
      methods: {
        // 获取讲师列表
        initTeacherList() {
          teacherApi.list().then(response => {
            this.teacherList = response.data
          })
        },
    
        // 初始化分类列表
        initSubjectList() {
          subjectApi.getChildList(0).then(response => {
            this.subjectList = response.data
          })
        },
    
        // 选择一级分类,切换二级分类
        subjectChanged(value) {
          subjectApi.getChildList(value).then(response => {
            this.courseInfo.subjectId = ''
            this.subjectLevelTwoList = response.data
          })
        },
    
        // 上传成功回调
        handleCoverSuccess(res, file) {
          this.courseInfo.cover = res.data
        },
    
        // 上传校验
        beforeCoverUpload(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
        },
    
        // 错误处理
        handleCoverError() {
          console.log('error')
          this.$message.error('上传失败2')
        },
    
        // 保存并下一步
        saveAndNext() {
          this.saveBtnDisabled = true
          if (!this.$parent.courseId) {
            this.saveData()
          } else {
            //this.updateData()
          }
        },
    
        // 保存
        saveData() {
          courseApi.saveCourseInfo(this.courseInfo).then(response => {
            this.$message.success(response.message)
            this.$parent.courseId = response.data // 获取courseId
            this.$parent.active = 1 // 下一步
          })
        }
      }
    }
    </script>
    <style scoped>
    .tinymce-container {
      position: relative;
      line-height: normal;
    }
    .cover-uploader .avatar-uploader-icon {
      border: 1px dashed #d9d9d9;
      border-radius: 6px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
    
      font-size: 28px;
      color: #8c939d;
      width: 640px;
      height: 357px;
      line-height: 357px;
      text-align: center;
    }
    .cover-uploader .avatar-uploader-icon:hover {
      border-color: #409EFF;
    }
    .cover-uploader img {
      width: 640px;
      height: 357px;
      display: block;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199

    2.5页面效果

    点击添加按钮
    在这里插入图片描述跳转到填写基本信息页面 ,即info页面
    在这里插入图片描述填写基本信息并进行提交
    在这里插入图片描述提交对应数据库文件
    在这里插入图片描述对应数据在腾讯云中
    在这里插入图片描述

    3.修改课程基本信息

    3.1controller层

     /**
         * 根据id查询课程信息
         * @param id
         * @return
         */
        @GetMapping("get/{id}")
        public Result get(@PathVariable Long id){
          CourseFormVo courseFormVo= courseService.geCourseInfoById(id);
          return Result.ok(courseFormVo);
    
        }
    
        /**
         * 修改课程信息
         * @param courseFormVo
         * @return
         */
        @PostMapping("update")
        public Result update(@RequestBody CourseFormVo courseFormVo){
            courseService.updateCourseId(courseFormVo);
            return Result.ok(null);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.2serviceImpl层

        /**
         * 根据id查询课程信息
         * @param id
         * @return
         */
        @Override
        public CourseFormVo geCourseInfoById(Long id) {
            //课程的基本信息
            Course course = baseMapper.selectById(id);
            if (course==null){
                return null;
            }
            //课程描述信息
            CourseDescription courseDescription = descriptionService.getById(id);
            //数据封装
            CourseFormVo courseFormVo = new CourseFormVo();
            BeanUtils.copyProperties(course,courseFormVo);
            if(courseDescription!=null){
                courseFormVo.setDescription(courseDescription.getDescription());
            }
    
            return courseFormVo;
        }
    
        /**
         * 修改课程的基本信息
         * @param courseFormVo
         */
        @Override
        public void updateCourseId(CourseFormVo courseFormVo) {
            //修改课程基本信息
            Course course =new Course();
            BeanUtils.copyProperties(courseFormVo,course);
            baseMapper.updateById(course);
    
            //修改课程描述信息
            CourseDescription description = new CourseDescription();
            description.setDescription(courseFormVo.getDescription());
            descriptionService.updateById(description);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3.3前端-js文件中 接口定义

      //id获取课程信息
      getCourseInfoById(id) {
        return request({
          url: `${api_name}/get/${id}`,
          method: 'get'
        })
      },
      //修改课程信息
      updateCourseInfoById(courseInfo) {
        return request({
          url: `${api_name}/update`,
          method: 'put',
          data: courseInfo
        })
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.4前端-info页面中添加方法

    // 获取课程信息
        fetchCourseInfoById(id) {
          courseApi.getCourseInfoById(id).then(response => {
            this.courseInfo = response.data
            // 初始化分类列表
            subjectApi.getChildList(0).then(response => {
              this.subjectList = response.data
              // 填充二级菜单:遍历一级菜单列表,
              this.subjectList.forEach(subject => {
                // 找到和courseInfo.subjectParentId一致的父类别记录
                if (subject.id === this.courseInfo.subjectParentId) {
                  // 拿到当前类别下的子类别列表,将子类别列表填入二级下拉菜单列表
                  subjectApi.getChildList(subject.id).then(response => {
                    this.subjectLevelTwoList = response.data
                  })
                }
              })
            })
          })
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.5前端-页面代码

    在这里插入图片描述

    <template>
      <div class="app-container">
        <div style="text-align:center">
          <el-button type="primary" @click="prev()">上一步</el-button>
          <el-button type="primary" @click="next()">下一步</el-button>
        </div>
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
         
        }
      },
      created() {
        
      },
      methods: {
        // 上一步
        prev() {
          this.$parent.active = 0
        },
        // 下一步
        next() {
          this.$parent.active = 2
        }
      }
    }
    </script>
    <style scoped>
    .chapterList{
        position: relative;
        list-style: none;
        margin: 0;
        padding: 0;
    }
    .chapterList li{
      position: relative;
    }
    .chapterList p{
      float: left;
      font-size: 20px;
      margin: 10px 0;
      padding: 10px;
      height: 70px;
      line-height: 50px;
      width: 100%;
      border: 1px solid #DDD;
    }
    .chapterList .acts {
        float: right;
        font-size: 14px;
    }
    .videoList{
      padding-left: 50px;
    }
    .videoList p{
      float: left;
      font-size: 14px;
      margin: 10px 0;
      padding: 10px;
      height: 50px;
      line-height: 30px;
      width: 100%;
      border: 1px dashed #DDD;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    保存并下一步代码

        // 保存并下一步
        saveAndNext() {
          this.saveBtnDisabled = true
          if (!this.$parent.courseId) {
            this.saveData()
          } else {
            this.updateData()
          }
        },
        // 修改
        updateData() {
          courseApi.updateCourseInfoById(this.courseInfo).then(response => {
            this.$message.success(response.message)
            this.$parent.courseId = response.data // 获取courseId
            this.$parent.active = 1 // 下一步
          })
        },
        // 保存
        saveData() {
          courseApi.saveCourseInfo(this.courseInfo).then(response => {
            this.$message.success(response.message)
            this.$parent.courseId = response.data // 获取courseId
            this.$parent.active = 1 // 下一步
          })
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    4.创建课程大纲

    4.0课程大纲列表

    在这里插入图片描述在这里插入图片描述

    4.0.1实体类

    package com.jq.vo.vod;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author helen
     * @since 2020/6/6
     */
    @ApiModel("课程章节对象")
    @Data
    public class ChapterVo {
    
        @ApiModelProperty(value = "章节ID")
        private Long id;
        @ApiModelProperty(value = "章节标题")
        private String title;
        @ApiModelProperty(value = "排序")
        private Integer sort;
        @ApiModelProperty(value = "章节下的课时列表")
        private List<VideoVo> children = new ArrayList<>();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4.0.2大纲列表controller层

        /**
         * 大纲列表 章节和小节列表
         */
        @ApiOperation("大纲列表")
        @GetMapping("getNestedTreeList/{courseId}")
        public Result  getTreeList(@PathVariable Long courseId){
            List<ChapterVo> list=chapterService.getTreeList(courseId);
            return Result.ok(list);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.0.3serviceImpl层

    package com.jq.vod.service.impl;
    
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.jq.model.vod.Chapter;
    import com.jq.model.vod.Video;
    import com.jq.vo.vod.ChapterVo;
    import com.jq.vo.vod.VideoVo;
    import com.jq.vod.mapper.ChapterMapper;
    import com.jq.vod.service.ChapterService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.jq.vod.service.VideoService;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 

    * 课程 服务实现类 *

    * * @author CJQ * @since 2022-08-11 */
    @Service public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> implements ChapterService { @Autowired private VideoService videoService; /** * 大纲列表 章节和小节列表 * @param courseId * @return */ @Override public List<ChapterVo> getTreeList(Long courseId) { //定义最终数据list集合 List<ChapterVo> finalChapterList= new ArrayList<>(); //根据courseId 获取课程里面所有章节 QueryWrapper<Chapter> wrapperChapter=new QueryWrapper<>(); wrapperChapter.eq("course_id",courseId); List<Chapter> chapterList = baseMapper.selectList(wrapperChapter); //根据courseId 获取课程里面所有小节部分 LambdaQueryWrapper<Video>wrapperVideo =new LambdaQueryWrapper<>(); wrapperVideo.eq(Video::getCourseId,courseId); List<Video> videoList = videoService.list(wrapperVideo); //封装章节 //遍历所有章节 for (int i = 0; i < chapterList.size(); i++) { //得到课程里面的每个章节 Chapter chapter = chapterList.get(i); //chapter-->ChapterVo ChapterVo chapterVo = new ChapterVo(); BeanUtils.copyProperties(chapter,chapterVo); //得到的每个章节对象放到finalChapterList集合 finalChapterList.add(chapterVo); //封装章节里面小节 //创建list集合用户封装章节所有小节 List<VideoVo> videoVoList =new ArrayList<>(); //遍历小节 for (Video video: videoList) { //判断小节是哪个章节下面的小节 //章节的id和小节里面的chapter_id if(chapter.getId().equals(video.getChapterId())){ VideoVo videoVo = new VideoVo(); //放到videoVoList //video-->videoVo BeanUtils.copyProperties(video,videoVo); videoVoList.add(videoVo); } } //把章节里面的所有小节集合放到每个章节里面 chapterVo.setChildren(videoVoList); } return finalChapterList; } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    在这里插入图片描述

    4.1章节添加

    在这里插入图片描述在这里插入图片描述

    4.1.1controller层

        /**
         * 添加章节
         */
        @PostMapping("save")
        public Result save(@RequestBody Chapter chapter){
            chapterService.save(chapter);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2章节修改

    4.2.1controller层

     /**
         * 修改-根据id查询
         */
        @GetMapping ("get/{id}")
        public Result get(@PathVariable Long id){
            Chapter chapter = chapterService.getById(id);
            return Result.ok(chapter);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
        /**
         * 修改-最终实现
         */
        @PostMapping ("update")
        public Result update(@RequestBody Chapter chapter){
            chapterService.updateById(chapter);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.3章节删除

    4.3.1controller层

        /**
         * 删除章节
         */
        @DeleteMapping ("remove/{id}")
        public Result remove(@PathVariable Long id){
            chapterService.removeById(id);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.4小节添加

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    4.4.1controller层

       @ApiOperation(value = "新增")
        @PostMapping("save")
        public Result save(@RequestBody Video video) {
            videoService.save(video);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.5小节修改

    4.5.1controller层

        @ApiOperation(value = "获取")
        @GetMapping("get/{id}")
        public Result get(@PathVariable Long id) {
            Video video = videoService.getById(id);
            return Result.ok(video);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
        @ApiOperation(value = "修改")
        @PutMapping("update")
        public Result updateById(@RequestBody Video video) {
            videoService.updateById(video);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.6小节删除

    4.6.1controller层

        @ApiOperation(value = "删除")
        @DeleteMapping("remove/{id}")
        public Result remove(@PathVariable Long id) {
            videoService.removeById(id);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.7前端章节接口定义 chapter.js

    import request from '@/utils/request'
    
    const api_name = '/admin/vod/chapter'
    
    export default {
    
      getNestedTreeList(courseId) {
        return request({
          url: `${api_name}/getNestedTreeList/${courseId}`,
          method: 'get'
        })
      },
    
      removeById(id) {
        return request({
          url: `${api_name}/remove/${id}`,
          method: 'delete'
        })
      },
    
      save(chapter) {
        return request({
          url: `${api_name}/save`,
          method: 'post',
          data: chapter
        })
      },
    
      getById(id) {
        return request({
          url: `${api_name}/get/${id}`,
          method: 'get'
        })
      },
    
      updateById(chapter) {
        return request({
          url: `${api_name}/update`,
          method: 'post',
          data: chapter
        })
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    4.8前端小节接口定义 video.js

    import request from '@/utils/request'
    
    const api_name = '/admin/vod/video'
    
    export default {
    
      save(video) {
        return request({
          url: `${api_name}/save`,
          method: 'post',
          data: video
        })
      },
    
      getById(id) {
        return request({
          url: `${api_name}/get/${id}`,
          method: 'get'
        })
      },
    
      updateById(video) {
        return request({
          url: `${api_name}/update`,
          method: 'put',
          data: video
        })
      },
    
      removeById(id) {
        return request({
          url: `${api_name}/remove/${id}`,
          method: 'delete'
        })
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    4.9前端章节页面

    <template>
      <div class="app-container">
    
        <!-- 添加章节按钮 -->
        <div>
          <el-button type="primary" @click="addChapter()">添加章节</el-button>
        </div>
    
        <!-- 章节列表 -->
        <ul class="chapterList">
          <li
            v-for="chapter in chapterList"
            :key="chapter.id">
            <p>
              {{ chapter.title }}
              <span class="acts">
                <el-button type="text" @click="addVideo(chapter.id)">添加课时</el-button>
                <el-button type="text" @click="editChapter(chapter.id)">编辑</el-button>
                <el-button type="text" @click="removeChapterById(chapter.id)">删除</el-button>
              </span>
            </p>
            <!-- 视频 -->
            <ul class="chapterList videoList">
              <li
                v-for="video in chapter.children"
                :key="video.id">
                <p>
                  {{ video.title }}
                  <el-tag v-if="!video.videoSourceId" size="mini" type="danger">
                    {{ '尚未上传视频' }}
                  </el-tag>
                  <span class="acts">
                    <el-tag v-if="video.isFree" size="mini" type="success">{{ '免费观看' }}</el-tag>
                    <el-button type="text" @click="editVideo(chapter.id, video.id)">编辑</el-button>
                    <el-button type="text" @click="removeVideoById(video.id)">删除</el-button>
                  </span>
                </p>
              </li>
            </ul>
          </li>
        </ul>
        <!-- 章节表单对话框 -->
        <chapter-form ref="chapterForm" />
        <!-- 课时表单对话框 -->
        <video-form ref="videoForm" />
        <div style="text-align:center">
          <el-button type="primary" @click="prev()">上一步</el-button>
          <el-button type="primary" @click="next()">下一步</el-button>
        </div>
      </div>
    </template>
    <script>
    import chapterApi from '@/api/vod/chapter'
    import videoApi from '@/api/vod/video'
    
    // 引入组件
    import ChapterForm from '@/views/vod/course/components/Chapter/Form'
    import VideoForm from '@/views/vod/course/components/Video/Form'
    
    export default {
      // 注册组件
      components: { ChapterForm, VideoForm },
      data() {
        return {
          chapterList: [] // 章节嵌套列表
        }
      },
      created() {
        this.fetchNodeList()
      },
      methods: {
        // 获取章节小节数据
        fetchNodeList() {
          chapterApi.getNestedTreeList(this.$parent.courseId).then(response => {
            this.chapterList = response.data
          })
        },
        //删除章节
        removeChapterById(chapterId) {
          this.$confirm('此操作将永久删除该章节,是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            return chapterApi.removeById(chapterId)
          }).then(response => {
            this.fetchNodeList()
            this.$message.success(response.message)
          }).catch((response) => {
            if (response === 'cancel') {
              this.$message.info('取消删除')
            }
          })
        },
        // 添加章节
        addChapter() {
          this.$refs.chapterForm.open()
        },
        // 编辑章节
        editChapter(chapterId) {
          this.$refs.chapterForm.open(chapterId)
        },
        // 添加课时
        addVideo(chapterId) {
          this.$refs.videoForm.open(chapterId)
        },
        // 编辑课时
        editVideo(chapterId, videoId) {
          this.$refs.videoForm.open(chapterId, videoId)
        },
        // 删除课时
        removeVideoById(videoId) {
          this.$confirm('此操作将永久删除该课时, 是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            return videoApi.removeById(videoId)
          }).then(response => {
            this.fetchNodeList()
            this.$message.success(response.message)
          }).catch((response) => {
            if (response === 'cancel') {
              this.$message.info('取消删除')
            }
          })
        },
        // 上一步
        prev() {
          this.$parent.active = 0
        },
        // 下一步
        next() {
          this.$parent.active = 2
        }
      }
    }
    </script>
    <style scoped>
    .chapterList{
        position: relative;
        list-style: none;
        margin: 0;
        padding: 0;
    }
    .chapterList li{
      position: relative;
    }
    .chapterList p{
      float: left;
      font-size: 20px;
      margin: 10px 0;
      padding: 10px;
      height: 70px;
      line-height: 50px;
      width: 100%;
      border: 1px solid #DDD;
    }
    .chapterList .acts {
        float: right;
        font-size: 14px;
    }
    
    .videoList{
      padding-left: 50px;
    }
    .videoList p{
      float: left;
      font-size: 14px;
      margin: 10px 0;
      padding: 10px;
      height: 50px;
      line-height: 30px;
      width: 100%;
      border: 1px dashed #DDD;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177

    章节表单页面

    <template>
      <!-- 添加和修改章节表单 -->
      <el-dialog :visible="dialogVisible" title="添加章节" @close="close()">
        <el-form :model="chapter" label-width="120px">
          <el-form-item label="章节标题">
            <el-input v-model="chapter.title"/>
          </el-form-item>
          <el-form-item label="章节排序">
            <el-input-number v-model="chapter.sort" :min="0"/>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="close()">取 消</el-button>
          <el-button type="primary" @click="saveOrUpdate()">确 定</el-button>
        </div>
      </el-dialog>
    </template>
    
    <script>
    import chapterApi from '@/api/vod/chapter'
    export default {
    
      data() {
        return {
          dialogVisible: false,
          chapter: {
            sort: 0
          }
        }
      },
      methods: {
        open(chapterId) {
          this.dialogVisible = true
          if (chapterId) {
            chapterApi.getById(chapterId).then(response => {
              this.chapter = response.data.item
            })
          }
        },
    
        close() {
          this.dialogVisible = false
          // 重置表单
          this.resetForm()
        },
    
        resetForm() {
          this.chapter = {
            sort: 0
          }
        },
    
        saveOrUpdate() {
          if (!this.chapter.id) {
            this.save()
          } else {
            this.update()
          }
        },
    
        save() {
          this.chapter.courseId = this.$parent.$parent.courseId
          chapterApi.save(this.chapter).then(response => {
            this.$message.success(response.message)
            // 关闭组件
            this.close()
            // 刷新列表
            this.$parent.fetchNodeList()
          })
        },
    
        update() {
          chapterApi.updateById(this.chapter).then(response => {
            this.$message.success(response.message)
            // 关闭组件
            this.close()
            // 刷新列表
            this.$parent.fetchNodeList()
          })
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    4.10前端小节页面

    表单页面

    <template>
      <!-- 添加和修改课时表单 -->
      <el-dialog :visible="dialogVisible" title="添加课时" @close="close()">
        <el-form :model="video" label-width="120px">
          <el-form-item label="课时标题">
            <el-input v-model="video.title"/>
          </el-form-item>
          <el-form-item label="课时排序">
            <el-input-number v-model="video.sort" :min="0" />
          </el-form-item>
          <el-form-item label="是否免费">
            <el-radio-group v-model="video.isFree">
              <el-radio :label="0">免费</el-radio>
              <el-radio :label="1">默认</el-radio>
            </el-radio-group>
          </el-form-item>
    
          <!-- 上传视频 -->
          <el-form-item label="上传视频">
            <el-upload
              ref="upload"
              :auto-upload="false"
              :on-success="handleUploadSuccess"
              :on-error="handleUploadError"
              :on-exceed="handleUploadExceed"
              :file-list="fileList"
              :limit="1"
              :before-remove="handleBeforeRemove"
              :on-remove="handleOnRemove"
              :action="BASE_API+'/admin/vod/upload'">
              <el-button slot="trigger" size="small" type="primary">选择视频</el-button>
              <el-button
                :disabled="uploadBtnDisabled"
                style="margin-left: 10px;"
                size="small"
                type="success"
                @click="submitUpload()">上传</el-button>
            </el-upload>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="close()">取 消</el-button>
          <el-button type="primary" @click="saveOrUpdate()">确 定</el-button>
        </div>
      </el-dialog>
    </template>
    
    <script>
    import videoApi from '@/api/vod/video'
    //import vodApi from '@/api/vod/vod'
    export default {
    
      data() {
        return {
          BASE_API: 'http://localhost:8301',
          dialogVisible: false,
          video: {
            sort: 0,
            free: false
          },
          fileList: [], // 上传文件列表
          uploadBtnDisabled: false
        }
      },
    
      methods: {
        open(chapterId, videoId) {
          this.dialogVisible = true
          this.video.chapterId = chapterId
          if (videoId) {
            videoApi.getById(videoId).then(response => {
              this.video = response.data
              // 回显
              if (this.video.videoOriginalName) {
                this.fileList = [{ 'name': this.video.videoOriginalName }]
              }
            })
          }
        },
    
        close() {
          this.dialogVisible = false
          // 重置表单
          this.resetForm()
        },
    
        resetForm() {
          this.video = {
            sort: 0,
            free: false
          }
    
          this.fileList = [] // 重置视频上传列表
        },
    
        saveOrUpdate() {
          if (!this.video.id) {
            this.save()
          } else {
            this.update()
          }
        },
    
        save() {
          this.video.courseId = this.$parent.$parent.courseId
          videoApi.save(this.video).then(response => {
            this.$message.success(response.message)
            // 关闭组件
            this.close()
            // 刷新列表
            this.$parent.fetchNodeList()
          })
        },
    
        update() {
          videoApi.updateById(this.video).then(response => {
            this.$message.success(response.message)
            // 关闭组件
            this.close()
            // 刷新列表
            this.$parent.fetchNodeList()
          })
        },
    
        // 上传多于一个视频
        handleUploadExceed(files, fileList) {
          this.$message.warning('想要重新上传视频,请先删除已上传的视频')
        },
    
        // 上传
        submitUpload() {
          this.uploadBtnDisabled = true
          this.$refs.upload.submit() // 提交上传请求
        },
    
        // 视频上传成功的回调
        handleUploadSuccess(response, file, fileList) {
          this.uploadBtnDisabled = false
          this.video.videoSourceId = response.data
          this.video.videoOriginalName = file.name
        },
    
        // 失败回调
        handleUploadError() {
          this.uploadBtnDisabled = false
          this.$message.error('上传失败2')
        },
    
        // 删除视频文件确认
        handleBeforeRemove(file, fileList) {
          return this.$confirm(`确定移除 ${file.name}`)
        },
    
        // 执行视频文件的删除
        handleOnRemove(file, fileList) {
          if (!this.video.videoSourceId) {
            return
          }
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162

    5.课程发布

    在这里插入图片描述
    在这里插入图片描述

    5.1所用实体类

    package com.jq.vo.vod;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    
    /**
     * @author helen
     * @since 2020/6/6
     */
    @ApiModel("课程发布对象")
    @Data
    public class CoursePublishVo {
        @ApiModelProperty(value = "课程ID")
        private String id;
        @ApiModelProperty(value = "课程标题")
        private String title;
        @ApiModelProperty(value = "课程封面图片路径")
        private String cover;
        @ApiModelProperty(value = "总课时")
        private Integer lessonNum;
        @ApiModelProperty(value = "一级分类标题")
        private String subjectParentTitle;
        @ApiModelProperty(value = "二级分类标题")
        private String subjectTitle;
        @ApiModelProperty(value = "讲师姓名")
        private String teacherName;
        @ApiModelProperty(value = "课程销售价格")
        private String price;//只用于显示
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5.2根据课程id 查询发布的课程信息controller层

        //根据课程id 查询发布的课程信息
        @ApiOperation("id查询课程发布的信息")
        @GetMapping("getCoursePublishVo/{id}")
        public Result getCoursePublishVo(@PathVariable Long id){
            CoursePublishVo coursePublishVo=courseService.getCoursePublishVo(id);
            return Result.ok(coursePublishVo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.3根据课程id 查询发布的课程信息serviceImpl层

        /**
         * 根据课程id 查询发布的课程信息
         * @param id
         * @return
         */
        @Override
        public CoursePublishVo getCoursePublishVo(Long id) {
            return baseMapper.selectCoursePublishVoById(id);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.4根据课程id 查询发布的课程信息mapper层

    请添加图片描述

    5.4.1pom.xml

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.ymlinclude>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>falsefiltering>
            resource>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes> <include>**/*.ymlinclude>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>falsefiltering>
            resource>
        resources>
    build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    5.4.2application.properties

    mybatis-plus.mapper-locations=classpath:com/atguigu/ggkt/vod/mapper/xml/*.xml
    
    • 1
    package com.jq.vod.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jq.model.vod.Course;
    import com.jq.vo.vod.CoursePublishVo;
    
    /**
     * 

    * 课程 Mapper 接口 *

    * * @author CJQ * @since 2022-08-11 */
    public interface CourseMapper extends BaseMapper<Course> { //根据课程id 查询发布的课程信息 CoursePublishVo selectCoursePublishVoById(Long id); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    
    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.jq.vod.mapper.CourseMapper">
    
        <select id="selectCoursePublishVoById" resultType="com.jq.vo.vod.CoursePublishVo">
            SELECT
                c.id,
                c.title,
                c.cover,
                c.lesson_num AS lessonNum,
                c.price,
                t.name AS teacherName,
                s1.title AS subjectParentTitle,
                s2.title AS subjectTitle
            FROM course c
                     LEFT OUTER JOIN teacher t ON c.`teacher_id`=t.`id`
                     LEFT OUTER JOIN `subject` s1 ON c.`subject_parent_id`=s1.id
                     LEFT OUTER JOIN `subject` s2 ON c.`subject_id`=s2.id
            WHERE
                c.`id`=#{id}
        select>
    mapper>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    5.5最终发布controller层

        //课程最终发布
        @ApiOperation("课程最终发布")
        @PutMapping("publishCourse/{id}")
        public Result publishCourse(@PathVariable Long id){
            courseService.publishCourse(id);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.6最终发布serviceImpl层

        //最终发布
        @Override
        public void publishCourse(Long id) {
            Course course = baseMapper.selectById(id);
            course.setStatus(1);//已发布
            course.setPublishTime(new Date());
            baseMapper.updateById(course);
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.7前端接口定义

      //获取发布课程信息  
      getCoursePublishById(id) {
        return request({
          url: `${api_name}/getCoursePublishVo/${id}`,
          method: 'get'
        })
      },
      //发布课程  
      publishCourseById(id) {
        return request({
          url: `${api_name}/publishCourse/${id}`,
          method: 'put'
        })
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5.8前端页面Publish.vue

    <template>
      <div class="app-container">
        <!--课程预览-->
        <div class="ccInfo">
          <img :src="coursePublish.cover">
          <div class="main">
            <h2>{{ coursePublish.title }}</h2>
            <p class="gray"><span>{{ coursePublish.lessonNum }}课时</span></p>
            <p><span>所属分类:{{ coursePublish.subjectParentTitle }}{{ coursePublish.subjectTitle }}</span></p>
            <p>课程讲师:{{ coursePublish.teacherName }}</p>
            <h3 class="red">{{ coursePublish.price }}</h3>
          </div>
        </div>
        <div style="text-align:center">
          <el-button type="primary" @click="prev()">上一步</el-button>
          <el-button :disabled="publishBtnDisabled" type="primary" @click="publish()">发布课程</el-button>
        </div>
      </div>
    </template>
    
    <script>
    import courseApi from '@/api/vod/course'
    
    export default {
      data() {
        return {
          publishBtnDisabled: false, // 按钮是否禁用
          coursePublish: {}
        }
      },
      created() {
        if (this.$parent.courseId) {
          this.fetchCoursePublishById(this.$parent.courseId)
        }
      },
      methods: {
        // 获取课程发布信息
        fetchCoursePublishById(id) {
          courseApi.getCoursePublishById(id).then(response => {
            this.coursePublish = response.data
          })
        },
        // 上一步
        prev() {
          this.$parent.active = 1
        },
        // 下一步
        publish() {
          this.publishBtnDisabled = true
          courseApi.publishCourseById(this.$parent.courseId).then(response => {
            this.$parent.active = 3
            this.$message.success(response.message)
            this.$router.push({ path: '/vodcourse/course/list' })
          })
        }
      }
    }
    </script>
    <style scoped>
    .ccInfo {
        background: #f5f5f5;
        padding: 20px;
        overflow: hidden;
        border: 1px dashed #DDD;
        margin-bottom: 40px;
        position: relative;
    }
    .ccInfo img {
        background: #d6d6d6;
        width: 500px;
        height: 278px;
        display: block;
        float: left;
        border: none;
    }
    .ccInfo .main {
        margin-left: 520px;
    }
    .ccInfo .main h2 {
        font-size: 28px;
        margin-bottom: 30px;
        line-height: 1;
        font-weight: normal;
    }
    .ccInfo .main p {
        margin-bottom: 10px;
        word-wrap: break-word;
        line-height: 24px;
        max-height: 48px;
        overflow: hidden;
    }
    .ccInfo .main p {
        margin-bottom: 10px;
        word-wrap: break-word;
        line-height: 24px;
        max-height: 48px;
        overflow: hidden;
    }
    .ccInfo .main h3 {
        left: 540px;
        bottom: 20px;
        line-height: 1;
        font-size: 28px;
        color: #d32f24;
        font-weight: normal;
        position: absolute;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    6.点播课程的删除

    • 章节
    • 小节
    • 描述
    • 基本信息

    6.1点播课程删除controller层

        /**
         * 点播课程删除 根据id
         * @param id
         * @return
         */
        @DeleteMapping("remove/{id}")
        public  Result remove(@PathVariable Long id){
            courseService.removeCourseId(id);
            return Result.ok(null);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.2serviceImpl

        /**
         * 点播课程根据id删除课程
         * @param id
         */
        @Override
        public void removeCourseId(Long id) {
            //根据id删除小节
            videoService.removeVideoByCourseId(id);
            
            //根据课程id 删除章节
            chapterService.removeChapterByCourseId(id);
            
            //根据课程id 删除课程描述
            descriptionService.removeById(id);
            
            //根据课程id 删除课
            baseMapper.deleteById(id);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    6.3前端接口

      removeById(id) {
        return request({
          url: `${api_name}/remove/${id}`,
          method: 'delete'
        })
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6.4前端方法

    methods: {
    	......
    	// 根据id删除数据
        removeById(id) {
          this.$confirm('此操作将永久删除该课程,以及该课程下的章节和视频,是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            return courseApi.removeById(id)
          }).then(response => {
            this.fetchData()
            this.$message.success(response.message)
          }).catch((response) => { // 失败
            if (response === 'cancel') {
              this.$message.info('取消删除')
            }
          })
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    数据挖掘技术-转换字符串时间为标准时间
    物联网通信-如何基于TCP/IP简要设计业务应用协议(c++案例)
    java.sql.SQLExceptio
    Git:完美实现远端仓库迁移,包含提交历史
    系列一、堆里面的分区:Eden、From、To、老年代各自的特点
    【C++】匿名对象 ① ( 匿名对象引入 | 匿名对象简介 | 匿名对象概念 | 匿名对象作用域 - 对象创建与销毁 )
    人工智能核心基础 - 规划和概要
    Spring bean到底是如何创建的?(上)
    前端必看!css中常用单位及区别
    单链表的模拟实现
  • 原文地址:https://blog.csdn.net/qq_45498432/article/details/126281997