1.在线教育项目介绍
- 在线教育,是一个B2C模式的职业技能在线教育系统,分为前台用户系统和后台运营平台。
目录
1.1 功能简介
-
做的什么模块?
- 整个项目分为两大部分:前台部分、后台部分
- 前台部分:为用户使用部分,可以进行视频的购买与学习。
- 后台部分:为管理操作部分,进行视频上传与维护。
- 本课程主要完成的是
后台部分
。
-
用到什么技术?
- 后端:SpringCloud alibaba+SSM+mybatis-plus+swagger-ui+POI+Redis + JavaMail +…
- 前端:Vue全家桶:Vue+Vue-Router+Vuex+SPA + element ui admin
-
解决什么问题?
1.2 系统架构
-
前后端分离开发:
-
解耦
-
后端和前端完全分离,并且后台接口可以供给多端使用!(APP,微信,PC,WAP)(Restful风格的接口可以给任何应用去使用)
-
-
架构设计需要考虑的几个方面:
- 性能:主要考虑访问频率,每个用户每天的访问次数。项目初始阶段用户的访问量并不大,如果考虑做运营推广,可能会迎来服务器访问量骤增,因此要考虑分布式部署,引入缓存
- 可扩展性:系统功能会随着用户量的增加以及多变的互联网用户需求不断地扩展,因此考虑到系统的可扩展性的要求需要使用
微服务
架构,引入消息中间件 - 高可用:系统一旦宕机,将会带来不可挽回的损失,因此必须做负载均衡,甚至是异地多活这类复杂的方案。如果数据丢失,修复将会非常麻烦,只能靠人工逐条修复,这个很难接受,因此需要考虑存储高可靠。我们需要考虑多种异常情况:机器故障、机房故障,针对机器故障,我们需要设计 MySQL 同机房主备方案;针对机房故障,我们需要设计 MySQL 跨机房同步方案。
- 安全性:系统的信息有一定的隐私性,例如用户的个人身份信息,不包含强隐私(例如玉照、情感)的信息,因此使用账号密码管理、数据库访问权限控制即可。
- 成本:视频类网站的主要成本在于服务器成本、流量成本、存储成本、流媒体研发成本,中小型公司可以考虑使用云服务器和云服务。
2.数据库设计
2.1 数据库
数据库名称 | 描述 |
---|---|
zx_edu_teacher | 老师相关数据库 |
zx_edu_course | 课程相关数据库 |
zx_edu_user | 用户相关数据库 |
zx_edu_vod | 视频vod相关数据库 |
2.2 数据表
2.2.1 讲师表:zx_edu_teacher
CREATE DATABASE zx_edu_teacher;
USE zx_edu_teacher;
# 老师
CREATE TABLE `edu_teacher` (
`id` int(19) NOT NULL AUTO_INCREMENT COMMENT '讲师ID',
`name` varchar(20) COMMENT '讲师姓名',
`intro` varchar(255) COMMENT '讲师资历,一句话说明讲师',
`career` text COMMENT '讲师简介',
`level` int(10) COMMENT '头衔 1高级讲师 2首席讲师',
`avatar` varchar(255) COMMENT '讲师头像',
`sort` int(10) DEFAULT 0 COMMENT '排序',
`is_deleted` tinyint(10) DEFAULT 0 COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime COMMENT '创建时间',
`gmt_modified` datetime COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_name`(`name`) USING BTREE
) COMMENT = '讲师';
INSERT INTO `edu_teacher` VALUES (1, '谢霆锋', '毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余', '具备深厚的数学思维功底、丰富的小学教育经验,授课风格生动活泼,擅长用形象生动的比喻帮助理解、简单易懂的语言讲解难题,深受学生喜欢', 2, 'https://czxy-lt.oss-cn-shanghai.aliyuncs.com/avatar/449972ccd28a41d6a8317c97a9c2319e.png', 10, 0, '2020-03-30 17:15:57', '2020-07-10 10:13:59');
INSERT INTO `edu_teacher` VALUES (2, '周润发', '中国人民大学附属中学数学一级教师', '中国科学院数学与系统科学研究院应用数学专业博士,研究方向为数字图像处理,中国工业与应用数学学会会员。参与全国教育科学“十五”规划重点课题“信息化进程中的教育技术发展研究”的子课题“基与课程改革的资源开发与应用”,以及全国“十五”科研规划全国重点项目“掌上型信息技术产品在教学中的运用和开发研究”的子课题“用技术学数学”。', 2, '', 1, 0, '2020-03-30 18:28:26', '2020-02-22 02:01:26');
INSERT INTO `edu_teacher` VALUES (3, '周杰伦', '毕业于北京大学数学系', '中教一级职称。讲课极具亲和力。', 1, '', 1, 0, '2020-03-31 09:20:46', '2020-02-22 02:01:27');
INSERT INTO `edu_teacher` VALUES (4, '任贤齐', '长期从事考研政治课讲授和考研命题趋势与应试对策研究。考研辅导新锐派的代表。', '政治学博士、管理学博士后,北京师范大学马克思主义学院副教授。多年来总结出了一套行之有效的应试技巧与答题方法,针对性和实用性极强,能帮助考生在轻松中应考,在激励的竞争中取得高分,脱颖而出。', 1, '', 1, 0, '2020-04-03 14:13:51', '2020-02-22 02:01:28');
INSERT INTO `edu_teacher` VALUES (5, '陈伟霆', '人大附中2009届毕业生', '北京大学数学科学学院2008级本科生,2012年第八届学生五四奖章获得者,在数学领域取得多项国际国内奖项,学术研究成绩突出。曾被两次评为北京大学三好学生、一次评为北京大学三好标兵,获得过北京大学国家奖学金、北京大学廖凯原奖学金、北京大学星光国际一等奖学金、北京大学明德新生奖学金等。', 1, '', 1, 0, '2020-04-03 14:15:36', '2020-02-22 02:01:29');
INSERT INTO `edu_teacher` VALUES (6, '姚晨', '华东师范大学数学系硕士生导师,中国数学奥林匹克高级教练', '曾参与北京市及全国多项数学活动的命题和组织工作,多次带领北京队参加高中、初中、小学的各项数学竞赛,均取得优异成绩。教学活而新,能够调动学生的学习兴趣并擅长对学生进行思维点拨,对学生学习习惯的养成和非智力因素培养有独到之处,是一位深受学生喜爱的老师。', 1, '', 1, 0, '2020-04-01 14:19:28', '2020-02-22 02:01:29');
INSERT INTO `edu_teacher` VALUES (7, '胡歌', '考研政治辅导实战派专家,全国考研政治命题研究组核心成员。', '法学博士,北京师范大学马克思主义学院副教授,专攻毛泽东思想概论、邓小平理论,长期从事考研辅导。出版著作两部,发表学术论文30余篇,主持国家社会科学基金项目和教育部重大课题子课题各一项,参与中央实施马克思主义理论研究和建设工程项目。', 2, '', 8, 0, '2020-04-03 14:21:03', '2020-02-22 02:01:30');
INSERT INTO `edu_teacher` VALUES (8, '马云', '传智专修学院副教授', '传智专修学院软件工程系副教授、清华大学法学博士。自2004年至今已有9年的司法考试培训经验。长期从事司法考试辅导,深知命题规律,了解解题技巧。内容把握准确,授课重点明确,层次分明,调理清晰,将法条法理与案例有机融合,强调综合,深入浅出。', 1, '', 9, 0, '2020-04-03 14:23:06', '2020-02-22 02:01:31');
INSERT INTO `edu_teacher` VALUES (9, '谢娜', '资深课程设计专家,专注10年AACTP美国培训协会认证导师', '十年课程研发和培训咨询经验,曾任国企人力资源经理、大型外企培训经理,负责企业大学和培训体系搭建;曾任专业培训机构高级顾问、研发部总监,为包括广东移动、东莞移动、深圳移动、南方电网、工商银行、农业银行、民生银行、邮储银行、TCL集团、清华大学继续教育学院、中天路桥、广西扬翔股份等超过200家企业提供过培训与咨询服务,并担任近50个大型项目的总负责人。', 1, '', 10, 0, '2020-04-03 14:23:33', '2020-02-22 02:01:32');
INSERT INTO `edu_teacher` VALUES (10, 'string', 'string', 'string', 0, 'string', 0, 0, '2020-05-31 13:02:59', '2020-06-28 22:56:49');
2.2.2 用户表:zx_edu_user
CREATE DATABASE zx_edu_user;
USE zx_edu_user;
CREATE TABLE `edu_user` (
`id` INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) DEFAULT NULL COMMENT '用户名',
`password` VARCHAR(255) DEFAULT NULL COMMENT '用户密码',
`phone` CHAR(11) DEFAULT NULL COMMENT '电话',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`roles` VARCHAR(30) DEFAULT NULL COMMENT '角色,多个值使用逗号分隔,例如:admin,editor',
`created` DATE DEFAULT NULL,
`status` CHAR(2) COMMENT '状态:0 未激活、1已激活'
) ;
INSERT INTO `edu_user` VALUES (1, 'jack', '1234', '13699282444', 'itcast_lt@126.com', 'admin', '2021-10-20','1');
INSERT INTO `edu_user` VALUES (2, 'rose', '1234', '13377776666', 'itcast_lt@126.com', 'editor', NULL,'1');
INSERT INTO `edu_user` VALUES (3, 'tom', '1234', '15533336666', 'itcast_lt@126.com', 'admin,editor', '2020-02-14','0');
2.2.3 课程相关表:zx_edu_course
CREATE DATABASE zx_edu_course;
USE zx_edu_course;
# 课程章节表
CREATE TABLE `edu_chapter` (
`id` VARCHAR(32) PRIMARY KEY COMMENT '章节ID',
`course_id` VARCHAR(32) COMMENT '课程ID',
`title` VARCHAR(50) COMMENT '章节名称',
`sort` INT(10) DEFAULT 0 COMMENT '显示排序',
`gmt_create` DATETIME COMMENT '创建时间',
`gmt_modified` DATETIME COMMENT '更新时间'
)COMMENT = '课程章节';
INSERT INTO `edu_chapter` VALUES ('1', '14', '第一章:HTML', 1, '2020-01-01 12:27:40', '2020-01-01 12:55:30');
INSERT INTO `edu_chapter` VALUES ('15', '18', '第一章:Java入门', 1, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('3', '14', '第二章:CSS', 2, '2020-01-01 12:55:35', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('32', '18', '第二章:控制台输入和输出', 2, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('44', '18', '第三章:控制流', 3, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('48', '18', '第四章:类的定义', 4, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('63', '18', '第五章:数组', 5, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('64', '18', '第六章:继承', 6, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
INSERT INTO `edu_chapter` VALUES ('65', '18', '第七章:多态性和抽象类', 7, '2020-01-01 12:27:40', '2020-01-01 12:27:40');
#课程表
CREATE TABLE `edu_course` (
`id` VARCHAR(32) PRIMARY KEY COMMENT '课程ID',
`teacher_id` INT(19) COMMENT '课程讲师ID',
`subject_id` VARCHAR(32) COMMENT '课程专业ID二级分类ID',
`subject_parent_id` VARCHAR(32) COMMENT '一级分类ID',
`title` VARCHAR(50) COMMENT '课程标题',
`price` DECIMAL(10, 4) DEFAULT 0.0000 COMMENT '课程销售价格,设置为0则可免费观看',
`lesson_num` INT(10) DEFAULT 0 COMMENT '总课时',
`cover` VARCHAR(255) COMMENT '课程封面图片路径',
`buy_count` BIGINT(10) DEFAULT 0 COMMENT '销售数量',
`view_count` BIGINT(10) DEFAULT 0 COMMENT '浏览数量',
`version` BIGINT(20) DEFAULT 1 COMMENT '乐观锁',
`status` VARCHAR(10) DEFAULT 'Draft' COMMENT '视频状态 Draft未发布 Normal已发布',
`gmt_create` DATETIME COMMENT '创建时间',
`gmt_modified` DATETIME COMMENT '更新时间'
)COMMENT = '课程';
INSERT INTO `edu_course` VALUES ('10', 1, '221', NULL, '零基础入门学习Python课程学习', 1.0000, 10, '', 80, 165, 21, 'Draft', '2020-03-26 00:00:28', '2020-02-21 20:46:36');
INSERT INTO `edu_course` VALUES ('1282276374928773122', 1, '401', '4', '测试003', 10.0000, 100, '', 0, 0, 1, 'Draft', '2020-07-12 19:31:25', '2020-07-12 19:46:44');
INSERT INTO `edu_course` VALUES ('1282620880706351106', 1, '', '', '', 0.0000, 0, '', 0, 0, 1, 'Draft', '2020-07-13 18:20:22', '2020-07-13 18:20:22');
INSERT INTO `edu_course` VALUES ('14', 1, '221', NULL, 'XHTML CSS2 JS整站制作教程课程学习', 0.0000, 3, '', 3, 29, 15, 'Draft', '2020-04-02 18:33:34', '2020-02-21 20:46:36');
INSERT INTO `edu_course` VALUES ('15', 1, '251', NULL, 'HTML5入门课程学习', 0.0000, 23, '', 0, 39, 17, 'Draft', '2020-04-02 18:34:32', '2020-02-21 20:46:37');
INSERT INTO `edu_course` VALUES ('17', 2, '223', NULL, 'MySql从入门到精通', 0.0000, 100, '', 34, 130, 4, 'Draft', '2020-04-02 21:13:58', '2020-02-21 20:46:38');
INSERT INTO `edu_course` VALUES ('18', 2, '202', NULL, 'Java精品课程', 0.0000, 20, '', 150, 522, 6, 'Draft', '2020-04-02 21:28:46', '2020-02-21 20:46:39');
INSERT INTO `edu_course` VALUES ('21', 3, '221', NULL, '搜索引擎优化技术', 0.0000, 23, '', 23, 123, 1, 'Draft', '2020-09-15 11:38:57', '2020-02-21 20:46:40');
INSERT INTO `edu_course` VALUES ('22', 3, '223', NULL, '影响力摄影小课堂', 0.0000, 0, '', 0, 2, 3, 'Draft', '2020-11-02 10:49:41', '2020-02-21 20:46:40');
INSERT INTO `edu_course` VALUES ('24', 3, '223', NULL, '国家教师资格考试', 0.0000, 12, '', 324, 25, 3, 'Draft', '2020-11-04 09:48:44', '2020-02-21 20:46:41');
INSERT INTO `edu_course` VALUES ('25', 3, '223', NULL, '听力口语训练营', 0.0000, 0, '', 0, 13, 14, 'Draft', '2020-02-26 19:23:48', '2020-02-21 20:46:42');
INSERT INTO `edu_course` VALUES ('26', 4, '223', NULL, 'CAD4零基础教学', 0.0000, 0, '', 0, 34, 35, 'Draft', '2020-02-26 19:24:44', '2020-02-21 20:46:43');
#课程简介
CREATE TABLE `edu_course_description` (
`id` VARCHAR(32) PRIMARY KEY COMMENT '课程ID',
`description` MEDIUMTEXT COMMENT '课程简介',
`gmt_create` DATETIME COMMENT '创建时间',
`gmt_modified` DATETIME COMMENT '更新时间'
) COMMENT = '课程简介';
INSERT INTO `edu_course_description` VALUES ('1282276374928773122', '<p>好课程--传智造</p>', '2020-07-12 19:31:25', '2020-07-12 19:46:44');
INSERT INTO `edu_course_description` VALUES ('1282620880706351106', '', '2020-07-13 18:20:22', '2020-07-13 18:20:22');
#课程科目
CREATE TABLE `edu_subject` (
`id` VARCHAR(32) NOT NULL PRIMARY KEY COMMENT '课程科目ID',
`title` VARCHAR(10) NOT NULL COMMENT '科目名称',
`parent_id` VARCHAR(32) NOT NULL DEFAULT '0' COMMENT '父ID',
`sort` INT(10) NOT NULL DEFAULT 0 COMMENT '排序字段',
`gmt_create` DATETIME NOT NULL COMMENT '创建时间',
`gmt_modified` DATETIME NOT NULL COMMENT '更新时间'
) COMMENT = '课程科目';
INSERT INTO `edu_subject` VALUES ('1', '云计算', '0', 0, '2020-06-26 09:41:21', '2020-02-20 23:25:58');
INSERT INTO `edu_subject` VALUES ('2', '系统/运维', '0', 0, '2020-02-20 23:29:59', '2020-02-20 23:29:59');
INSERT INTO `edu_subject` VALUES ('3', '数据库', '0', 0, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
INSERT INTO `edu_subject` VALUES ('4', '服务器', '0', 0, '2020-02-20 23:30:19', '2020-02-20 23:30:19');
INSERT INTO `edu_subject` VALUES ('5', 'MySQL', '3', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
INSERT INTO `edu_subject` VALUES ('6', 'Oracle', '3', 2, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
INSERT INTO `edu_subject` VALUES ('7', 'Tomcat', '4', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
INSERT INTO `edu_subject` VALUES ('8', 'Nginx ', '4', 2, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
INSERT INTO `edu_subject` VALUES ('9', 'MySQL优化', '5', 1, '2020-02-20 23:30:13', '2020-02-20 23:30:13');
#课程视频
CREATE TABLE `edu_video` (
`id` VARCHAR(32) PRIMARY KEY COMMENT '视频ID',
`course_id` VARCHAR(32) COMMENT '课程ID',
`chapter_id` VARCHAR(32) COMMENT '章节ID',
`title` VARCHAR(50) COMMENT '节点名称',
`sort` INT(10) DEFAULT 0 COMMENT '排序字段',
`play_count` BIGINT(20) DEFAULT 0 COMMENT '播放次数',
`is_free` TINYINT(1) DEFAULT 0 COMMENT '是否可以试听:0免费 1收费',
`video_source_id` VARCHAR(100) COMMENT '视频资源',
`video_original_name` VARCHAR(50) COMMENT '视频原始文件名字',
`duration` FLOAT NOT NULL DEFAULT 0 COMMENT '视频时长(秒)',
`status` VARCHAR(20) DEFAULT '' COMMENT '视频状态:见阿里云文档',
`size` BIGINT(20) DEFAULT 0 COMMENT '视频源文件大小(字节)',
`version` BIGINT(20) NOT NULL DEFAULT 1 COMMENT '乐观锁',
`gmt_create` DATETIME NOT NULL COMMENT '创建时间',
`gmt_modified` DATETIME NOT NULL COMMENT '更新时间'
)COMMENT = '课程视频';
INSERT INTO `edu_video` VALUES ('17', '18', '15', '第一节:Java简介', 1, 1000, 1, '','', 100, 'Draft', 0, 1, '2020-01-01 13:08:57', '2020-02-21 20:46:08');
INSERT INTO `edu_video` VALUES ('18', '18', '15', '第二节:表达式和赋值语句', 2, 999, 1, '','', 100, 'Draft', 0, 1, '2020-01-01 13:09:02', '2020-02-21 20:46:09');
INSERT INTO `edu_video` VALUES ('19', '18', '15', '第三节:String类', 3, 888, 0, '','', 100, 'Draft', 0, 1, '2020-01-01 13:09:05', '2020-02-21 20:46:10');
INSERT INTO `edu_video` VALUES ('20', '18', '15', '第四节:程序风格', 4, 666, 0, '','', 100, 'Draft', 0, 1, '2020-01-01 13:09:05', '2020-02-21 20:46:10');
2.2.3 分类表:zx_edu_vod
CREATE DATABASE zx_edu_vod;
USE zx_edu_vod;
# 分类表
CREATE TABLE vod_category(
cate_id BIGINT PRIMARY KEY,
cate_name VARCHAR(64),
`level` BIGINT,
parent_id BIGINT,
`type` VARCHAR(10) COMMENT '取值:default、material'
);
#转码模板表
CREATE TABLE vod_template(
template_id VARCHAR(32) PRIMARY KEY,
`name` VARCHAR(128) COMMENT '',
is_default VARCHAR(20) COMMENT '取值:Default、NotDefault',
transcode_mode VARCHAR(20) COMMENT '取值:NoTranscode、FastTranscode'
);
本章使用到了老师表:edu_teacher
3.创建项目
3.1 项目架构
3.2 创建父工程zx-parent
-
第一步:创建 zx-parent31项目
-
第二步:配置 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.czxy.zx</groupId>
<artifactId>zx-parent31</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>zx-gateway31</module>
<module>zx-domain31</module>
<module>zx-common31</module>
<module>zx-service-teacher31</module>
</modules>
<!-- 1 确定spring boot的版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!--2 确定版本-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud-release.version>Hoxton.SR3</spring-cloud-release.version>
<nacos.version>1.1.0</nacos.version>
<alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version>
<mysql.version>5.1.32</mysql.version>
<mybatis.plus.version>3.4.0</mybatis.plus.version>
<druid.starter.version>1.1.9</druid.starter.version>
<jwt.jjwt.version>0.9.0</jwt.jjwt.version>
<jwt.joda.version>2.9.7</jwt.joda.version>
<swagger.version>2.7.0</swagger.version>
<swagger.anno.version>1.5.13</swagger.anno.version>
<beanutils.version>1.9.3</beanutils.version>
<aliyun.sdk.core.version>3.3.1</aliyun.sdk.core.version>
<aliyun.sdk.dysmsapi.version>1.0.0</aliyun.sdk.dysmsapi.version>
<fastjson.version>1.2.9</fastjson.version>
<zx.version>1.0-SNAPSHOT</zx.version>
</properties>
<!-- 3 锁定版本-->
<dependencyManagement>
<dependencies>
<!-- sprig cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-release.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--nacos -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!--nacos cloud 发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${alibaba.cloud.version}</version>
</dependency>
<!--nacos cloud 配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${alibaba.cloud.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${alibaba.cloud.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>${alibaba.cloud.version}</version>
</dependency>
<!-- mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- druid启动器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.starter.version}</version>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.anno.version}</version>
</dependency>
<!--jwt-->
<!--JavaBean工具类,用于JavaBean数据封装-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${beanutils.version}</version>
</dependency>
<!--jwt工具-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.jjwt.version}</version>
</dependency>
<!--joda 时间工具类 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jwt.joda.version}</version>
</dependency>
<!--短信-->
<dependency>
<groupId>com.aliyuncs</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>${aliyun.sdk.core.version}</version>
</dependency>
<dependency>
<groupId>com.aliyuncs.dysmsapi</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>${aliyun.sdk.dysmsapi.version}</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--自定义项目 zx.version-->
<dependency>
<groupId>com.czxy.zx</groupId>
<artifactId>zx-common31</artifactId>
<version>${zx.version}</version>
</dependency>
<dependency>
<groupId>com.czxy.zx</groupId>
<artifactId>zx-domain31</artifactId>
<version>${zx.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.3 创建zx-common
第一步:创建项目
第二步:配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>zx-parent31</artifactId>
<groupId>com.czxy.zx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zx-common31</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok , @Data 等-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!--jwt工具-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!--joda 时间工具类 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!--JavaBean工具类,用于JavaBean数据封装-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<!-- vod相关 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-vod</artifactId>
<version>2.15.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-sdk-vod-upload</artifactId>
<version>1.4.13</version>
</dependency>
</dependencies>
</project>
- 第三步:拷贝工具类
- 工具类:exception-EduException
package com.czxy.zx.exception;
import io.swagger.annotations.ApiModel;
@ApiModel(value = "自定义异常")
public class EduException extends RuntimeException {
public EduException(String message) {
super(message);
}
public EduException(String message, Throwable cause) {
super(message, cause);
}
public EduException(Throwable cause) {
super(cause);
}
protected EduException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
- 工具类:exception-ExceptionUtils
package com.czxy.zx.exception;
public class ExceptionUtils {
/**
* 抛出异常
* @param message
*/
public static void cast(String message) {
throw new EduException(message);
}
}
- 工具类:exception-GlobalExceptionHandler
package com.czxy.zx.exception;
import com.czxy.zx.vo.BaseResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)//拦截什么异常
@ResponseBody
public BaseResult error(Exception e){
e.printStackTrace();
return BaseResult.error("系统错误");
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public BaseResult error(ArithmeticException e){
e.printStackTrace();
return BaseResult.error("除数不能为0");
}
@ExceptionHandler(EduException.class)
@ResponseBody
public BaseResult error(EduException e){
e.printStackTrace();
if(e.getMessage() == null) {
return BaseResult.error("空指针异常");
}
return BaseResult.error(e.getMessage());
}
}
- 工具类:utils-JwtUtils
package com.czxy.zx.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.beanutils.BeanUtils;
import org.joda.time.DateTime;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.security.PrivateKey;
import java.security.PublicKey;
public class JwtUtils {
/**
* 私钥加密token
* @param data 需要加密的数据(载荷内容)
* @param expireMinutes 过期时间,单位:分钟
* @param privateKey 私钥
* @return
*/
public static String generateToken(Object data, int expireMinutes, PrivateKey privateKey) {
try {
//1 获得jwt构建对象
JwtBuilder jwtBuilder = Jwts.builder();
//2 设置数据
if( data == null ) {
throw new RuntimeException("数据不能为空");
}
BeanInfo beanInfo = Introspector.getBeanInfo(data.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 获得属性名
String name = propertyDescriptor.getName();
// 获得属性值
Object value = propertyDescriptor.getReadMethod().invoke(data);
if(value != null) {
jwtBuilder.claim(name,value);
}
}
//3 设置过期时间
jwtBuilder.setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate());
//4 设置加密
jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey);
//5 构建
return jwtBuilder.compact();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 通过公钥解析token
* @param token 需要解析的数据
* @param publicKey 公钥
* @param beanClass 封装的JavaBean
* @return
* @throws Exception
*/
public static <T> T getObjectFromToken(String token, PublicKey publicKey,Class<T> beanClass) throws Exception {
//1 获得解析后内容
Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
//2 将内容封装到对象JavaBean
T bean = beanClass.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
// 获得属性名
String name = propertyDescriptor.getName();
// 通过属性名,获得对应解析的数据
Object value = body.get(name);
if(value != null) {
// 将获得的数据封装到对应的JavaBean中
BeanUtils.setProperty(bean,name,value);
}
}
return bean;
}
}
- 工具类:utils-RsaUtils
package com.czxy.zx.utils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RsaUtils {
/**
* 从文件中读取公钥
*
* @param filename 公钥保存路径,相对于classpath
* @return 公钥对象
* @throws Exception
*/
public static PublicKey getPublicKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPublicKey(bytes);
}
/**
* 从文件中读取密钥
*
* @param filename 私钥保存路径,相对于classpath
* @return 私钥对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPrivateKey(bytes);
}
/**
* 获取公钥
*
* @param bytes 公钥的字节形式
* @return
* @throws Exception
*/
public static PublicKey getPublicKey(byte[] bytes) throws Exception {
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
/**
* 获取密钥
*
* @param bytes 私钥的字节形式
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
/**
* 根据密文,生存rsa公钥和私钥,并写入指定文件
*
* @param publicKeyFilename 公钥文件路径
* @param privateKeyFilename 私钥文件路径
* @param secret 生成密钥的密文
* @throws Exception
*/
public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 获取公钥并写出
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
writeFile(publicKeyFilename, publicKeyBytes);
// 获取私钥并写出
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
writeFile(privateKeyFilename, privateKeyBytes);
}
private static byte[] readFile(String fileName) throws Exception {
return Files.readAllBytes(new File(fileName).toPath());
}
private static void writeFile(String destPath, byte[] bytes) throws IOException {
File dest = new File(destPath);
//创建父文件夹
if(!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
//创建需要的文件
if (!dest.exists()) {
dest.createNewFile();
}
Files.write(dest.toPath(), bytes);
}
}
- 工具类:vo-BaseResult
package com.czxy.zx.vo;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class BaseResult<T> {
//成功状态码
public static final int OK = 20000;
//失败状态码
public static final int ERROR = 0;
//返回码
private Integer code;
//返回消息
private String message;
//存放数据
private T data;
//其他数据
private Map<String, Object> other = new HashMap<>();
public BaseResult() {
}
public BaseResult(Integer code, String message) {
this.code = code;
this.message = message;
}
public BaseResult(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
/**
* 快捷成功BaseResult对象
* @param message
* @return
*/
public static BaseResult ok(String message){
return new BaseResult(BaseResult.OK , message);
}
public static BaseResult ok(String message, Object data){
return new BaseResult(BaseResult.OK , message, data );
}
/**
* 快捷失败BaseResult对象
* @param message
* @return
*/
public static BaseResult error(String message){
return new BaseResult(BaseResult.ERROR , message);
}
/**
* 自定义数据区域
* @param key
* @param msg
* @return
*/
public BaseResult append(String key , Object msg){
other.put(key , msg);
return this;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
public Map<String, Object> getOther() {
return other;
}
}
- 工具类:vo-UserEmail
package com.czxy.zx.vo;
import lombok.Data;
@Data
public class UserEmail {
private String username;
private String email;
private String text;
}
- 工具类:vo-UserVo
package com.czxy.zx.vo;
import lombok.Data;
@Data
public class UserVo {
private String username;
private String password;
private String email;
private String verifycode;
}
- 工具类:vod-VideoUtils
package com.czxy.zx.utils;
import com.aliyun.vod.upload.impl.UploadVideoImpl;
import com.aliyun.vod.upload.req.UploadStreamRequest;
import com.aliyun.vod.upload.resp.UploadStreamResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.vod.model.v20170321.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@Component
public class VideoUtils {
@Resource
private VideoProperties videoProperties;
/**
* 初始化客户端
* @return
*/
public DefaultAcsClient initVodClient() {
try {
String regionId = videoProperties.getRegionId();
String accessKeyId = videoProperties.getKeyId();
String accessKeySecret = videoProperties.getKeySecret();
DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
return client;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获得所有转码模板
* @return
*/
public List<VodTemplate> getTranscodeList() {
try {
// 1 获得客户端
DefaultAcsClient client = initVodClient();
// 2 创建请求对象
ListTranscodeTemplateGroupRequest request = new ListTranscodeTemplateGroupRequest();
// 3 通过请求对象获得响应对象
ListTranscodeTemplateGroupResponse response = client.getAcsResponse(request);
// 4 获得所有数据
List<VodTemplate> templateList = new ArrayList<>();
response.getTranscodeTemplateGroupList().forEach(temp -> {
VodTemplate vodTemplate = new VodTemplate();
vodTemplate.setTemplateId(temp.getTranscodeTemplateGroupId());
vodTemplate.setName(temp.getName());
vodTemplate.setIsDefault(temp.getIsDefault());
vodTemplate.setTranscodeMode(temp.getTranscodeMode());
templateList.add(vodTemplate);
});
return templateList;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 查询分类
* @return
*/
public List<VodCategory> getCategoryList() {
// 1 获得客户端
DefaultAcsClient client = initVodClient();
// 2 数据
Long cateId = -1L;
return getChildrenList(client, cateId);
}
/**
* 查询所有分类
* @param client
* @param cateId
* @return
*/
private List<VodCategory> getChildrenList(DefaultAcsClient client, Long cateId) {
try {
//1 分页信息
Long pageNo = 1L;
Long pageSize = Long.parseLong(videoProperties.getCategoryPageSize());
//2 封装请求数据
GetCategoriesRequest request = new GetCategoriesRequest();
request.setCateId(cateId);
request.setPageNo(pageNo);
request.setPageSize(pageSize);
GetCategoriesResponse response = client.getAcsResponse(request);
//3 结果
List<VodCategory> resultList = new ArrayList<>();
//4 封装查询结果
for (GetCategoriesResponse.Category category : response.getSubCategories()) {
VodCategory vodCategory = new VodCategory();
vodCategory.setCateId(category.getCateId());
vodCategory.setCateName(category.getCateName());
vodCategory.setLevel(category.getLevel());
vodCategory.setParentId(category.getParentId());
vodCategory.setType(category.getType());
// 设置子分类
vodCategory.setChildren(getChildrenList(client, category.getCateId()));
resultList.add(vodCategory);
}
return resultList;
} catch (com.aliyuncs.exceptions.ClientException e) {
throw new RuntimeException(e);
}
}
/**
* 获得凭证
* @param videoId
* @return
*/
public String getVideoPlayAuth(String videoId) {
try {
// 1 获得客户端
DefaultAcsClient client = initVodClient();
// 2 设置视频id
GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
request.setVideoId(videoId);
GetVideoPlayAuthResponse response = client.getAcsResponse(request);
// 3 返回凭证
return response.getPlayAuth();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获得视频信息
* @param videoId
* @return
*/
public VodVideoInfo getPlayInfo(String videoId) {
try {
// 1 获得客户端
DefaultAcsClient client = initVodClient();
// 2 设置视频id
GetPlayInfoRequest request = new GetPlayInfoRequest();
request.setVideoId(videoId);
GetPlayInfoResponse response = client.getAcsResponse(request);
// 3 视频信息
VodVideoInfo vodVideoInfo = new VodVideoInfo();
// 3.1 封面
vodVideoInfo.setCoverURL(response.getVideoBase().getCoverURL());
// 3.2 视频名称
vodVideoInfo.setTitle(response.getVideoBase().getTitle());
// 3.3 视频地址
if(response.getPlayInfoList().size() > 0) {
vodVideoInfo.setPlayURL(response.getPlayInfoList().get(0).getPlayURL());
}
// 4 视频信息
return vodVideoInfo;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String uploadVideo(Long categoryId, String templateId, MultipartFile file) {
try {
//1.1 获得文件名
String fileName = file.getOriginalFilename();
String title = fileName.substring(0, fileName.lastIndexOf("."));
// 1.2 获得资源流
InputStream is = file.getInputStream();
//2 获得流请求对象
UploadStreamRequest request = new UploadStreamRequest(videoProperties.getKeyId(),videoProperties.getKeySecret(),title,fileName,is);
//3. 设置其他数据
if(categoryId != null) {
request.setCateId(categoryId);
}
if(StringUtils.isNotBlank(templateId)) {
request.setTemplateGroupId(templateId);
}
//4 上传
UploadVideoImpl uploadVideo = new UploadVideoImpl();
UploadStreamResponse response = uploadVideo.uploadStream(request);
if(response.isSuccess()) {
return response.getVideoId();
}
String errorMessage = "阿里云上传错误:" + "code:" + response.getCode() + ", message:" + response.getMessage();
throw new RuntimeException(errorMessage);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
- 工具类:vod-VodCategory
package com.czxy.zx.utils;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Data
@TableName("vod_category")
//@EqualsAndHashCode
public class VodCategory {
@TableId
private Long cateId;
private String cateName;
private Long level;
private Long parentId;
private String type;
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<VodCategory> children = new ArrayList<>();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VodCategory that = (VodCategory) o;
return Objects.equals(cateId, that.cateId) &&
Objects.equals(cateName, that.cateName) &&
Objects.equals(level, that.level) &&
Objects.equals(parentId, that.parentId) &&
Objects.equals(type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(cateId, cateName, level, parentId, type);
}
}
3.4 创建zx-domain
-
第一步:创建模块
-
第二步:配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>zx-parent31</artifactId>
<groupId>com.czxy.zx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zx-domain31</artifactId>
<dependencies>
<!--lombok , @Data 等-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--jackson , @JsonFormat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<!--mybatis-plus , @TableName @TableId 等 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
</dependency>
</dependencies>
</project>
- 步骤三:创建domain目录
- JavaBean:domain-EduChapter
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 课程
*
*/
@Data
@ApiModel(value="EduChapter对象", description="课程")
public class EduChapter {
@ApiModelProperty(value = "章节ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@ApiModelProperty(value = "课程ID")
private String courseId;
@ApiModelProperty(value = "章节名称")
private String title;
@ApiModelProperty(value = "显示排序")
private Integer sort;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT, value = "gmt_create")
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE, value = "gmt_modified")
private Date gmtModified;
@TableField(exist = false)
private List<EduVideo> videoList;
}
- JavaBean:domain-EduCourse
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 课程
*
*/
@Data
@ApiModel(value="EduCourse对象", description="课程")
public class EduCourse {
@ApiModelProperty(value = "课程ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@ApiModelProperty(value = "课程讲师ID")
private Integer teacherId;
@ApiModelProperty(value = "课程专业ID二级分类ID")
private String subjectId;
@ApiModelProperty(value = "一级分类ID")
private String subjectParentId;
@ApiModelProperty(value = "课程标题")
private String title;
@ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
private Double price;
@ApiModelProperty(value = "总课时")
private Integer lessonNum;
@ApiModelProperty(value = "课程封面图片路径")
private String cover;
@ApiModelProperty(value = "销售数量")
private Long buyCount;
@ApiModelProperty(value = "浏览数量")
private Long viewCount;
@ApiModelProperty(value = "乐观锁")
private Long version;
@ApiModelProperty(value = "视频状态 Draft未发布 Normal已发布")
private String status;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT, value = "gmt_create")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE, value = "gmt_modified")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date gmtModified;
}
- JavaBean:domain-EduCourseDescription
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 课程简介
*
*/
@Data
@ApiModel(value="EduCourseDescription对象", description="课程简介")
public class EduCourseDescription {
@ApiModelProperty(value = "课程ID")
//将CourseDescription和Course的ID保持一致
@TableId(value = "id", type = IdType.INPUT)
private String id;
@ApiModelProperty(value = "课程简介")
private String description;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT, value = "gmt_create")
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE, value = "gmt_modified")
private Date gmtModified;
}
- JavaBean:domain-EduSubject
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 课程科目(EduSubject)表实体类
*/
@Data
@TableName("edu_subject")
public class EduSubject{
@TableId(type = IdType.ASSIGN_UUID)
//课程科目ID
private String id;
//科目名称
private String title;
//父ID
private String parentId;
//排序字段
private Integer sort;
//创建时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
//更新时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT)
private Date gmtModified;
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY) //JavaBean转换成JSON数据时,忽略空数据
private List<EduSubject> children = new ArrayList<>();
}
- JavaBean:domain-EduTeacher
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
*
*/
@Data//lombok注解
@ApiModel(value = "EduTeacher对象",description = "讲师")//swagger注解
//@TableName("edu_teacher")
public class EduTeacher {
@TableId(value = "id",type = IdType.AUTO)//mybatis-plus的注解
@ApiModelProperty(value = "讲师ID")//swagger注解
private Integer id;
@ApiModelProperty(value = "讲师姓名")
private String name;
@ApiModelProperty(value = "讲师资历,一句话说明讲师")
private String intro;
@ApiModelProperty(value = "讲师简介")
private String career;
@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
private Integer level;
@ApiModelProperty(value = "讲师头像")
private String avatar;
@ApiModelProperty(value = "讲师排序")
private Integer sort;
@ApiModelProperty(value = "逻辑删除 1已删除, 0未删除")
@TableField(value = "is_deleted",fill = FieldFill.INSERT)
@TableLogic//逻辑删除
private Integer isDeleted;
@ApiModelProperty(value = "创建时间")
@TableField(value = "gmt_create",fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(value = "gmt_modified",fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date gmtModified;
}
- JavaBean:domain-EduUser
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
*
*/
@Data
//@TableName("edu_user")
@ApiModel(value = "EduUser对象",description = "用户")
public class EduUser {
@TableId(value="id" , type = IdType.AUTO)
private Integer id;
//用户名
@ApiModelProperty("用户名")
private String username;
//用户密码
@ApiModelProperty("用户密码")
private String password;
//电话
@ApiModelProperty("电话")
private String phone;
//邮箱
@ApiModelProperty("邮箱")
private String email;
//角色,多个值使用逗号分隔,例如:admin,editor
@ApiModelProperty("角色,多个值使用逗号分隔,例如:admin,editor")
private String roles;
//创建时间
@ApiModelProperty("创建时间")
private Date created;
//状态:0 未激活、1已激活
@ApiModelProperty("状态:0 未激活、1已激活")
private String status;
@TableField(exist = false)
@ApiModelProperty("验证码")
private String verifycode;
@TableField(exist = false)
@ApiModelProperty("重复密码")
private String repassword;
}
- JavaBean:domain-EduVideo
package com.czxy.zx.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
* 课程视频
*
*/
@Data
@ApiModel(value="EduVideo对象", description="课程视频")
public class EduVideo {
@ApiModelProperty(value = "视频ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@ApiModelProperty(value = "课程ID")
private String courseId;
@ApiModelProperty(value = "章节ID")
private String chapterId;
@ApiModelProperty(value = "节点名称")
private String title;
@ApiModelProperty(value = "排序字段")
private Integer sort;
@ApiModelProperty(value = "播放次数")
private Long playCount;
@ApiModelProperty(value = "是否可以试听:0免费 1收费")
private Integer isFree;
@ApiModelProperty(value = "视频资源")
private String videoSourceId;
@ApiModelProperty(value = "视频原始文件名字")
private String videoOriginalName;
@ApiModelProperty(value = "视频时长(秒)")
private Float duration;
@ApiModelProperty(value = "视频状态:见阿里云文档")
private String status;
@ApiModelProperty(value = "视频源文件大小(字节)")
private Long size;
@ApiModelProperty(value = "乐观锁")
private Long version;
@ApiModelProperty(value = "创建时间")
@TableField(value = "gmt_create",fill = FieldFill.INSERT)
private Date gmtCreate;
@ApiModelProperty(value = "更新时间")
@TableField(value = "gmt_modified",fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
}
3.5 创建zx-gateway
-
第一步:创建模块
-
第二步:配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>zx-parent31</artifactId>
<groupId>com.czxy.zx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zx-gateway31</artifactId>
<dependencies>
<!-- 网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>
- 第三步:创建 application.yml 核心配置文件
#端口号
server:
port: 10010
spring:
application:
name: zx-gateway
servlet:
multipart:
max-file-size: 2MB #上传文件的大小
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos服务地址
gateway:
discovery:
locator:
enabled: true #开启服务注册和发现的功能,自动创建router以服务名开头的请求路径转发到对应的服务
lowerCaseServiceId: true #将请求路径上的服务名配置为小写
sc:
jwt:
secret: sc@Login(Auth}*^31)&czxy% # 登录校验的密钥
pubKeyPath: D:/rsa/rsa.pub # 公钥地址
priKeyPath: D:/rsa/rsa.pri # 私钥地址
expire: 360 # 过期时间,单位分钟
filter:
allowPaths:
- swagger
- /api-docs
-
步骤四:拷贝跨域配置类
-
跨域配置类:config-GlobalCorsConfig
package com.czxy.zx.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* @author txt
* @email tantintong9968@163.com
*/
@Configuration
public class GlobalCorsConfig {
@Bean
public WebFilter corsFilter2() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
HttpHeaders requestHeaders = request.getHeaders();
ServerHttpResponse response = ctx.getResponse();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
-
步骤五:编写启动类
package com.czxy.zx; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @author txt * @email tantintong9968@163.com */ @SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
3.6 创建zx-service-teacher模块
第一步:创建模块
第二步:配置 pom.xml
注意:修改自定义项目的坐标(父项目坐标、teacher服务项目使用)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>zx-parent31</artifactId>
<groupId>com.czxy.zx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zx-service-teacher31</artifactId>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- feign 远程调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--自定义项目-->
<dependency>
<groupId>com.czxy.zx</groupId>
<artifactId>zx-common31</artifactId>
</dependency>
<dependency>
<groupId>com.czxy.zx</groupId>
<artifactId>zx-domain31</artifactId>
</dependency>
<!-- redis 启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- JavaMail 启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- MQ 启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!--开发者工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
第三步: 创建application.yml文件
# 服务端口号
server:
port: 9000
# 服务名
spring:
application:
name: teacher-service
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/zx_edu_teacher?useUnicode=true&characterEncoding=utf8
username: root
password: 1234
druid: #druid 连接池配置
initial-size: 1 #初始化连接池大小
min-idle: 1 #最小连接数
max-active: 20 #最大连接数
test-on-borrow: true #获取连接时候验证,会影响性能
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos服务地址
redis:
database: 0 #数据库索引,取值0-15,表示16个库可选择
host: 127.0.0.1 #服务器地址
port: 6379 #服务器连接端口号
mail:
host: smtp.126.com #发送邮件服务器
username: itcast_lt@126.com #账号
password: 1qaz2wsx #密码
default-encoding: UTF-8 #默认编码时
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
passowrd: guest
virtualHost: /
devtools:
restart:
enabled: true #设置开启热部署
additional-paths: src/main/java #重启目录
exclude: WEB-INF/**
freemarker:
cache: false #页面不加载缓存,修改即时生效
#开启log4j打印SQL语句
logging:
level:
com:
czxy:
zx:
teacher:
mapper: debug
# mp日志打印
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
第四步:启动类
package com.czxy.zx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author txt
* @email tantintong9968@163.com
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class TeacherServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TeacherServiceApplication.class,args);
}
}
-
第五步:配置类
-
配置类:config-MyBatisPlusConfig
package com.czxy.zx.teacher.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
- 配置类:config-Swagger2ConfigurationV3
package com.czxy.zx.teacher.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger2 配置类,
* 访问路径:swagger-ui.html
* 自动注册:
* 位置:resources/META-INF/spring.factories
* 内容:
* org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
* com.czxy.changgou4.config.Swagger2Configuration
*/
@Configuration
@EnableSwagger2
public class Swagger2ConfigurationV3 {
@Bean
public Docket createRestApi() {
// 1 确定文档Swagger版本
Docket docket = new Docket(DocumentationType.SWAGGER_2);
// 2 设置 api基本信息
docket.apiInfo(apiInfo());
// 3 设置自定义加载路径
docket = docket.select()
.apis(RequestHandlerSelectors.basePackage("com.czxy"))
.paths(PathSelectors.any())
.build();
//4 设置权限
docket.securitySchemes(securitySchemes());
docket.securityContexts(securityContexts());
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("基于swagger接口文档")
.contact(new Contact("梁桐","http://www.javaliang.com","liangtong@itcast.cn"))
.version("1.0")
.build();
}
private List<ApiKey> securitySchemes() {
List<ApiKey> list = new ArrayList<>();
// name 为参数名 keyname是页面传值显示的 keyname, name在swagger鉴权中使用
list.add(new ApiKey("Authorization", "Authorization", "header"));
return list;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> list = new ArrayList<>();
list.add(SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build());
return list;
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> list = new ArrayList();
list.add(new SecurityReference("Authorization", authorizationScopes));
return list;
}
}
end
后端环境搭建就到这里啦!
Blog的最后送所有正在努力的大家一句话:追风赶月莫停留,平芜尽处是春山。
好啦,我是话里人,我们下期见。