当前位置: 首页 > news >正文

[学成在线]09-课程预览

模块需求分析

模块介绍

课程信息编辑完毕即可发布课程,发布课程相当于一个确认操作,课程发布后学习者在网站可以搜索到课程,然后查看课程的详细信息,进一步选课、支付、在线学习。

下边是课程编辑与发布的整体流程:

为了课程内容没有违规信息、课程内容安排合理,在课程发布之前运营方会进行课程审核,审核通过后课程方可发布。

作为课程制作方即教学机构,在课程发布前通过课程预览功能可以看到课程发布后的效果,哪里的课程信息存在问题方便查看,及时修改。

下图是课程预览的效果图,也是课程正式发布后的课程详情界面:

教学机构确认课程内容无误,提交审核,平台运营人员对课程内容审核,审核通过后教学机构人员发布课程成功。

课程发布模块共包括三块功能:

1、课程预览

2、课程审核

3、课程发布

业务流程

课程预览

1.教育机构用户在课程管理中可对该机构内所管理的课程进行检索。

2.点击某课程数据后的预览链接,即可对该课程进行预览,可以看到发布后的详情页面效果。

下图是课程详情首页,显示了课程的基本信息。

点击课程目录,显示课程计划,通过此界面去核实课程计划的信息是否存在问题。

点击课程目录中的具体章节,查看视频播放是否正常

课程审核

教学机构提交课程审核后,平台运营人员登录运营平台进行课程审核,课程审核包括程序自动审核和人工审核,程序会审核内容的完整性,人员通过课程预览进行审核。

流程如下:

1、首先查询待审核的记录。

2、课程审核

具体审核的过程与课程预览的过程类似,运营人员查看课程信息、课程视频等内容。

如果存在问题则审核不通过,并附上审核不通过的原因供教学机构人员查看。

如果课程内容没有违规信息且课程内容全面则审核通过。

课程审核通过后教学机构发布课程成功。

课程发布

1.教育机构用户在课程管理中可对机构内课程进行检索。

2.点击某课程数据后的发布链接(审核状态为通过),即可对该课程进行发布。

3、课程发布后可通过课程搜索查询到课程信息,并查看课程的详细信息。

4 点击课程搜索页中课程列表的某个课程,可进入课程详情页。

课程预览

需求分析

课程预览就是把课程的相关信息进行整合,在课程详情界面进行展示,通过课程预览页面查看信息是否存在问题。

下图是课程预览的数据来源:

在课程预览页面点击"视频播放图片"打开视频播放页面,通过视频播放页面查看课程计划对应的视频是否存在问题。

课程预览的效果与最终课程发布后查看到的效果是一致的,所以课程预览时会通过网站门户域名地址进行预览,下图显示了整个课程预览的流程图:

说明如下:

1、点击课程预览,通过Nginx、后台服务网关请求内容管理服务进行课程预览。

2、内容管理服务查询课程相关信息进行整合,并通过模板引擎技术在服务端渲染生成页面,返回给浏览器。

3、通过课程预览页面点击”马上学习“打开视频播放页面。

4、视频播放页面通过Nginx请求后台服务网关,查询课程信息展示课程计划目录,请求媒资服务查询课程计划绑定的视频文件地址,在线浏览播放视频。

模板引擎

什么是模板引擎

根据前边的数据模型分析,课程预览就是把课程的相关信息进行整合,在课程预览界面进行展示,课程预览界面与课程发布的课程详情界面一致。

项目采用模板引擎技术实现课程预览界面。什么是模板引擎?

早期我们采用的jsp技术就是一种模板引擎技术,如下图:

1、浏览器请求web服务器

2、服务器渲染页面,渲染的过程就是向jsp页面(模板)内填充数据(模型)。

3、服务器将渲染生成的页面返回给浏览器。

  1. 所以模板引擎就是:模板+数据=输出,Jsp页面就是模板,页面中嵌入的jsp标签就是数据,两者相结合输出html网页。

常用的java模板引擎还有哪些? Jsp、Freemarker、Thymeleaf 、Velocity 等。

本项目采用Freemarker作为模板引擎技术。

Freemarker官方地址:http://freemarker.foofun.cn/

FreeMarker 是一款模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。FreeMarker 是免费的,基于Apache许可证2.0版本发布。

Freemarker快速入门

下边在内容管理接口层搭建Freemarker的运行环境并进行测试。

  1. 在内容管理接口工层添加Freemarker与SpringBoot的整合包
<!-- Spring Boot 对结果视图 Freemarker 集成 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
  1. 在nacos为内容管理接口层配置freemarker,公用配置组新加一个freemarker-config-dev.yaml

  1. 在内容管理接口工程添加freemarker-config-dev.yaml

  1. 添加模板,在resources下创建templates目录,添加test.ftl模板文件

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>
  1. 编写controller方法,准备模型数据

package com.xuecheng.content.api;

/**
 * @author Mr.M
 * @version 1.0
 * @description freemarker测试
 * @date 2022/9/15 19:20
 */
@Controller
public class FreemarkerController {
    @GetMapping("/testfreemarker")
    public ModelAndView test() {
        // 创建数据模型
        ModelAndView modelAndView = new ModelAndView();
        //设置模型数据
        modelAndView.addObject("name","小明");
        //设置模板名称
        modelAndView.setViewName("test");
        return modelAndView;
    }

}
  1. 启动内容管理接口工程,访问http://localhost:63040/content/testfreemarker

  1. freemarker提供很多指令用于解析各种类型的数据模型,
  2. 参考地址:http://freemarker.foofun.cn/ref_directives.html
部署网站门户

在课程预览界面上要加载css、js、图片等内容,这里部署nginx来访问这些静态资源,对于SpringBoot服务的动态资源由Nginx去代理请求,如下图:

安装 Nginx

  1. 在本机安装 Nginx ,从课程资料目录获取nginx-1.23.1.zip并解压。
  2. 运行nginx-1.23.1目录下的nginx.exe。
  • 默认端口为80,如果本机80端口被占用,则需要杀掉占用进程后再启动nginx。
  • 如果无法杀掉80端口占用进程则需要修改nginx-1.23.1目录下conf/nginx.conf配置文件, 将80端口修改为空闲端口。

  1. 启动nginx,访问http://localhost 出现下边的网页表示启动成功

下边开始部署前端工程:

  1. 从课程资料目录获取xc-ui-pc-static-portal.zip 并解压。
  2. 修改本机hosts文件,加入127.0.0.1 www.51xuecheng.cn 51xuecheng.cn ucenter.51xuecheng.cn teacher.51xuecheng.cn file.51xuecheng.cn。

  • window10操作系统hosts文件在C:\Windows\System32\drivers\etc下
  • Centos7操作系统的hosts文件在/etc目录下。
  • 在hosts文件加入如下配置
127.0.0.1 www.51xuecheng.cn 51xuecheng.cn ucenter.51xuecheng.cn teacher.51xuecheng.cn file.51xuecheng.cn
  1. 在nginx-1.23.1目录中找到conf目录,配置目录下的nginx.conf文件。

配置内容如下,注意更改xc-ui-pc-static-portal目录的路径:

server {
        listen       80;
        server_name  www.51xuecheng.cn localhost;
        #rewrite ^(.*) https://$server_name$1 permanent;
        #charset koi8-r;
        ssi on;
        ssi_silent_errors on;
        #access_log  logs/host.access.log  main;

        location / {
            alias   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/;
            index  index.html index.htm;
        }
        #静态资源
        location /static/img/ {  
                alias  D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/img/;
        } 
        location /static/css/ {  
                alias   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/css/;
        } 
        location /static/js/ {  
                alias   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/js/;
        } 
        location /static/plugins/ {  
                alias   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/plugins/;
                add_header Access-Control-Allow-Origin http://ucenter.51xuecheng.cn;  
                add_header Access-Control-Allow-Credentials true;  
                add_header Access-Control-Allow-Methods GET;
        } 
        location /plugins/ {  
                alias   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/plugins/;
        } 



        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
  1. 启动nginx:
  • 进入任务管理器,杀死nginx的两个进程

  • 杀死后再次双击nginx.exe。
  • 启动成功在任务管理器会出现nginx的进程。
  • 日志文件在nginx安装目录下的logs目录:

  1. 启动成功访问http://www.51xuecheng.cn

课程详情页面

course_template.html是一个静态html页面,里边还没有添加freemarker标签,如果要预览该页面需要借助Nginx进行预览,因为页面需要加载一些css样式表、图片等内容。

  1. course_template.html文件在xc-ui-pc-static-portal\course目录下

  1. 通过浏览器访问:http://www.51xuecheng.cn/course/course_template.html

  1. 出现这个画面说明模板文件正常浏览是没有问题的。
文件服务器

在进行课程预览时需要展示课程的图片,在线插放课程视频,课程图片、视频这些都在MinIO文件系统存储,下边统一由Nginx代理,通过文件服务域名统一访问。如下图:

  1. 在hosts文件配置如下内容,如果已存在不要重复配置。
127.0.0.1 www.51xuecheng.cn file.51xuecheng.cn
  1. 在nginx.conf中配置文件服务器的代理地址
 #文件服务
  upstream fileserver{
    server 192.168.101.65:9000 weight=10;
  } 
   server {
        listen       80;
        server_name  file.51xuecheng.cn;
        #charset koi8-r;
        ssi on;
        ssi_silent_errors on;
        #access_log  logs/host.access.log  main;
        location /video {
            proxy_pass   http://fileserver;
        }

        location /mediafiles {
            proxy_pass   http://fileserver;
        }
   }
  1. 配置完毕,重新加载nginx配置文件。

通过cmd进入nginx.exe所在目录,运行如下命令

nginx.exe -s reload
  1. 通过http://file.51xuecheng.cn/mediafiles/图片文件地址 访问图片
  • 在媒资数据库的文件表中找一个图片的地址进行测试。
  • http://file.51xuecheng.cn/mediafiles/2025/02/20/775a578fbfb0aa97ed8eeef80c62a76e.png
视频播放页面

进入课程详情页面,点击马上学习或课程目录下的小节的名称将打开视频播放页面。

首先在nginx.conf中配置视频播放页面的地址, 然后加载nginx配置文件

     location /course/preview/learning.html {
                alias D:\UserDatas\Note\16Project\xue-cheng-zai-xian/xc-ui-pc-static-portal/course/learning.html;
        } 
        location /course/search.html {  
                root   D:\UserDatas\Note\16Project\xue-cheng-zai-xian/xc-ui-pc-static-portal;
        } 
        location /course/learning.html {  
                root   D:\UserDatas\Note\16Project\xue-cheng-zai-xian/xc-ui-pc-static-portal;
        }

下边需要配置learning.html页面的视频播放路径来测试视频播放页面,找到learning.html页面中videoObject对象的定义处,配置视频的播放地址。

点击课程详情页面上的视频播放链接,打开视频播放页面,如下图:

配置完成,刷新页面,观察视频是否可以正常播放。
注意:此页面会去请求后台接口获取课程计划,这里暂时不处理,稍后在接口开发处进行处理。只要页面可以正常打开,可以播放视频就测试通过了。

接口定义

课程预览接口要将课程信息进行整合,在服务端渲染页面后返回浏览器。

下边对课程预览接口进行分析:

1、请求参数

传入课程id,表示要预览哪一门课程。

2、响应结果

输出课程详情页面到浏览器。

响应页面到浏览器使用freemarker模板引擎技术实现,

  1. 首先从课程资料目录下获取课程预览页面course_template.html,
  2. 拷贝至内容管理的接口工程的resources/templates下,
  3. 并将其在本目录复制一份命名为course_template.ftl

下边开始定义接口:

package com.xuecheng.content.api;

/**
 * @author Mr.M
 * @version 1.0F
 * @description 课程预览,发布
 * @date 2022/9/16 14:48
 */
@Controller
public class CoursePublishController {
    @GetMapping("/coursepreview/{courseId}")
    public ModelAndView preview(@PathVariable("courseId") Long courseId) {

        ModelAndView modelAndView = new ModelAndView(); // 数据模型
        modelAndView.addObject("model", null); // 模型数据,暂时为null
        modelAndView.setViewName("course_template"); // 视图名称, 自动拼接.ftl后缀
        return modelAndView;
    }

}

重启内容管理接口工程,访问http://localhost:63040/content/coursepreview/74

注意: 如果Bean冲突了, 检查xuecheng-plus-generator工程中的controller代码, 解决冲突

课程预览接口虽然可以正常访问,但是页面没有样式,查看浏览器请求记录,发现图片、样式无法正常访问。

这些静态资源全在门户下,我们需要由Nginx反向代理访问课程预览接口,通过门户的URL去访问课程预览。

1、在Nginx下配置:

 #后台网关
  upstream gatewayserver{
    server 127.0.0.1:63010 weight=10;
  } 
  server {
        listen       80;
        server_name  www.51xuecheng.cn localhost;
        ....
        #api
        location /api/ {
                proxy_pass http://gatewayserver/;
        } 
        ....
}

2、重新加载Nginx配置文件:

nginx.exe -s reload

3、启动微服务网关

4、此时访问新地址: http://www.51xuecheng.cn/api/content/coursepreview/74

5、页面虽然正常,但是里边的内容都是静态内容,稍后接口层调用service方式获取模型数据并进行页面渲染。

6、目前的方式是通过Nginx访问网关,由网关再将请求转发到微服务,Nginx是整个的项目最前方的代理服务器,如下图:

接口开发

课程预览就是把课程基本信息、营销信息、课程计划、师资等课程的相关信息进行整合,在预览页面进行展示。如下图:

在使用freemarker渲染生成视图时需要数据模型,此数据模型包括了基本信息、营销信息、课程计划、师资等信息。

所以首先定义一个数据模型类:

package com.xuecheng.content.model.dto;

/**
 * @description 课程预览数据模型
 * @author Mr.M
 * @date 2022/9/16 15:03
 * @version 1.0
 */
@Data
@ToString
public class CoursePreviewDto {

    //课程基本信息,课程营销信息
    CourseBaseInfoDto courseBase;


    //课程计划信息
    List<TeachplanDto> teachplans;

    //师资信息暂时不加...

}
  • CourseBaseInfoDto:包括了课程基本信息、营销信息。
  • List<TeachplanDto> :包括了课程计划列表。

Service负责从数据库查询基本信息、营销信息、课程计划等课程相关信息,组成CoursePreviewDto 对象。

package com.xuecheng.content.service;

import com.xuecheng.content.model.dto.CoursePreviewDto;

/**
 * @description 课程预览、发布接口
 * @author Mr.M
 * @date 2022/9/16 14:59
 * @version 1.0
 */
public interface CoursePublishService {


    /**
     * @description 获取课程预览信息
     * @param courseId 课程id
     * @return com.xuecheng.content.model.dto.CoursePreviewDto
     * @author Mr.M
     * @date 2022/9/16 15:36
     */
    public CoursePreviewDto getCoursePreviewInfo(Long courseId);


}
package com.xuecheng.content.service.impl;

/**
 * @description TODO
 * @author Mr.M
 * @date 2022/9/16 15:37
 * @version 1.0
 */
@Service
public class CoursePublishServiceImpl implements CoursePublishService {

    @Autowired
    CourseBaseInfoService courseBaseInfoService;

    @Autowired
    TeachplanService teachplanService;


    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {

        //课程基本信息、营销信息
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);

        //课程计划信息
        List<TeachplanDto> teachplanTree= teachplanService.findTeachplanTree(courseId);

        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        coursePreviewDto.setCourseBase(courseBaseInfo);
        coursePreviewDto.setTeachplans(teachplanTree);
        return coursePreviewDto;
    }

}

接口层Controller调用Service方法获取模板引擎需要的模型数据

package com.xuecheng.content.api;

/**
 * @description 课程预览,发布
 * @author Mr.M
 * @date 2022/9/16 14:48
 * @version 1.0
 */
@Controller()
public class CoursePublishController {

    @Autowired
    CoursePublishService coursePublishService;

    @GetMapping("/coursepreview/{courseId}")
    public ModelAndView preview(@PathVariable("courseId") Long courseId){

        //获取课程预览信息
        CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId);

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("model",coursePreviewInfo);
        modelAndView.setViewName("course_template");
        return modelAndView;

    }

}

前后端联调

原来前端直接指向后台网关地址,现在要更改为Nginx的地址,如下:

重启前端工程,进入课程列表点击"预览"按钮,正常打开课程预览页面

http://www.51xuecheng.cn/api/content/coursepreview/2

编写模板

模型数据准备好后下一步将模型数据填充到course_template.ftl上,填充时注意不要一次填充太多,一边填充一边刷新调试。

  1. freemarker提供很多指令用于解析各种类型的数据模型,参考地址:http://freemarker.foofun.cn/ref_directives.html
  2. 修改模板后需要编译,如下图:

  1. 在调试模板时,可以看出哪些信息有缺少,在课程管理处进行补充,比如下图显示课程计划信息不完整,需要进入课程计划界面添加课程计划。

  1. 完整的course_template.ftl模板在课程资料目录下,差不多学会了freemarker标签的使用方法,将课程资料下的course_template.ftl覆盖自己的工程下的course_template.ftl。
  2. 覆盖后报错页面报错, 是因为模板文件的27行数据为null, 造成报错

视频播放页面接口

从课程详情页面进入视频播放页面,如下图:

在此页面需要从后台获取课程信息、根据课程计划获取对应的视频地址,下边编写这两个接口:

  1. 获取课程信息接口:/open/content/course/whole/{courseId}
/open/content/course/whole/课程id

响应:同课程预览service接口返回数据
  1. 根据课程计划获取视频地址接口:/open/media/preview/{mediaId}
Java
/open/media/preview/课程计划id

响应:
{"code":0,"msg":"success","result":"视频的url","successful":true}
  1. 在nginx配置如下地址
#openapi
location /open/content/ {
        proxy_pass http://gatewayserver/content/open/;
} 
location /open/media/ {
        proxy_pass http://gatewayserver/media/open/;
} 

配置运行nginx.exe -s reload加载nginx的配置文件

  1. 在内容管理接口层定义CourseOpenController类,并定义接口:获取课程信息接口:/open/content/course/whole/{courseId}
package com.xuecheng.content.api;

@Api(value = "课程公开查询接口",tags = "课程公开查询接口")
@RestController
@RequestMapping("/open")
public class CourseOpenController {

    @Autowired
    private CourseBaseInfoService courseBaseInfoService;

    @Autowired
    private CoursePublishService coursePublishService;


    @GetMapping("/course/whole/{courseId}")
    public CoursePreviewDto getPreviewInfo(@PathVariable("courseId") Long courseId) {
        //获取课程预览信息
        CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId);
        return coursePreviewInfo;
    }

}
  1. 在媒资管理服务media-api工程定义MediaOpenController类,并定义接口/open/media/preview/
package com.xuecheng.media.api;

@Api(value = "媒资文件管理接口",tags = "媒资文件管理接口")
@RestController
@RequestMapping("/open")
public class MediaOpenController {

    @Autowired
    MediaFileService mediaFileService;

    @ApiOperation("预览文件")
    @GetMapping("/preview/{mediaId}")
    public RestResponse<String> getPlayUrlByMediaId(@PathVariable String mediaId){

        MediaFiles mediaFiles = mediaFileService.getFileById(mediaId);
        if(mediaFiles == null || StringUtils.isEmpty(mediaFiles.getUrl())){
            XueChengPlusException.cast("视频还没有转码处理");
        }
        return RestResponse.success(mediaFiles.getUrl());

    }


}
package com.xuecheng.media.service;


/**
 * @author Mr.M
 * @version 1.0
 * @description 媒资文件管理业务类
 * @date 2022/9/10 8:55
 */
public interface MediaFileService {

    /**
     * 根据媒资文件id查询文件信息
     * @param mediaId
     * @return
     */
    MediaFiles getFileById(String mediaId);

}
package com.xuecheng.media.service.impl;


/**
 * @author Mr.M
 * @version 1.0
 * @description TODO
 * @date 2022/9/10 8:58
 */
@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {

    @Autowired
    MediaFilesMapper mediaFilesMapper;

    @Override
    public MediaFiles getFileById(String mediaId) {
        MediaFiles mediaFiles = mediaFilesMapper.selectById(mediaId);
        return mediaFiles;
    }

}
  1. 启动内容管理、媒资管理、后台服务网关服务,测试视频播放页面是否可以正常获取课程计划,点击具体的课程计划是否正常可以播放视频。

相关文章:

  • 论文阅读笔记:Denoising Diffusion Implicit Models (2)
  • Spring Boot 快速入手
  • node.js、npm相关知识
  • Redis 在 Linux 系统的安装指南
  • 【Docker项目实战】使用Docker部署NoteFlow笔记工具
  • 本地RAG知识库,如何进行数据结构化和清洗?
  • 在 Vue2 项目中配置自定义属性并在组件中使用,可按以下步骤进行:
  • 探秘 LPC 接收端重建:从理论根基到 Matlab 仿真实战
  • Android 应用程序包的 adb 命令
  • android studio 安装flutter插件
  • kubectl 命令
  • LLM的Sink(水槽) Token
  • 【漫话机器学习系列】168.最大最小值缩放(Min-Max Scaling)
  • 解锁兰亭妙微桌面端 UE/UI 设计,抢占数字先机
  • 主流数据库的存储引擎/存储机制的详细对比分析,涵盖关系型数据库、NoSQL数据库和分布式数据库
  • go游戏后端开发21:处理nats消息
  • 数据结构实验1.2: 顺序表的基本运算
  • 【CSS】- 表单控件的 placeholder 如何控制换行显示?
  • 自动驾驶---学术论文的常客:nuScenes数据集的使用
  • 卫星电话究竟是“锦上添花”?还是“刚需之选”?
  • 深入贯彻中央八项规定精神学习教育中央第六指导组指导督导中国工商银行见面会召开
  • 李彦宏:技术迭代速度之快从业30年来未见过,要提升执行力战胜对手
  • 两国战机均未侵入对方领空,巴方公布对印回击细节
  • 联合国秘书长吁印巴“最大程度克制”,特朗普:遗憾,希望尽快结束冲突
  • 李云泽:大型保险集团资本补充已经提上日程
  • 《蓦然回首》:现代动画的践行与寓言