在线教育网站项目

在线教育网站项目

一、项目简介:

在线教育项目采用的是B2C的商业模块,主要分为前台网站系统和后台运营平台。
角色分为管理员和(普通会员)用户,其中系统后台由管理员进行使用,系统前台由用户进行使用。
系统后台包含的模块主要有:
1、讲师管理模块
2、课程分类管理功能
3、课程管理功能
(1)视频
4、统计分析模块
5、订单管理
6、banner管理、等等
系统前台包含的模块主要有:
1、首页数据的显示
2、讲师列表和详情
3、课程列表和课程详情
(1)视频在线播放
4、登录和注册功能、等等

二、开发环境

(一)、开发环境

	Windows+JDK1.8+Idea+vscode+linux+mysql+maven+spring boot

(二)、在线教育项目技术栈

	后端技术架构:SpringBoot + SpringCloud + MyBatis-Plus +  MySQL + Maven+EasyExcel+ nginx
	
	前端的架构是:Vue+element-ui+Node.js + ECharts

	其他涉及到的技术:包括Redis、阿里云OSS、阿里云视频点播
	业务中使用了ECharts做图表展示,使用EasyExcel完成分类批量添加、注册分布式单点登录使用了JWT

(三)、开发时间

		2020.6

三、项目模块实现

项目结构:
创建父工程 其类型为pom类型,用于管理依赖版本和放公共依赖
下面为子模块和子子模块,其中子子模块为功能实现模块
在这里插入图片描述
配置文件: application.properties

# 服务端口
server.port=8001
# 服务名
spring.application.name=service-edu

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456


#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

#注册中心nacos
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#开启熔断机制配置
feign.hystrix.enabled=true
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/gt/eduservice/mapper/xml/*.xml

springboot启动类

package com.gt.eduservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"com.gt"})
@EnableDiscoveryClient  //注册中心
@EnableFeignClients //调用服务
/*@MapperScan("com.gt.eduservice.mapper")*/
public class eduApplication {
    public static void main(String[] args) {
        SpringApplication.run(eduApplication.class,args);
    }
}

配置swagger2

	*前后端分离开发模式中,api文档是最好的沟通方式。
	Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。*

1、在父工程下创建子模块common,再commom的pom文件中引入,lombok,swagger,
mybatis-plus等依赖
具体以来如下:

<!--mybatis-plus-->

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--lombok用来简化实体类:需要安装lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--swagger-->

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <scope>provided </scope>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <scope>provided </scope>
        </dependency>

2、在子模块common下创建子子模块service_base,并在子子模块service_base中创建swagger的配置类。
在这里插入图片描述
代码如下:

package com.gt.servicebase;


import com.google.common.base.Predicates;
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.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@Configuration
public class SwaggerConfig {
    @Bean

    public Docket webApiConfig(){

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.not(PathSelectors.regex("/admin/.*")))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();

    }
    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                .title("网站-课程中心API文档")
                .description("本文档描述了课程中心微服务接口定义")
                .version("1.0")
                .contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com"))
                .build();

    }
}

3、在子模块service中引入service_base
在这里插入图片描述
定义统一返回数据格式

将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。

在子模块common下创建子子模块common-utils
1、创建接口定义返回码

package com.gt.commonutils;
public interface ResultCode {
    public  static  Integer SUCCESS=20000;
    public static  Integer ERROR = 20001;
}

2、创建结果类

package com.gt.commonutils;


import lombok.Data;

import java.util.HashMap;
import java.util.Map;

@Data
public class Msg {
    private  Boolean success;
    private  Integer code;
    private  String  message;
    private Map<String,Object> data = new HashMap<String,Object>();

    private  Msg(){}

    public static  Msg ok(){
        Msg msg = new Msg();
        msg.setSuccess(true);
        msg.setCode(ResultCode.SUCCESS);
        msg.setMessage("成功");
        return msg;
    }
    public static  Msg error(){
        Msg msg = new Msg();
        msg.setSuccess(false);
        msg.setCode(ResultCode.ERROR);
        msg.setMessage("失败");
        return msg;
    }

    public Msg  success(boolean success){
        this.setSuccess(success);
        return this;
    }
    public Msg message(String message){
        this.setMessage(message);
        return this;
    }
    public Msg code(Integer code){
        this.setCode(code);
        return this;
    }
    public Msg data(String key, Object value){
        this.data.put(key, value);
        return this;
    }
    public Msg data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}

3、在子模块service中引入子子模块common_utils,因为在子子模块service_base中已经引入了子子模块common_utils,所以直接在子模块service中引入子子模块service_base即可。
在这里插入图片描述
自动填充封装
在子子service-base模块中创建自动填充类MymetaobjectHandler

package com.gt.servicebase.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
//自动添加创建时间,更新时间
@Component
public class MymetaobjectHandler implements MetaObjectHandler{
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("gmtCreate",new Date(),metaObject);
        this.setFieldValByName("gmtModified",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified",new Date(),metaObject);
    }
}

安装vscode,
下载vue-element-admin,
vue-element-admin是基于element-ui 的一套后台管理系统集成方案。
下载vue.js,vue是一套用于构建用户界面的渐进式框架
下载node.js, Node.js 就是运行在服务端的 JavaScript。
Node.js是一个事件驱动I/O服务端JavaScript环境

===============以上为前期准备工作 ===============
(1)讲师管理模块:其中 课程分类管理功能、课程管理功能都在讲师管理模块中
讲师管理:
a、创建数据库,创建讲师数据库表
在这里插入图片描述
在这里插入图片描述
b、创建MP代码生成器:
生成comtroller 、service、mapper 和实体类等

讲师的条件查询带分页 以及 增加、修改、删除功能实现

  //条件查询带分页
@PostMapping("pagelistbycondition/{current}/{limit}")
    public  Msg pagelistbycondition(@PathVariable long current,
                                    @PathVariable long limit, 
                                    @RequestBody(required = false) TeacherQuery teacherQuery){
        //创建page对象
    Page<EduTeacher>pagelist = new  Page<>(current,limit);
    //创建条件对象
    QueryWrapper<EduTeacher>Wrapper=new QueryWrapper<>();
    String name = teacherQuery.getName();
    Integer level = teacherQuery.getLevel();
    String begin = teacherQuery.getBegin();
    String end = teacherQuery.getEnd();
    //判断条件是否为空,不为空就拼接条件
    if (!StringUtils.isEmpty(name)) {
        Wrapper.like("name",name);
    }
    if (!StringUtils.isEmpty(level)){
        Wrapper.eq("level",level);
    }
    if (!StringUtils.isEmpty(begin)) {
        Wrapper.ge("gmt_create",begin);
    }
    if (!StringUtils.isEmpty(end)) {
        Wrapper.le("gmt_create",end);
    }
    //排序
    Wrapper.orderByDesc("gmt_create");
    //底层封装,把分页数据封装到pagelist对象中
    eduTeacherService.page(pagelist, Wrapper);
    long total = pagelist.getTotal();//总记录数
    List<EduTeacher> records = pagelist.getRecords();//每页数据的list集合
    return Msg.ok().data("total",total).data("records",records);

    }

//添加讲师接口
    @PostMapping("postteacher")
   public  Msg postteacher(@RequestBody EduTeacher eduTeacher){
        boolean save = eduTeacherService.save(eduTeacher);
        if (save) {
            return Msg.ok();
        }else{
            return Msg.error();
        }
   }

 @PostMapping("teacher")
    public Msg  updateteacher(@RequestBody EduTeacher eduTeacher){
        boolean b = eduTeacherService.updateById(eduTeacher);
        if (b) {
            return Msg.ok();
        }else {
            return Msg.error();
        }
    }
    @DeleteMapping("{id}")
    public Msg removebyid(@PathVariable  String id){
        boolean b = eduTeacherService.removeById(id);
        return Msg.ok();

    }

前台调用:
在js文件中进行代码的编写:
在这里插入图片描述

vue界面进行调用:
这里只做一部分展示
在这里插入图片描述
特别注意的是,要使用前后端整合时可能会出现跨域问题
跨域问题:通过一个地址去访问另外一个地址,这个过程中有三个地方不一样都会出现跨域问题。
访问协议,IP地址,端口号
解决方案在controller层中加上@CrossOrigin解决

问题:修改讲师和添加讲师都在同一个页面中显示,当修改完成后,再次添加时,清空表单的代码没有执行,这是因为vue页面中多次跳转到同一个页面中时 created只会执行一次。解决方法,使用vue中的监听方法,当有路由发生变化时,就会执行清空表单的方法。

在这里插入图片描述

阿里云oss上传讲师头像
1创建子子模块service_oss,创建配置文件

到阿里云上,申请管理控制台得到 accessKeyId和accessKeySecret
创建子模块service_oss
创建配置文件:
#服务端口
server.port=8002
#服务名
spring.application.name=service-oss
#环境设置:dev、test、prod
spring.profiles.active=dev
#注册中心nacos
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-beijing.aliyuncs.com
aliyun.oss.file.keyid=LTAI4GFU1kvnA8ctTzaWpnka
aliyun.oss.file.keysecret=05Zj6xHrgH32hxNxxjEr9TlfzyQnM8
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=edu-guli1103

2创建启动类在这里插入图片描述
3创建常量类读取配置文件内容

package com.gt.vod.utils;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


//交给spring容器管理
@Component
//实现一个接口用来spring加载后实现其中的一个方法
public class constantPropertiesUtils implements InitializingBean {
    //读取配置文件
    @Value("${aliyun.oss.file.endpoint}")
    private  String endpoint;
    @Value("${aliyun.oss.file.keyid}")
    private  String keyid;
    @Value("${aliyun.oss.file.keysecret}")
    private  String keysecret;
    @Value("${aliyun.oss.file.bucketname}")
    private  String bucketname;
        //定义公开静态常量
    public static String END_POIND;
    public static String ACCESS_KEY_ID;
    public static String ACCESS_KEY_SECRET;
    public static String BUCKET_NAME;

    @Override
    public void afterPropertiesSet() throws Exception {
        END_POIND   = endpoint;
        ACCESS_KEY_ID= keyid;
        ACCESS_KEY_SECRET = keysecret;
        BUCKET_NAME = bucketname;
    }
}

4编写controller 实现上传文件的代码
在service实现上传文件到oss的过程
controller:
在这里插入图片描述
service:
在这里插入图片描述
前端进行调用:
在这里插入图片描述
在这里插入图片描述
新添加模块后,路径中有多个路由时,使用nginx进行请求转发操作
nginx:反向代理服务器。
主要有三个功能:1,请求转发 2,负载均衡 3,动静分离
客户端发起请求,nginx通过得到客户端的请求后会进行路径匹配,数据会到不同的服务器上。
(2)课程分类管理
创建数据库表edu_subject
在这里插入图片描述

表的存储关系:一级分类的id是二级分类的parentId
在添加课程分类时,我们通过EasyExcel来读取excel表格来添加课程分类到数据库中
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
实现过程:
第一步:引入依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>

第二步:
创建和Excel对应的实体类

@Data
public class excelData {
    @ExcelProperty(index = 0)
    private  String oneSubjectName;
    @ExcelProperty(index = 1)
    private  String twoSubjectName;
}

编写controller:

//获取上传过来得文件 把文件内容读取出来
@PostMapping(“addSubject”)
public Msg addSubject(MultipartFile file){
eduSubjectService.saveSubject(file,eduSubjectService);
return Msg.ok();
}
获取上传的excel文件 MultipartFile file
业务层在service中实现

@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {
        //添加课程分类
    @Override
    public void saveSubject(MultipartFile file,EduSubjectService eduSubjectService) {
       try {
           //文件输入流
           InputStream inputStream = file.getInputStream();

           EasyExcel.read(inputStream,excelData.class,new SubjectExcelListener(eduSubjectService)).sheet().doRead();
       } catch (IOException e) {
           e.printStackTrace();
       }
    }

创建读取Excel监听器:
在这里插入图片描述
前台是通过vue的表单提交到接口中实现,把课程分类到数据库中
在这里插入图片描述
在这里插入图片描述
课程列表显示:显示一二级分类
编写controller:
在这里插入图片描述
封装两个实体类
一级分类,二级分类,其中一级分类里面包含二级分类

@Data//一级分类
public class OneSubject {
    private  String id;
    private  String title;


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

service层中
先得到一级分类和二级分类
然后封装一级分类和二级分类到两个list集合中,最后整合到最终的list集合用于返回

在这里插入图片描述
前端js代码:
在这里插入图片描述

vue界面:vue界面进行调用js中的代码,然后进行遍历
在这里插入图片描述

(3)课程管理功能:
课程添加:课程添加的同时,向简介表中添加简介信息
controller层:
在这里插入图片描述
service层:
在这里插入图片描述
前端页面显示:
js代码
在这里插入图片描述
vue页面显示:
在这里插入图片描述
讲师下拉列表的显示就是查询出所有的讲师,然后传到前端进行遍历
在这里插入图片描述

课程查询:即点击一级分类时显示对应的二级分类
在这里插入图片描述
实现过程为:

显示一级分类:还是先调用EduSubjectController中的查询分类的方法
在这里插入图片描述
然后进行表单遍历
在这里插入图片描述

一二级联动效果 实在vue中的代码进行实现的,先得出所有的一级分类和二级分类的集合,再通过比较点击得一级分类id和遍历出来的一级分类id作比较,相吻合的情况下,就把这个一级分类得children给二级分类的集合,然后遍历出二级分类。
在这里插入图片描述
回显修改课程信息:根据课程id查询课程基本信息用于数据的回显。
在这里插入图片描述
修改课程信息:
在这里插入图片描述
需要注意:修改和添加课程在前端中是同一个页面,此时要进行辨别,如果页面中有课程id就是修改,没有课程id就是添加!
在这里插入图片描述

课程列表的显示:
对章节和小节进行查询,和一级分类二级分类一样,首先先封装两个实体类
其中章节里面有小节。
在这里插入图片描述
前端遍历之后得到的结果:
在这里插入图片描述
删除章节和小节:
先判断有没有小节,有小节 不能删除,没有小节才可以删除
在这里插入图片描述
在这里插入图片描述
最终发布课程:
根据id查询课程信息,mp不能满足我们的需求,需要使用多表查询
在这里插入图片描述
调用mapper在这里插入图片描述
在这里插入图片描述
前端页面与前面相似,不再赘述,最终得到结果为:
在这里插入图片描述
课程最终发布:
在这里插入图片描述
如何判断课程是否发布:根据数据库表中的状态
如果为normal就时发布,为D开头的就是没有发布
在这里插入图片描述
发布课程之后查询所有课程列表
在这里插入图片描述
删除课程:
这里考虑一般情况,删除课程时把里面的章节,小节,描述信息,课程信息,一起删掉
在这里插入图片描述
注意,删除小节时,顺便把小节视频也进行删除
在这里插入图片描述

小节上传视频:
上传到阿里云视频点播控制台:返回视频id
在这里插入图片描述
一、服务端渲染技术NUXT
1、什么是服务端渲染
服务端渲染又称SSR (Server Side Render)是在服务端完成页面的内容,而不是在客户端通过AJAX获取数据。

服务器端渲染(SSR)的优势主要在于:更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。

如果你的应用程序初始展示 loading 菊花图,然后通过 Ajax 获取内容,抓取工具并不会等待异步完成后再进行页面内容的抓取。也就是说,如果 SEO 对你的站点至关重要,而你的页面又是异步获取内容,则你可能需要服务器端渲染(SSR)解决此问题。

另外,使用服务器端渲染,我们可以获得更快的内容到达时间(time-to-content),无需等待所有的 JavaScript 都完成下载并执行,产生更好的用户体验,对于那些「内容到达时间(time-to-content)与转化率直接相关」的应用程序而言,服务器端渲染(SSR)至关重要。

2、什么是NUXT
Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性

banner管理:分为两部分
1、是对后端banner ,crud管理
2、另一部分是调用banner接口进行显示
1、这里只做一部分展示
在这里插入图片描述
2、另一部分是调用banner接口进行显示
在这里插入图片描述
降序排列只取前两条记录
在这里插入图片描述

发送短信验证码,使用阿里云的短信验证服务:其中短信验证码的时间实现用的是redis 设置的
在这里插入图片描述
需要网站签名名称 模板code 手机号
在这里插入图片描述
效果图:
在这里插入图片描述
用户登录与注册
在这里插入图片描述
登录通过手机号和密码与数据库中的信息作比较,登录功能返回的是token字符串
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

注册,带有发送验证码的,验证码已经在短信模块中被存储到redis中了,先判断redis中有没有验证码,没有就不能注册,然后有的话再把用户信息放入数据库表中
在这里插入图片描述
在这里插入图片描述

名师列表
后端接口
在这里插入图片描述
名师列表前端显示:
在api中创建js文件,定义接口地址,
vue页面中引入js文件,调用方法进行显示
在这里插入图片描述
在这里插入图片描述

名师详情
后端接口,根据讲师id查询讲师基本信息和所讲课程
在这里插入图片描述
在api中创建js文件,定义接口地址,
vue页面中引入js文件,调用方法进行显示
在这里插入图片描述

在这里插入图片描述

课程列表,条件查询带分页
在这里插入图片描述
前端实现,在api中创建js文件,定义接口地址,
vue页面中引入js文件,调用方法进行显示,显示所有的一级分类和二级分类,点击对应的一级分类,显示二级分类

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

课程详情:
后端接口,根据id进行课程信息查询时要进行联合查询。根据课程id获得章节要进行调用章节接口。
在这里插入图片描述
在这里插入图片描述

根据视频id进行视频播放。根据播放凭证
在这里插入图片描述
前端整合视频播放器进行整合:
在这里插入图片描述

视频播放:
在这里插入图片描述

===================================分割线=
项目已上传到码云:https://gitee.com/octandnov/onlinestudy.git

  • 8
    点赞
  • 65
    收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码ta

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值