学成在线笔记+踩坑(8)——课程预览、提交审核,Freemarker模板引擎

news2024/11/13 8:35:48

导航:

【黑马Java笔记+踩坑汇总】JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud+黑马旅游+谷粒商城+学成在线+牛客面试题_java黑马笔记 

目录

1 模块需求分析

1.1 模块介绍

1.2 业务流程

1.2.1 课程预览

1.2.2 课程审核

1.2.3 课程发布

2 课程预览

2.1 需求分析

2.2 模板引擎

2.2.1 什么是模板引擎

2.2.2 Freemarker快速入门

2.3 测试静态页面

2.3.1 部署网站门户

2.3.2 课程详情页面

2.3.3 Nginx配置文件服务器地址(先不配网关)

2.3.4 Nginx视频播放静态页面路由

2.4 接口定义

2.4.1 课程预览接口,根据课程id返回ModelAndView对象

2.4.2 Nginx配置反向代理(配网关)

2.5 接口开发

2.5.1 课程预览信息模型类抽取

2.5.2 Service,根据课程id查询模型类

service,根据id查询课程基本信息、营销信息 

service,dao外连接,根据id查询课程计划信息

2.5.3 接口层完善

2.5.4 前后端联调

2.5.5 编写模板

2.5.6 视频播放页面,查询视频url和预览模型类

3 课程提交审核

3.1 需求分析

3.1.1 业务流程

3.1.2 课程预发布表和审核记录表

3.2 接口定义,根据课程id提交审核

3.3 业务实现

3.3.1 业务流程

3.3.2 Service,根据机构id和课程id提交审核

3.4 接口完善

3.5 测试


1 模块需求分析

1.1 模块介绍

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

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

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

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

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

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

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

1、课程预览

2、课程审核

3、课程发布

1.2 业务流程

1.2.1 课程预览

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

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

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

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

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

1.2.2 课程审核

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

流程如下:

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

2、课程审核

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

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

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

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

1.2.3 课程发布

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

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

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

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

2 课程预览

2.1 需求分析

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

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

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

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

说明如下:

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

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

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

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

2.2 模板引擎

2.2.1 什么是模板引擎

springboot推荐的模板引擎是thymeleaf,老技术还用模板引擎,推荐前后端分离。 

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

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

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

1、浏览器请求web服务器

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

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

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

常用的java模板引擎还有哪些?

Jsp、Freemarker、Thymeleaf 、Velocity 等。

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

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

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

2.2.2 Freemarker快速入门

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

在内容管理接口工层 添加Freemarker与SpringBoot的整合包

<!-- Spring Boot 对结果视图 Freemarker 集成 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

在nacos为内容管理接口层配置freemarker,公用配置组新加一个freemarker-config-dev.yaml

配置信息如下:

spring:
  freemarker:
    enabled: true
    cache: false   #关闭模板缓存,方便测试
    settings:
      template_update_delay: 0
    suffix: .ftl   #页面模板后缀名
    charset: UTF-8
    template-loader-path: classpath:/templates/   #页面模板位置(默认为 classpath:/templates/)
    resources:
      add-mappings: false   #关闭项目中的静态资源映射(static、resources文件夹下的资源)

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

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

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
Hello ${name}!
</body>
</html>

编写controller方法,准备模型数据

package com.xuecheng.content.api;

/**
 * @description freemarker测试
 */
@Controller
public class FreemarkerController {

    @GetMapping("/testfreemarker")
    public ModelAndView test(){
        ModelAndView modelAndView = new ModelAndView();
        //设置模型数据
        modelAndView.addObject("name","小明");
        //设置模板名称
        modelAndView.setViewName("test");
        return modelAndView;
    }


}

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

屏幕输出:Hello 小明!

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

2.3 测试静态页面

2.3.1 部署网站门户

在课程预览界面上要加载css、js、图片等内容,这里部署nginx来访问这些静态资源,对于SpringBoot服务的动态资源由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端口修改为空闲端口。

启动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

3、在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;
        #}
    }

启动nginx:

进入任务管理器,杀死nginx的两个进程

杀死后再次双击nginx.exe。

启动成功在任务管理器会出现nginx的进程。

日志文件在nginx安装目录下的logs目录:

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

2.3.2 课程详情页面

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

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

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

效果如下:

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

2.3.3 Nginx配置文件服务器地址(先不配网关)

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

在hosts文件配置如下内容,如果已存在不要重复配置。

127.0.0.1 www.51xuecheng.cn file.51xuecheng.cn

在nginx.conf中配置文件服务器的代理地址

Nginx回顾:配置文件详看下文第三小节:

Nginx基础_vincewm的博客-CSDN博客  

   #文件服务
  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;
        }
   }

配置完毕,重新加载nginx配置文件。

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

nginx.exe -s reload

通过http://file.51xuecheng.cn/mediafiles/图片文件地址  访问图片

在媒资数据

2.3.4 Nginx视频播放静态页面路由

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

首先在nginx.conf中配置视频播放页面的地址

        location /course/preview/learning.html {
                alias D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal/course/learning.html;
        }
        location /course/search.html { 
                root   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal;
        }
        location /course/learning.html { 
                root   D:/itcast2022/xc_edu3.0/code_1/xc-ui-pc-static-portal;
        }

加载nginx配置文件

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

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

配置完成,刷新页面,观察视频是否可以正常播放。

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

2.4 接口定义

2.4.1 课程预览接口,根据课程id返回ModelAndView对象

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

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

1、请求参数

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

2、响应结果

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

响应页面到浏览器使用freemarker模板引擎技术实现,首先从课程资料目录下获取课程预览页面course_template.html,拷贝至内容管理的接口工程的resources/templates下,并将其在本目录复制一份命名为course_template.ftl

下边开始定义接口:

注意:

不用@RestController,因为不要@ResponseBody,因为方法返回值不是JSON

package com.xuecheng.content.api;
/**
 * @description 课程预览,发布
 */
 @Controller
public class CoursePublishController {


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

      ModelAndView modelAndView = new ModelAndView();
//指定模型
      modelAndView.addObject("model",null);
//指定模板
      modelAndView.setViewName("course_template");//根据视图名称加“.ftl”找到模板,即course_template.ftl
   return modelAndView;
  }

}

回顾thymeleaf用法:

package com.xuecheng.content.api;
/**
 * @description 课程预览,发布,thymeleaf方法
 */
 @Controller
public class CoursePublishController {


 @GetMapping("/coursepreview/{courseId}")
 public String preview(@PathVariable("courseId") Long courseId,Model model){


//指定模型
      model.addAttribute("model",null);
//指定模板
   return "course_template";//等同于classpath:/templates/course_template.ftl
  }

}

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

如下图:

课程预览页面内容没有样式,稍后解决这个问题。

2.4.2 Nginx配置反向代理(配网关)

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

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

1、在Nginx下配置:

Nginx回顾:配置文件详看下文第三小节:

Nginx基础_vincewm的博客-CSDN博客

   #后台网关
  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

输出如下,页面样式正常。

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

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

2.5 接口开发

2.5.1 课程预览信息模型类抽取

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

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

课程预览信息模型类

package com.xuecheng.content.model.dto;

/**
 * @description 课程预览数据模型
 */
 @Data
 @ToString
public class CoursePreviewDto {

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


    //课程计划信息
    List<TeachplanDto> teachplans;
   
    //师资信息暂时不加...


}

CourseBaseInfoDto:包括了课程基本信息、营销信息。

//课程基本信息dto
@Data
public class CourseBaseInfoDto extends CourseBase {


 /**
  * 收费规则,对应数据字典
  */
 private String charge;

 /**
  * 价格
  */
 private Float price;


 /**
  * 原价
  */
 private Float originalPrice;

 /**
  * 咨询qq
  */
 private String qq;

 /**
  * 微信
  */
 private String wechat;

 /**
  * 电话
  */
 private String phone;

 /**
  * 有效期天数
  */
 private Integer validDays;

 /**
  * 大分类名称
  */
 private String mtName;

 /**
  * 小分类名称
  */
 private String stName;

}

List<TeachplanDto> :包括了课程计划列表。

TeachplanDto

/**
 * @description 课程计划信息模型类
 */
@Data
@ToString
public class TeachplanDto extends Teachplan {
  //与媒资管理的信息
   private TeachplanMedia teachplanMedia;

  //小章节list
   private List<TeachplanDto> teachPlanTreeNodes;
}

2.5.2 Service,根据课程id查询模型类

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

package com.xuecheng.content.service.impl;

@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;
 }
}

service,根据id查询课程基本信息、营销信息 

CourseBaseInfoServiceImpl
    //查询课程信息
    public CourseBaseInfoDto getCourseBaseInfo(Long courseId){

        //从课程基本信息表查询
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        if(courseBase==null){
            return null;
        }
        //从课程营销表查询
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);

        //组装在一起
        CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto();
        BeanUtils.copyProperties(courseBase,courseBaseInfoDto);
        if(courseMarket!=null){
            BeanUtils.copyProperties(courseMarket,courseBaseInfoDto);
        }

        //通过courseCategoryMapper查询分类信息,将分类名称放在courseBaseInfoDto对象
        CourseCategory mtObj = courseCategoryMapper.selectById(courseBase.getMt());
        String mtName = mtObj.getName();//大分类名称
        courseBaseInfoDto.setMtName(mtName);
        CourseCategory stObj = courseCategoryMapper.selectById(courseBase.getSt());
        String stName = stObj.getName();//小分类名称
        courseBaseInfoDto.setStName(stName);

        return courseBaseInfoDto;

    }

service,dao外连接,根据id查询课程计划信息

TeachplanService课程计划信息
    @Override
    public List<TeachplanDto> findTeachplanTree(Long courseId) {
        List<TeachplanDto> teachplanDtos = teachplanMapper.selectTreeNodes(courseId);
        return teachplanDtos;
    }
    <select id="selectTreeNodes" parameterType="long" resultMap="treeNodeResultMap">

        select
            one.id            one_id,
            one.pname         one_pname,
            one.parentid      one_parentid,
            one.grade         one_grade,
            one.media_type    one_mediaType,
            one.start_time    one_stratTime,
            one.end_time      one_endTime,
            one.orderby       one_orderby,
            one.course_id     one_courseId,
            one.course_pub_id one_coursePubId,
            two.id            two_id,
            two.pname         two_pname,
            two.parentid      two_parentid,
            two.grade         two_grade,
            two.media_type    two_mediaType,
            two.start_time    two_stratTime,
            two.end_time      two_endTime,
            two.orderby       two_orderby,
            two.course_id     two_courseId,
            two.course_pub_id two_coursePubId,
            m1.media_fileName mediaFilename,
            m1.id             teachplanMeidaId,
            m1.media_id       mediaId
        from teachplan one
                 left join teachplan two on two.parentid = one.id
                 left join teachplan_media m1 on two.id = m1.teachplan_id
        where one.parentid = 0
          and one.course_id = #{id}
        order by one.orderby,two.orderby

    </select>

2.5.3 接口层完善

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

@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;
 }

2.5.4 前后端联调

期待效果:点击课程管理中“预览”,跳转预览的视频详情页

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

重启前端工程,进入课程列表点击"预览"按钮,正常打开课程预览页面http://www.51xuecheng.cn/api/content/coursepreview/2

2.5.5 编写模板

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

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

修改模板后需要编译,如下图:

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

完整的course_template.ftl模板略:

2.5.6 视频播放页面,查询视频url和预览模型类

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

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

两个请求和响应:

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

/open/content/course/whole/课程id

响应:同课程预览service接口返回数据

根据课程计划获取视频地址接口:/open/media/preview/{mediaId}

/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的配置文件

2、根据课程id查询课程预览信息

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

代码如下:

 @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;
}

}

3、【媒资模块】根据文件id获取视频url

在媒资管理服务media-api工程定义MediaOpenController类,并定义接口/open/media/preview/

代码如下:

@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());

    }


}

5、测试

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

3 课程提交审核

3.1 需求分析

3.1.1 业务流程

根据模块需求分析,课程发布前要先审核,审核通过方可发布。下图是课程审核及发布的流程图:

为什么课程审核通过才可以发布呢?

这样做为了防止课程信息有违规情况,课程信息不完善对网站用户体验也不好,课程审核不仅起到监督作用,也是帮助教学机构规范使用平台的手段。

如何控制课程审核通过才可以发布课程呢?

在课程基本表course_base表设置课程审核状态字段,包括:未提交、已提交(未审核)、审核通过、审核不通过。

下边是课程状态的转化关系:

说明如下:

1、一门课程新增后它的审核状为”未提交“,发布状态为”未发布“。

2、课程信息编辑完成,教学机构人员执行”提交审核“操作。此时课程的审核状态为”已提交“。

3、当课程状态为已提交时运营平台人员对课程进行审核。

4、运营平台人员审核课程,结果有两个:审核通过、审核不通过。

5、课程审核过后不管状态是通过还是不通过,教学机构可以再次修改课程并提交审核,此时课程状态为”已提交“。此时运营平台人员再次审核课程。

6、课程审核通过,教学机构人员可以发布课程,发布成功后课程的发布状态为”已发布“。

7、课程发布后通过”下架“操作可以更改课程发布状态为”下架“

8、课程下架后通过”上架“操作可以再次发布课程,上架后课程发布状态为“发布”。

3.1.2 课程预发布表和审核记录表

审核后允许数据修改:

如果不允许修改是不合理的,因为提交审核后可以继续做下一个阶段的课程内容,比如添加课程计划,上传课程视频等。

如果允许修改那么课程审核时看到的课程内容从哪里来?如果也从课程基本信息表、课程营销表、课程计划表查询那么存在什么问题呢?如下图:

运营人员审核课程和教学机构编辑课程操作的数据是同一份,此时会导致冲突。比如:运营人员正在审核时教学机构把数据修改了。

使用课程预发布表,解决审核时数据修改问题:

如下图:

提交课程审核,将课程信息汇总后写入课程预发布表,课程预发布表记录了教学机构在某个时间点要发布的课程信息。

课程审核人员从预发布表查询信息进行审核。

课程审核的同时可以对课程进行修改,修改的内容不会写入课程预发布表。

课程审核通过执行课程发布,将课程预发布表的信息写入课程发布表。

审核后、修改后、允许再次提交审核:

这个问题在上边分析课程审核状态时已经有了答案,如下图:

提交审核课程后,必须等到课程审核完成后才可以再次提交课程。

课程审核功能涉及教学机构提交审核,运营人员进行课程审核。在课堂上我们仅实现教学机构提交审核功能,课程审核的结果通过手动修改数据库来实现。

虽然课堂上不实现课程审核功能,完整的课程审核数据表设计需要理解。

提交审核将信息写入课程预发布表course_publish_pre,表结构与课程发布表相似,主要是审核状态字段和发布上架字段不同:

更新课程基本信息表的课程审核状态为:已经提交

课程审核后更新课程基本信息表的审核状态、课程预发布表的审核状态,并将审核结果写入课程审核记录。

课程发布表:

审核记录表course_audit结构如下:

3.2 接口定义,根据课程id提交审核

下边定义提交课程审核的接口,在课程发布Controller中定义接口如下:

 @ResponseBody
@PostMapping ("/courseaudit/commit/{courseId}")
public void commitAudit(@PathVariable("courseId") Long courseId){

 }

3.3 业务实现

3.3.1 业务流程

1、查询课程基本信息、课程营销信息、课程计划信息等课程相关信息,整合为课程预发布信息。

2、向课程预发布表course_publish_pre插入一条记录,如果已经存在则更新,审核状态为:已提交。

3、更新课程基本表course_base课程审核状态为:已提交。

不允许提交审核的情况:

1、对已提交审核的课程不允许提交审核。

2、本机构只允许提交本机构的课程。

3、没有上传图片不允许提交审核。

4、没有添加课程计划不允许提交审核。

3.3.2 Service,根据机构id和课程id提交审核

CoursePublishServiceImpl

    @Transactional
    @Override
    public void commitAudit(Long companyId, Long courseId) {

        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
        if (courseBaseInfo == null) {
            XueChengPlusException.cast("课程找不到");
        }
        //审核状态
        String auditStatus = courseBaseInfo.getAuditStatus();

        //如果课程的审核状态为已提交则不允许提交
        if (auditStatus.equals("202003")) {
            XueChengPlusException.cast("课程已提交请等待审核");
        }
        //本机构只能提交本机构的课程
        //todo:本机构只能提交本机构的课程

        //课程的图片、计划信息没有填写也不允许提交
        String pic = courseBaseInfo.getPic();
        if (StringUtils.isEmpty(pic)) {
            XueChengPlusException.cast("请求上传课程图片");
        }
        //查询课程计划
        //课程计划信息
        List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId);
        if (teachplanTree == null || teachplanTree.size() == 0) {
            XueChengPlusException.cast("请编写课程计划");
        }

        //查询到课程基本信息、营销信息、计划等信息插入到课程预发布表
        CoursePublishPre coursePublishPre = new CoursePublishPre();
        BeanUtils.copyProperties(courseBaseInfo, coursePublishPre);
        //设置机构id
        coursePublishPre.setCompanyId(companyId);
        //营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        //转json
        String courseMarketJson = JSON.toJSONString(courseMarket);
        coursePublishPre.setMarket(courseMarketJson);
        //计划信息
        //转json
        String teachplanTreeJson = JSON.toJSONString(teachplanTree);
        coursePublishPre.setTeachplan(teachplanTreeJson);
        //状态为已提交
        coursePublishPre.setStatus("202003");
        //提交时间
        coursePublishPre.setCreateDate(LocalDateTime.now());
        //查询预发布表,如果有记录则更新,没有则插入
        CoursePublishPre coursePublishPreObj = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPreObj == null) {
            //插入
            coursePublishPreMapper.insert(coursePublishPre);
        } else {
            //更新
            coursePublishPreMapper.updateById(coursePublishPre);
        }

        //更新课程基本信息表的审核状态为已提交
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setAuditStatus("202003");//审核状态为已提交

        courseBaseMapper.updateById(courseBase);
    }

3.4 接口完善

完善接口层的代码

 @ResponseBody
@PostMapping ("/courseaudit/commit/{courseId}")
public void commitAudit(@PathVariable("courseId") Long courseId){
     Long companyId = 1232141425L;
     coursePublishService.commitAudit(companyId,courseId);

 }

3.5 测试

使用前端提前课程审核:

1、找一门信息不全的课程,测试各各约束条件。

2、正常提交后,观察数据库中课程预发布表记录的内容是否完整。

3、测试审核过后再次提交,提交后观察数据库中课程预发布表记录的内容是否正确。

审核通过需手动修改数据库:

1、修改课程预发布表的状态为审核通过202004。

2、修改课程基本表的审核状态为审核通过202004。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/458741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习 - 43.SeNET、Bilinear Interaction 实现特征交叉 By Keras

目录 一.引言 二.SENET Layer 1.简介 2.Keras 实现 2.1 Init Function 2.2 Build Function 2.3 Call Function 2.4 Test Main Function 2.5 完整代码 三.BiLinear Intercation Layer 1.简介 2.Keras 实现 2.1 Init Function 2.2 Build Function 2.3 Call Functi…

〖ChatGPT实践指南 - 零基础扫盲篇③〗- 开始使用 ChatGPT 并访问 OpenAI 获取 API Keys

文章目录 ⭐ 访问 ChatGPT 并登录⭐ OpenAI API keys 简介⭐ 获取 OpenAI 的 API keys 文件 请注意&#xff0c;该章节介绍的是如何使用 ChatGPT &#xff0c;并通过登录ChatGPT后访问 OpenAI 获取 API Keys&#xff0c;并不涉及如何科学的注册 ChatGPT。 ⭐ 访问 ChatGPT 并登…

D. Mysterious Present(Codeforces Beta Round 4 (Div. 2 Only))

https://codeforces.com/contest/4/problem/D 题目大意 给定 n n n 个信封的长和宽&#xff0c;以及一张卡片的长和宽&#xff0c;要求选出最多的信封&#xff0c;并且这些信封的长和宽都比前面的信封要大&#xff0c;并且最小的信封能够装下这张卡片。输出这些信封的数量和…

VS项目常规属性

常规属性页&#xff08;项目&#xff09; 常规 目标平台 指定运行项目的平台。例如&#xff0c;Windows&#xff0c;Android或iOS。 在此处&#xff0c;值 Windows 10 表示项目面向通用 Windows 平台。此属性是在创建项目时设置的只读字段。 目标平台版本 指定用于生成项目…

基于html+css的图展示41

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

智慧园区数字化转型下的移动App发展

随着智慧城市的建设和智慧园区的崛起&#xff0c;智慧园区数字一体化建设成为园区发展的重心&#xff0c;当然数字转型离不开移动应用的整合服务。 在过去的几年中&#xff0c;智慧园区移动应用已经发展成为园区管理和服务的重要手段之一&#xff0c;为企业和员工提供了更加便…

OkHttp3源码解析 - 连接机制和缓存机制

系列文章目录 第一章 OkHttp3源码解析 - 请求流程 第二章 OkHttp3源码解析 - 拦截器 第三章 OkHttp3源码解析 - 连接机制和缓存机制 文章目录 系列文章目录前言一、连接机制1.1 创建连接1.2 连接池 二、缓存机制2.1 缓存策略2.2 缓存管理 彩蛋致谢 前言 本文基于okhttp3.12.1…

我的一些实战的漏洞挖掘过程(一)

最近挖到的漏洞&#xff0c;在这里分享一下&#xff0c;有些信息比较敏感就打码处理&#xff0c;目标网站都换为target.com 反射xss漏洞挖掘 跨站脚本攻击&#xff08;Cross-site Scripting&#xff0c;XSS&#xff09;是一种常见的Web安全漏洞&#xff0c;攻击者通过在Web应…

Windows上使用gcc

安装 下载x86_64-7.3.0-release-win32-seh-rt_v5-rev0 安装包&#xff0c;解压&#xff0c;将对应解压路径下的bin加入环境变量path&#xff0c;将mingw32-make.exe 改名make.exe&#xff0c;使用gcc同样可以在Windows上生成.o文件和.a文件&#xff0c;也可以生成.lib文件 te…

AI思维导图来了,让活动策划更加简单!

每当有活动的时候&#xff0c;都会让策划的小伙伴绞尽脑汁&#xff01; ProcessOn一直致力于提升大家的办公效率。新增的AI功能&#xff0c;可以帮助我们一键生成思维导图、流程图。让一切变得更加简单。 没有灵感&#xff1f;没有关系。不知道怎么做&#xff0c;没有关系&a…

五种原因导致孩子易患口腔溃疡,专家为你一一支招

最近&#xff0c;常接到电话咨询&#xff1a;疫情期间&#xff0c;孩子宅在家&#xff0c;反复起“口疮”怎么办&#xff1f; 这里说到的“口疮”&#xff0c;即是一种常见的口腔黏膜疾病——口腔溃疡。口腔溃疡的发病率较高&#xff0c;不仅成年人可能患病&#xff0c;不少儿…

使用PyTorch和Flower 进行联邦学习

本文将介绍如何使用 Flower 构建现有机器学习工作的联邦学习版本。我们将使用 PyTorch 在 CIFAR-10 数据集上训练卷积神经网络&#xff0c;然后将展示如何修改训练代码以联邦的方式运行训练。 什么是联邦学习&#xff1f; 我们将在这篇文章中区分两种主要方法&#xff1a;集中…

数据库的概念?怎么在linux内安装数据库?怎么使用?

目录 一、概念 二、mysql安装及设置 1.安装mysql 2.数据库服务启动停止 三、数据库基本操作 1、数据库的登录及退出 2、数据表的操作 3、mysql查询操作 一、概念 数据库:是存放数据的仓库&#xff0c;它是一个按数据结构来存储和管理数据的计算机软件系统。数据库管理…

BM38-在二叉树中找到两个节点的最近公共祖先

题目 给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2&#xff0c;请找到 o1 和 o2 的最近公共祖先节点。 数据范围&#xff1a;树上节点数满足 1≤n≤10^5 , 节点值val满足区间 [0,n) 要求&#xff1a;时间复杂度 O(n) 注&#xff1a;本题保证二叉树…

深入理解Javascript事件处理机制

深入理解javascript事件处理机制 前言 在开发web应用程序时&#xff0c;事件处理机制是javascript中至关重要的一部分。许多高级特性&#xff0c;如事件冒泡、事件捕获和事件委托&#xff0c;都是通过事件处理来实现的。熟练掌握这些技术可以帮助我们更好地组织代码、提高代码…

腾讯多媒体实验室画质增强技术的前沿应用

全真互联时代&#xff0c;音视频技术内核不断更新迭代&#xff0c;LiveVideoStackCon 2022 北京站邀请到腾讯多媒体实验室视频技术研发负责人——夏珍&#xff0c;与大家分享画质增强技术的一些前沿探索和应用研究&#xff0c;在经典影像中非常重要的画质提升技术人脸修复和去压…

告别web.xml映射Servlet、Filter、Listener,解锁注解新方式开发

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 服务器软件&#xff1a;apache-tomcat-8.5.27 目录 一. Servlet、Filter、Listener的注解方式是什么&#xff1f;二. 为什么要使用Servlet、Filter、Listener的注解方式&#xff1f;三…

【架构】互联网应用开发架构演进历程

文章目录 一、背景二、技术架构演进史三、架构演进一: 早期雏形四、架构演进二: 数据库开发&#xff08;LAMP特长&#xff09;五、架构演进三: javaweb的雏形六、架构演进四: javaweb的集群发展​七、架构演进五: javaweb的分布式发展八、架构演进六: javaweb的微服务发展​8.1…

开源 AI 辅助编程工具 AutoDev 现已上架 Jetbrains 插件市场

我们非常高兴地宣布 AutoDev v0.2.0 的发布&#xff01;AutoDev 是一款强大的 AI 辅助编程工具&#xff0c;可以与 Jetbrains 系列 IDE 无缝集成&#xff08;VS Code 支持正在开发中&#xff09;。通过与需求管理系统&#xff08;如 Github Issue 等&#xff09;直接对接&#…

WPF教程(八)--数据绑定(1)--基础概述

使用WPF可以很方便的设计出强大的用户界面&#xff0c;同时 WPF提供了数据绑定功能。WPF的数据绑定跟Winform与ASP.NET中的数据绑定功能类似&#xff0c;但也有所不同&#xff0c;在 WPF中以通过后台代码绑定、前台XAML中进行绑定&#xff0c;或者两者组合的方式进行数据绑定。…