Kevin's blog Kevin's blog
首页
  • Java基础
  • Java高级
  • MySQL
  • JDBC
  • Java 8新特性
  • 原生Servlet
  • 延迟队列
  • 分布式事务
  • ActiveMQ
  • Elasticsearch
  • Stream API
  • Redis 实战(黑马程序员)
  • Redis 课程(尚硅谷)
  • Redis数据类型和常用命令
  • 版本控制
  • Spring Framework
  • Spring MVC Framework
  • MyBatis Framework
  • MyBatis Plus Framework
  • Spring Boot Framework
  • 韩顺平 Spring Boot Framework
  • 在线教育
  • 谷粒商城 - 分布式基础 高级 集群
  • 谷粒商城 - 详细开发文档
  • docker基础
  • docker-compose容器编排
  • docker swarm集群管理
  • Vue2基础
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Kevin

Java系统笔记
首页
  • Java基础
  • Java高级
  • MySQL
  • JDBC
  • Java 8新特性
  • 原生Servlet
  • 延迟队列
  • 分布式事务
  • ActiveMQ
  • Elasticsearch
  • Stream API
  • Redis 实战(黑马程序员)
  • Redis 课程(尚硅谷)
  • Redis数据类型和常用命令
  • 版本控制
  • Spring Framework
  • Spring MVC Framework
  • MyBatis Framework
  • MyBatis Plus Framework
  • Spring Boot Framework
  • 韩顺平 Spring Boot Framework
  • 在线教育
  • 谷粒商城 - 分布式基础 高级 集群
  • 谷粒商城 - 详细开发文档
  • docker基础
  • docker-compose容器编排
  • docker swarm集群管理
  • Vue2基础
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 项目 在线教育

    • 项目简介

    • Mybatis Plus入门

    • 课程中心微服务搭建

    • 前后端分离相关知识

    • 后台管理系统前端页面的搭建

    • 整合阿里云OSS文件上传

    • 使用POI实现Excel导入导出

    • 整合POI实现课程类目管理

    • 课程基本信息管理

    • 课程章节信息管理

    • 课程课时管理

    • 使用阿里云视频点播

    • 媒资管理

    • spring cloud服务发现和服务调用

    • 整合ECharts实现统计分析

    • 服务端渲染NUXT

      • 服务端渲染技术NUXT-初始化NUXT
      • 首页和路由
      • 名师页面
      • 课程页面
      • 讲师列表页
      • 讲师详情页
      • 课程列表页面
      • 课程详情页
        • 一、vo对象的定义
        • 二、课程和讲师信息的获取
          • 1、Mapper中关联查询课程和讲师信息
          • 2、业务层获取数据并更新浏览量
          • 3、接口层
          • 4、swagger测试
        • 三、前端js
          • 1、api/course.js
          • 2、pages/course/_id.vue
        • 四、页面模板
          • 1、template
          • 2、课程所属分类
          • 3、课程基本信息
          • 4、课程详情介绍
          • 5、课程大纲
          • 6、主讲讲师
    • 整合阿里云播放器

    • 微服务安全

    • 整合微信登录

    • spring cloud zuul 微服务网关在项目中的应用

    • 总结

  • 项目 谷粒商城

  • 项目 谷粒商城详细开发文档

  • Project
  • 项目 在线教育
  • 服务端渲染NUXT
zhihuanwang
2023-09-25
目录

课程详情页

# 一、vo对象的定义

在项目中很多时候需要把model转换成dto用于网站信息的展示,按前端的需要传递对象的数据,保证model对外是隐私的,例如密码之类的属性能很好地避免暴露在外,同时也会减小数据传输的体积。

CourseWebVo.java
package com.guli.edu.vo;

@ApiModel(value="课程信息", description="网站课程详情页需要的相关字段")
@Data
public class CourseWebVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String id;

    @ApiModelProperty(value = "课程标题")
    private String title;

    @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
    private BigDecimal price;

    @ApiModelProperty(value = "总课时")
    private Integer lessonNum;

    @ApiModelProperty(value = "课程封面图片路径")
    private String cover;

    @ApiModelProperty(value = "销售数量")
    private Long buyCount;

    @ApiModelProperty(value = "浏览数量")
    private Long viewCount;

    @ApiModelProperty(value = "课程简介")
    private String description;

    @ApiModelProperty(value = "讲师ID")
    private String teacherId;

    @ApiModelProperty(value = "讲师姓名")
    private String teacherName;
    
    @ApiModelProperty(value = "讲师资历,一句话说明讲师")
    private String intro;

    @ApiModelProperty(value = "讲师头像")
    private String avatar;

    @ApiModelProperty(value = "课程类别ID")
    private String subjectLevelOneId;

    @ApiModelProperty(value = "类别名称")
    private String subjectLevelOne;

    @ApiModelProperty(value = "课程类别ID")
    private String subjectLevelTwoId;

    @ApiModelProperty(value = "类别名称")
    private String subjectLevelTwo;
    
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 二、课程和讲师信息的获取

# 1、Mapper中关联查询课程和讲师信息

CourseMapper.java

CourseWebVo selectInfoWebById(String courseId);
1

CourseMapper.xml

<select id="selectInfoWebById" resultType="com.guli.edu.vo.CourseWebVo">
  SELECT
    c.id,
    c.title,
    c.cover,
    CONVERT(c.price, DECIMAL(8,2)) AS price,
    c.lesson_num AS lessonNum,
    c.cover,
    c.buy_count AS buyCount,
    c.view_count AS viewCount,
    cd.description,

    t.id AS teacherId,
    t.name AS teacherName,
    t.intro,
    t.avatar,
    
    s1.id AS subjectLevelOneId,
    s1.title AS subjectLevelOne,
    s2.id AS subjectLevelTwoId,
    s2.title AS subjectLevelTwo

  FROM
    edu_course c
    LEFT JOIN edu_course_description cd ON c.id = cd.id
    LEFT JOIN edu_teacher t ON c.teacher_id = t.id
    LEFT JOIN edu_subject s1 ON c.subject_parent_id = s1.id
    LEFT JOIN edu_subject s2 ON c.subject_id = s2.id
  WHERE
    c.id = #{id}
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 2、业务层获取数据并更新浏览量

CourseService

接口

/**
     * 获取课程信息
     * @param id
     * @return
     */
CourseWebVo selectInfoWebById(String id);

/**
     * 更新课程浏览数
     * @param id
     */
void updatePageViewCount(String id);
1
2
3
4
5
6
7
8
9
10
11
12

实现

@Transactional
@Override
public CourseWebVo selectInfoWebById(String id) {
    this.updatePageViewCount(id);
    return baseMapper.selectInfoWebById(id);
}

@Override
public void updatePageViewCount(String id) {
    Course course = baseMapper.selectById(id);
    course.setViewCount(course.getViewCount() + 1);
    baseMapper.updateById(course);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3、接口层

CourseController

@Autowired
private ChapterService chapterService;

@ApiOperation(value = "根据ID查询课程")
@GetMapping(value = "{courseId}")
public R getById(
    @ApiParam(name = "courseId", value = "课程ID", required = true)
    @PathVariable String courseId){

    //查询课程信息和讲师信息
    CourseWebVo courseWebVo = courseService.selectInfoWebById(courseId);

    //查询当前课程的章节信息
    List<ChapterVo> chapterVoList = chapterService.nestedList(courseId);

    return R.ok().data("course", courseWebVo).data("chapterVoList", chapterVoList);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4、swagger测试

# 三、前端js

# 1、api/course.js

getById(courseId) {
    return request({
        url: `${api_name}/${courseId}`,
        method: 'get'
    })
}
1
2
3
4
5
6

# 2、pages/course/_id.vue

<script>
import course from "@/api/course"
export default {
  asyncData({ params, error }) {
    return course.getById(params.id).then(response => {
      console.log(response);
      return { 
        course: response.data.data.course,
        chapterList: response.data.data.chapterVoList
      }
    })
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 四、页面模板

pages/course/_id.vue

# 1、template

<template>
  <div id="aCoursesList" class="bg-fa of">
    <!-- 课程详情 开始 -->
    <section class="container">

      <!-- 课程所属分类 开始 -->

      <!-- /课程所属分类 结束 -->

      <!-- 课程基本信息 开始 -->

      <!-- /课程基本信息 结束 -->

      <div class="mt20 c-infor-box">
        <article class="fl col-7">
          <section class="mr30">
            <div class="i-box">
              <div>
                <section id="c-i-tabTitle" class="c-infor-tabTitle c-tab-title">
                  <a name="c-i" class="current" title="课程详情">课程详情</a>
                </section>
              </div>
              <article class="ml10 mr10 pt20">

                <!-- 课程详情介绍 开始 -->

                <!-- /课程详情介绍 结束 -->

                <!-- 课程大纲 开始-->

                <!-- /课程大纲 结束 -->
              </article>
            </div>
          </section>
        </article>
        <aside class="fl col-3">
          <div class="i-box">
            <!-- 主讲讲师 开始-->

            <!-- /主讲讲师 结束 -->
          </div>
        </aside>
        <div class="clear"/>
      </div>
    </section>
    <!-- /课程详情 结束 -->
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 2、课程所属分类

<!-- 课程所属分类 开始 -->
<section class="path-wrap txtOf hLh30">
    <a href="#" title class="c-999 fsize14">首页</a>
    \
    <a href="/course" title class="c-999 fsize14">课程列表</a>
    \
    <span class="c-333 fsize14">{{ course.subjectLevelOne }}</span>
    \
    <span class="c-333 fsize14">{{ course.subjectLevelTwo }}</span>
</section>
<!-- /课程所属分类 结束 -->
1
2
3
4
5
6
7
8
9
10
11

# 3、课程基本信息

<!-- 课程基本信息 开始 -->
<div>
    <article class="c-v-pic-wrap" style="height: 357px;">
        <section id="videoPlay" class="p-h-video-box">
            <img :src="course.cover" :alt="course.title" class="dis c-v-pic">
        </section>
    </article>
    <aside class="c-attr-wrap">
        <section class="ml20 mr15">
            <h2 class="hLh30 txtOf mt15">
                <span class="c-fff fsize24">{{ course.title }}</span>
            </h2>
            <section class="c-attr-jg">
                <span class="c-fff">价格:</span>
                <b class="c-yellow" style="font-size:24px;">¥{{ course.price }}</b>
            </section>
            <section class="c-attr-mt c-attr-undis">
                <span class="c-fff fsize14">主讲: {{ course.teacherName }}&nbsp;&nbsp;&nbsp;</span>
            </section>
            <section class="c-attr-mt of">
                <span class="ml10 vam">
                    <em class="icon18 scIcon"/>
                    <a class="c-fff vam" title="收藏" href="#" >收藏</a>
                </span>
            </section>
            <section class="c-attr-mt">
                <a href="#" title="立即观看" class="comm-btn c-btn-3">立即观看</a>
            </section>
        </section>
    </aside>
    <aside class="thr-attr-box">
        <ol class="thr-attr-ol clearfix">
            <li>
                <p>&nbsp;</p>
                <aside>
                    <span class="c-fff f-fM">购买数</span>
                    <br>
                    <h6 class="c-fff f-fM mt10">{{ course.buyCount }}</h6>
                </aside>
            </li>
            <li>
                <p>&nbsp;</p>
                <aside>
                    <span class="c-fff f-fM">课时数</span>
                    <br>
                    <h6 class="c-fff f-fM mt10">{{ course.lessonNum }}</h6>
                </aside>
            </li>
            <li>
                <p>&nbsp;</p>
                <aside>
                    <span class="c-fff f-fM">浏览数</span>
                    <br>
                    <h6 class="c-fff f-fM mt10">{{ course.viewCount }}</h6>
                </aside>
            </li>
        </ol>
    </aside>
    <div class="clear"/>
</div>
<!-- /课程基本信息 结束 -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# 4、课程详情介绍

<!-- 课程详情介绍 开始 -->
<div>
    <h6 class="c-i-content c-infor-title">
        <span>课程介绍</span>
    </h6>
    <div class="course-txt-body-wrap">
        <section class="course-txt-body">
            <!-- 将内容中的html翻译过来 -->
            <p v-html="course.description">{{ course.description }}</p>
        </section>
    </div>
</div>
<!-- /课程详情介绍 结束 -->
1
2
3
4
5
6
7
8
9
10
11
12
13

# 5、课程大纲

<!-- 课程大纲 开始-->
<div class="mt50">
    <h6 class="c-g-content c-infor-title">
        <span>课程大纲</span>
    </h6>
    <section class="mt20">
        <div class="lh-menu-wrap">
            <menu id="lh-menu" class="lh-menu mt10 mr10">
                <ul>
                    <!-- 课程章节目录 -->
                    <li v-for="chapter in chapterList" :key="chapter.id" class="lh-menu-stair">
                        <a :title="chapter.title" href="javascript: void(0)" class="current-1">
                            <em class="lh-menu-i-1 icon18 mr10"/>{{ chapter.title }}
                        </a>
                        <ol class="lh-menu-ol" style="display: block;">
                            <li v-for="video in chapter.children" :key="video.id" class="lh-menu-second ml30">
                                <a href="#" title>
                                    <span v-if="video.free === true" class="fr">
                                        <i class="free-icon vam mr10">免费试听</i>
                                    </span>
                                    <em class="lh-menu-i-2 icon16 mr5">&nbsp;</em>{{ video.title }}
                                </a>
                            </li>
                        </ol>
                    </li>
                </ul>
            </menu>
        </div>
    </section>
    <!-- /课程大纲 结束 -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 6、主讲讲师

<!-- 主讲讲师 开始-->
<div>
    <section class="c-infor-tabTitle c-tab-title">
        <a title href="javascript:void(0)">主讲讲师</a>
    </section>
    <section class="stud-act-list">
        <ul style="height: auto;">
            <li>
                <div class="u-face">
                    <a :href="'/teacher/'+course.teacherId" target="_blank">
                        <img :src="course.avatar" width="50" height="50" alt>
                    </a>
                </div>
                <section class="hLh30 txtOf">
                    <a :href="'/teacher/'+course.teacherId" class="c-333 fsize16 fl" target="_blank">{{ course.teacherName }}</a>
                </section>
                <section class="hLh20 txtOf">
                    <span class="c-999">{{ course.intro }}</span>
                </section>
            </li>
        </ul>
    </section>
</div>
<!-- /主讲讲师 结束 -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
编辑 (opens new window)
上次更新: 2024/06/15, 15:12:25
课程列表页面
整合阿里云视频播放器

← 课程列表页面 整合阿里云视频播放器→

最近更新
01
04.Spring Boot 韩顺平
10-12
02
day14
08-29
03
day09
08-29
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式