尚硅谷谷粒学院学习笔记10--前台讲师列表详情,课程列表详情,阿里云视频播放器

讲师列表页面

EduTeacherService

  Map<String, Object> getTeacherFrontList(Page<EduTeacher> teacherPage);

EduTeacherServiceImpl

@Override
    public Map<String, Object> getTeacherFrontList(Page<EduTeacher> teacherPage) {
    
    
        QueryWrapper<EduTeacher> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        //把分页数据封装到pageTeacher对象
        baseMapper.selectPage(teacherPage,queryWrapper);
        List<EduTeacher> records = teacherPage.getRecords();
        long current = teacherPage.getCurrent();
        long pages = teacherPage.getPages();
        long size = teacherPage.getSize();
        long total = teacherPage.getTotal();
        boolean hasNext = teacherPage.hasNext();
        boolean hasPrevious = teacherPage.hasPrevious();
        //把分页数据获取出来,放到map集合
        Map<String, Object> map = new HashMap<>();
        map.put("items", records);
        map.put("current", current);
        map.put("pages", pages);
        map.put("size", size);
        map.put("total", total);
        map.put("hasNext", hasNext);
        map.put("hasPrevious", hasPrevious);



        return map;
    }

controller

//1.分页查询
    @GetMapping("getTeacherFrontList/{page}/{limit}")
    public ResultVo getTeacherFrontList(@PathVariable long page,@PathVariable long limit){
    
    
        Page<EduTeacher> teacherPage = new Page<>(page, limit);
        Map<String,Object> map=teacherService.getTeacherFrontList(teacherPage);
        //返回分页所有数据
        return ResultVo.ok().data(map);
    }

前端列表js

创建api

创建文件夹api,api下创建teacher.js,用于封装讲师模块的请求

//分页讲师查询的方法
  getTeacherList(page,limit) {
    
    
    return request({
    
    
      url: `/eduservice/teacherfront/getTeacherFrontList/${
    
    page}/${
    
    limit}`,
      method: 'get'
    })
  },

讲师列表组件中调用api

import teacherApi from "@/api/teacher";

export default {
    
    
  //异步调用,调用一次
  //params: 相当于之前 this.$route.params.id  等价  params.id
  asyncData({
    
     params, error }) {
    
    
    return teacherApi.getTeacherList(1, 8).then((response) => {
    
    
      //this.data = response.data.data
      return {
    
     data: response.data.data };
    });
  },

无数据提示

添加:v-if=“data.total==0”

<!-- /无数据提示 开始-->
          <section class="no-data-wrap" v-if="data.total == 0">
            <em class="icon30 no-data-ico">&nbsp;</em>
            <span class="c-666 fsize14 ml10 vam"
              >没有相关数据,小编正在努力整理中...</span>
          </section>

列表

 <article v-if="data.total > 0" class="i-teacher-list">
            <ul class="of">
              <li v-for="teacher in data.items" :key="teacher.id">
                <section class="i-teach-wrap">
                  <div class="i-teach-pic">
                    <a
                      :href="'/teacher/' + teacher.id"
                      :title="teacher.name"
                      target="_blank"
                    >
                      <img :src="teacher.avatar" :alt="teacher.name" />
                    </a>
                  </div>
                  <div class="mt10 hLh30 txtOf tac">
                    <a
                      :href="'/teacher/' + teacher.id"
                      :title="teacher.name"
                      target="_blank"
                      class="fsize18 c-666"
                      >{
    
    {
    
     teacher.name }}</a
                    >
                  </div>
                  <div class="hLh30 txtOf tac">
                    <span class="fsize14 c-999">{
    
    {
    
     teacher.intro }}</span>
                  </div>
                  <div class="mt15 i-q-txt">
                    <p class="c-999 f-fA">{
    
    {
    
     teacher.career }}</p>
                  </div>
                </section>
              </li>
            </ul>
            <div class="clear"></div>
          </article>

分页方法

//分页切换的方法
    //参数是页码数
    gotoPage(page) {
    
    
      teacherApi.getTeacherList(page, 8).then((response) => {
    
    
        this.data = response.data.data;
      });
    },

分页页面渲染

<div class="paging">
            <!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
            <a
              :class="{ undisable: !data.hasPrevious }"
              href="#"
              title="首页"
              @click.prevent="gotoPage(1)"
              >首页</a
            >

            <a
              :class="{ undisable: !data.hasPrevious }"
              href="#"
              title="前一页"
              @click.prevent="gotoPage(data.current - 1)"
              >&lt;</a
            >

            <a
              v-for="page in data.pages"
              :key="page"
              :class="{
    
    
                current: data.current == page,
                undisable: data.current == page,
              }"
              :title="'第' + page + '页'"
              href="#"
              @click.prevent="gotoPage(page)"
              >{
    
    {
    
     page }}</a
            >

            <a
              :class="{ undisable: !data.hasNext }"
              href="#"
              title="后一页"
              @click.prevent="gotoPage(data.current + 1)"
              >&gt;</a
            >

            <a
              :class="{ undisable: !data.hasNext }"
              href="#"
              title="末页"
              @click.prevent="gotoPage(data.pages)"
              >末页</a
            >

            <div class="clear" />
          </div>

讲师详情

根据讲师id查询讲师所讲课程列表

//2.讲师详情的功能
    @GetMapping("getTeacherFrontInfo/{teacherId}")
    public ResultVo getTeacherFrontInfo(@PathVariable String teacherId){
    
    
        //1.根据讲师id查询讲师基本信息
        EduTeacher eduTeacher = teacherService.getById(teacherId);
        //2.根据讲师id查询所有课程
        QueryWrapper<EduCourse> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teacher_id",teacherId);
        List<EduCourse> courseList = eduCourseService.list(queryWrapper);

        return ResultVo.ok().data("teacher",eduTeacher).data("courseList",courseList);
    }
//讲师详情的方法
  getTeacherInfo(id) {
    
    
    return request({
    
    
      url: `/eduservice/teacherfront/getTeacherFrontInfo/${
    
    id}`,
      method: 'get'
    })
  }
import teacherApi from "@/api/teacher";
export default {
    
    
  //params.id获取路径id值
  asyncData({
    
     params, error }) {
    
    
    return teacherApi.getTeacherInfo(params.id).then((response) => {
    
    
      return {
    
    
        teacher: response.data.data.teacher,
        courseList: response.data.data.courseList,
      };
    });
  },
};

讲师详情显示

<section class="fl t-infor-box c-desc-content">
          <div class="mt20 ml20">
            <section class="t-infor-pic">
              <img :src="teacher.avatar" />
            </section>
            <h3 class="hLh30">
              <span class="fsize24 c-333"
                >{
    
    {
    
     teacher.name }}&nbsp;
                {
    
    {
    
     teacher.level === 1 ? "高级讲师" : "首席讲师" }}
              </span>
            </h3>
            <section class="mt10">
              <span class="t-tag-bg">{
    
    {
    
     teacher.intro }}</span>
            </section>
            <section class="t-infor-txt">
              <p class="mt20">{
    
    {
    
     teacher.career }}</p>
            </section>
            <div class="clear"></div>
          </div>
        </section>
            

无数据提示

 <!-- /无数据提示 开始-->
          <section class="no-data-wrap" v-if="courseList.length == 0">
            <em class="icon30 no-data-ico">&nbsp;</em>
            <span class="c-666 fsize14 ml10 vam"
              >没有相关数据,小编正在努力整理中...</span
            >
          </section>

当前讲师课程列表

 <article class="comm-course-list">
            <ul class="of">
              <li v-for="course in courseList" :key="course.id">
                <div class="cc-l-wrap">
                  <section class="course-img">
                    <img :src="course.cover" class="img-responsive" />
                    <div class="cc-mask">
                      <a
                        href="#"
                        title="开始学习"
                        target="_blank"
                        class="comm-btn c-btn-1"
                        >开始学习</a
                      >
                    </div>
                  </section>
                  <h3 class="hLh30 txtOf mt10">
                    <a
                      href="#"
                      :title="course.title"
                      target="_blank"
                      class="course-title fsize18 c-333"
                      >{
    
    {
    
     course.title }}</a
                    >
                  </h3>
                </div>
              </li>
            </ul>
            <div class="clear"></div>
          </article>

课程后端接口

@Data
public class CourseFrontVo {
    
    

    @ApiModelProperty(value = "课程名称")
    private String title;

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

    @ApiModelProperty(value = "一级类别id")
    private String subjectParentId;

    @ApiModelProperty(value = "二级类别id")
    private String subjectId;

    @ApiModelProperty(value = "销量排序")
    private String buyCountSort;

    @ApiModelProperty(value = "最新时间排序")
    private String gmtCreateSort;

    @ApiModelProperty(value = "价格排序")
    private String priceSort;
}
//1 条件查询带分页查询课程
    @PostMapping("getFrontCourseList/{page}/{limit}")
    public ResultVo getFrontCourseList(@PathVariable long page, @PathVariable long limit,
                                       @RequestBody(required = false) CourseFrontVo courseFrontVo) {
    
    
        Page<EduCourse> pageCourse = new Page<>(page,limit);
        Map<String,Object> map = courseService.getCourseFrontList(pageCourse,courseFrontVo);
        //返回分页所有数据
        return ResultVo.ok().data(map);
    }
 //1 条件查询带分页查询课程
    @Override
    public Map<String, Object> getCourseFrontList(Page<EduCourse> pageParam, CourseFrontVo courseFrontVo) {
    
    
        //2 根据讲师id查询所讲课程
        QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();
        //判断条件值是否为空,不为空拼接
        if(!StringUtils.isEmpty(courseFrontVo.getSubjectParentId())) {
    
     //一级分类
            wrapper.eq("subject_parent_id",courseFrontVo.getSubjectParentId());
        }
        if(!StringUtils.isEmpty(courseFrontVo.getSubjectId())) {
    
     //二级分类
            wrapper.eq("subject_id",courseFrontVo.getSubjectId());
        }
        if(!StringUtils.isEmpty(courseFrontVo.getBuyCountSort())) {
    
     //关注度
            wrapper.orderByDesc("buy_count");
        }
        if (!StringUtils.isEmpty(courseFrontVo.getGmtCreateSort())) {
    
     //最新
            wrapper.orderByDesc("gmt_create");
        }

        if (!StringUtils.isEmpty(courseFrontVo.getPriceSort())) {
    
    //价格
            wrapper.orderByDesc("price");
        }

        baseMapper.selectPage(pageParam,wrapper);

        List<EduCourse> records = pageParam.getRecords();
        long current = pageParam.getCurrent();
        long pages = pageParam.getPages();
        long size = pageParam.getSize();
        long total = pageParam.getTotal();
        boolean hasNext = pageParam.hasNext();//下一页
        boolean hasPrevious = pageParam.hasPrevious();//上一页

        //把分页数据获取出来,放到map集合
        Map<String, Object> map = new HashMap<>();
        map.put("items", records);
        map.put("current", current);
        map.put("pages", pages);
        map.put("size", size);
        map.put("total", total);
        map.put("hasNext", hasNext);
        map.put("hasPrevious", hasPrevious);

        //map返回
        return map;
    }

定义api

//条件分页课程查询的方法
  getCourseList(page,limit,searchObj) {
    
    
    return request({
    
    
      url: `/eduservice/coursefront/getFrontCourseList/${
    
    page}/${
    
    limit}`,
      method: 'post',
      data: searchObj
    })
  },
  //查询所有分类的方法
  getAllSubject() {
    
    
    return request({
    
    
      url: '/eduservice/subject/getAllSubject',
      method: 'get'
    })
  },
<script>
import courseApi from '@/api/course'

export default {
    
    
  data() {
    
    
    return {
    
    
      page:1, //当前页
      data:{
    
    },  //课程列表
      subjectNestedList: [], // 一级分类列表
      subSubjectList: [], // 二级分类列表

      searchObj: {
    
    }, // 查询表单对象

      oneIndex:-1,
      twoIndex:-1,
      buyCountSort:"",
      gmtCreateSort:"",
      priceSort:""
    }
  },
  created() {
    
    
    //课程第一次查询
    this.initCourseFirst()
    //一级分类显示
    this.initSubject()
  },
  methods:{
    
    
    //1 查询第一页数据
    initCourseFirst() {
    
    
      courseApi.getCourseList(1,8,this.searchObj).then(response => {
    
    
        this.data = response.data.data
      })
    },

    //2 查询所有一级分类
    initSubject() {
    
    
      courseApi.getAllSubject()
        .then(response => {
    
    
          this.subjectNestedList = response.data.data.list
        })
    },

    //3 分页切换的方法
    gotoPage(page) {
    
    
      courseApi.getCourseList(page,8,this.searchObj).then(response => {
    
    
        this.data = response.data.data
      })
    },

    //4 点击某个一级分类,查询对应二级分类
    searchOne(subjectParentId,index) {
    
    
      //把传递index值赋值给oneIndex,为了active样式生效
      this.oneIndex = index

      this.twoIndex = -1
      this.searchObj.subjectId = ""
      this.subSubjectList = []

      //把一级分类点击id值,赋值给searchObj
      this.searchObj.subjectParentId = subjectParentId
      //点击某个一级分类进行条件查询
      this.gotoPage(1)

      //拿着点击一级分类id 和 所有一级分类id进行比较,
      //如果id相同,从一级分类里面获取对应的二级分类
      for(let i=0;i<this.subjectNestedList.length;i++) {
    
    
        //获取每个一级分类
        var oneSubject = this.subjectNestedList[i]
        //比较id是否相同
        if(subjectParentId == oneSubject.id) {
    
    
          //从一级分类里面获取对应的二级分类
          this.subSubjectList = oneSubject.children
        }
      }
    },

    //5 点击某个二级分类实现查询
    searchTwo(subjectId,index) {
    
    
      //把index赋值,为了样式生效
      this.twoIndex = index
      //把二级分类点击id值,赋值给searchObj
      this.searchObj.subjectId = subjectId
      //点击某个二级分类进行条件查询
      this.gotoPage(1)
    },

    //6 根据销量排序
    searchBuyCount() {
    
    
      //设置对应变量值,为了样式生效
      this.buyCountSort = "1"
      this.gmtCreateSort = ""
      this.priceSort = ""

      //把值赋值到searchObj
      this.searchObj.buyCountSort = this.buyCountSort
      this.searchObj.gmtCreateSort = this.gmtCreateSort;
      this.searchObj.priceSort = this.priceSort;

      //调用方法查询
      this.gotoPage(1)
    },

    //7 最新排序
    searchGmtCreate() {
    
    
      //设置对应变量值,为了样式生效
      this.buyCountSort = ""
      this.gmtCreateSort = "1"
      this.priceSort = ""

      //把值赋值到searchObj
      this.searchObj.buyCountSort = this.buyCountSort
      this.searchObj.gmtCreateSort = this.gmtCreateSort;
      this.searchObj.priceSort = this.priceSort;

      //调用方法查询
      this.gotoPage(1)
    },

    //8 价格排序
    searchPrice() {
    
    
      //设置对应变量值,为了样式生效
      this.buyCountSort = ""
      this.gmtCreateSort = ""
      this.priceSort = "1"

      //把值赋值到searchObj
      this.searchObj.buyCountSort = this.buyCountSort
      this.searchObj.gmtCreateSort = this.gmtCreateSort;
      this.searchObj.priceSort = this.priceSort;

      //调用方法查询
      this.gotoPage(1)
    }

  }
};
</script>

课程类别显示

<section class="c-sort-box">
        <section class="c-s-dl">
          <dl>
            <dt>
              <span class="c-999 fsize14">课程类别</span>
            </dt>
            <dd class="c-s-dl-li">
              <ul class="clearfix">
                <li>
                  <a title="全部" href="#">全部</a>
                </li>
                <li v-for="(item,index) in subjectNestedList" :key="index" :class="{active:oneIndex==index}">
                  <a :title="item.title" href="#" @click="searchOne(item.id,index)">{
    
    {
    
    item.title}}</a>
                </li>

              </ul>
            </dd>
          </dl>
          <dl>
            <dt>
              <span class="c-999 fsize14"></span>
            </dt>
            <dd class="c-s-dl-li">
              <ul class="clearfix">
                <li v-for="(item,index) in subSubjectList" :key="index" :class="{active:twoIndex==index}">
                  <a :title="item.title" href="#" @click="searchTwo(item.id,index)">{
    
    {
    
    item.title}}</a>
                </li>

              </ul>
            </dd>
          </dl>
          <div class="clear"></div>
        </section>

排序方式显示

<section class="fl">
            <ol class="js-tap clearfix">
              <li :class="{'current bg-orange':buyCountSort!=''}">
                <a title="销量" href="javascript:void(0);" @click="searchBuyCount()">销量
                  <span :class="{hide:buyCountSort==''}"></span>
                </a>
              </li>
              <li :class="{'current bg-orange':gmtCreateSort!=''}">
                <a title="最新" href="javascript:void(0);" @click="searchGmtCreate()">最新
                  <span :class="{hide:gmtCreateSort==''}"></span>
                </a>
              </li>
              <li :class="{'current bg-orange':priceSort!=''}">
                <a title="价格" href="javascript:void(0);" @click="searchPrice()">价格&nbsp;
                  <span :class="{hide:priceSort==''}"></span>
                </a>
              </li>
            </ol>
</section>

无数据提示

<!-- /无数据提示 开始-->
          <section class="no-data-wrap" v-if="data.total==0">
            <em class="icon30 no-data-ico">&nbsp;</em>
            <span class="c-666 fsize14 ml10 vam">没有相关数据,小编正在努力整理中...</span>
          </section>
          <!-- /无数据提示 结束-->

列表

<article  v-if="data.total>0" class="comm-course-list">
            <ul class="of" id="bna">
              <li v-for="item in data.items" :key="item.id">
                <div class="cc-l-wrap">
                  <section class="course-img">
                    <img :src="item.cover" class="img-responsive" :alt="item.title">
                    <div class="cc-mask">
                      <a :href="'/course/'+item.id" title="开始学习" class="comm-btn c-btn-1">开始学习</a>
                    </div>
                  </section>
                  <h3 class="hLh30 txtOf mt10">
                    <a :href="'/course/'+item.id" :title="item.title" class="course-title fsize18 c-333">{
    
    {
    
    item.title}}</a>
                  </h3>
                  <section class="mt10 hLh20 of">
                    <span v-if="Number(item.price) === 0" class="fr jgTag bg-green">
                      <i class="c-fff fsize12 f-fA">免费</i>
                    </span>
                    <span class="fl jgAttr c-ccc f-fA">
                      <i class="c-999 f-fA">9634人学习</i>
                      |
                      <i class="c-999 f-fA">9634评论</i>
                    </span>
                  </section>
                </div>
              </li>

            </ul>
            <div class="clear"></div>
          </article>

分页页面渲染

<div class="paging">
            <!-- undisable这个class是否存在,取决于数据属性hasPrevious -->
            <a
              :class="{undisable: !data.hasPrevious}"
              href="#"
              title="首页"
              @click.prevent="gotoPage(1)"></a>
            <a
              :class="{undisable: !data.hasPrevious}"
              href="#"
              title="前一页"
              @click.prevent="gotoPage(data.current-1)">&lt;</a>
            <a
              v-for="page in data.pages"
              :key="page"
              :class="{current: data.current == page, undisable: data.current == page}"
              :title="'第'+page+'页'"
              href="#"
              @click.prevent="gotoPage(page)">{
    
    {
    
     page }}</a>
            <a
              :class="{undisable: !data.hasNext}"
              href="#"
              title="后一页"
              @click.prevent="gotoPage(data.current+1)">&gt;</a>
            <a
              :class="{undisable: !data.hasNext}"
              href="#"
              title="末页"
              @click.prevent="gotoPage(data.pages)"></a>
            <div class="clear"/>
          </div>

课程详情

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

vo对象的定义

package com.atguigu.eduservice.entity.frontvo;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class CourseWebVo {
    
    

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

课程和讲师信息的获取

<select id="getBaseCourseInfo" resultType="com.atguigu.eduservice.entity.frontvo.CourseWebVo">
        SELECT ec.id,ec.title,ec.price,ec.lesson_num AS lessonNum,ec.cover,
               ec.buy_count AS buyCount,ec.view_count AS viewCount,
               ecd.description,
               et.id AS teacherId,et.name AS teacherName,et.intro,et.avatar,
               es1.id AS subjectLevelOneId,es1.title AS subjectLevelOne,
               es2.id AS subjectLevelTwoId,es2.title AS subjectLevelTwo
        FROM edu_course ec LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
                           LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
                           LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
                           LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
        WHERE ec.id=#{courseId}
    </select>

api/course.js

 //课程详情的方法
  getCourseInfo(id) {
    
    
    return request({
    
    
      url: '/eduservice/coursefront/getFrontCourseInfo/'+id,
      method: 'get'
    })
  }
<script>
import courseApi from '@/api/course'
export default {
    
    
  asyncData({
    
     params, error }) {
    
    
    return courseApi.getCourseInfo(params.id)
      .then(response => {
    
    
        return {
    
    
          courseWebVo: response.data.data.courseWebVo,
          chapterVideoList: response.data.data.chapterVideoList
        }
      })
  }
};
</script>

课程所属分类

<section class="path-wrap txtOf hLh30">
        <a href="#" title class="c-999 fsize14">首页</a>
        \
        <a href="#" title class="c-999 fsize14">{
    
    {
    
    courseWebVo.subjectLevelOne}}</a>
        \
        <span class="c-333 fsize14">{
    
    {
    
    courseWebVo.subjectLevelTwo}}</span>
      </section>

课程基本信息

 <div>
        <article class="c-v-pic-wrap" style="height: 357px;">
          <section class="p-h-video-box" id="videoPlay">
            <img :src="courseWebVo.cover" :alt="courseWebVo.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">{
    
    {
    
    courseWebVo.title}}</span>
            </h2>
            <section class="c-attr-jg">
              <span class="c-fff">价格:</span>
              <b class="c-yellow" style="font-size:24px;">{
    
    {
    
    courseWebVo.price}}</b>
            </section>
            <section class="c-attr-mt c-attr-undis">
              <span class="c-fff fsize14">主讲: {
    
    {
    
    courseWebVo.teacherName}}&nbsp;&nbsp;&nbsp;</span>
            </section>
            <section class="c-attr-mt of">
              <span class="ml10 vam">
                <em class="icon18 scIcon"></em>
                <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">{
    
    {
    
    courseWebVo.buyCount}}</h6>
              </aside>
            </li>
            <li>
              <p>&nbsp;</p>
              <aside>
                <span class="c-fff f-fM">课时数</span>
                <br>
                <h6 class="c-fff f-fM mt10">20</h6>
              </aside>
            </li>
            <li>
              <p>&nbsp;</p>
              <aside>
                <span class="c-fff f-fM">浏览数</span>
                <br>
                <h6 class="c-fff f-fM mt10">{
    
    {
    
     courseWebVo.viewCount }}</h6>
              </aside>
            </li>
          </ol>
        </aside>
        <div class="clear"></div>
      </div>

课程详情介绍

			<div>
                  <h6 class="c-i-content c-infor-title">
                    <span>课程介绍</span>
                  </h6>
                  <div class="course-txt-body-wrap">
                    <section class="course-txt-body">
                      <p v-html="courseWebVo.description">{
    
    {
    
    courseWebVo.description}}</p>
                    </section>
                  </div>
                </div>

课程大纲

<!-- /课程介绍 -->
                <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 class="lh-menu-stair" v-for="chapter in chapterVideoList" :key="chapter.id">
                            <a href="javascript: void(0)" :title="chapter.title" class="current-1">
                              <em class="lh-menu-i-1 icon18 mr10"></em>{
    
    {
    
    chapter.title}}
                            </a>

                            <ol class="lh-menu-ol" style="display: block;">
                              <li class="lh-menu-second ml30" v-for="video in chapter.children" :key="video.id">
                                <a :href="'/player/'+video.videoSourceId" target="_blank">
                                  <span 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>
                </div>
                <!-- /课程大纲 -->

主讲讲师

<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="#">
                        <img :src="courseWebVo.avatar" width="50" height="50" alt>
                      </a>
                    </div>
                    <section class="hLh30 txtOf">
                      <a class="c-333 fsize16 fl" href="#">{
    
    {
    
    courseWebVo.teacherName}}</a>
                    </section>
                    <section class="hLh20 txtOf">
                      <span class="c-999">{
    
    {
    
    courseWebVo.intro}}</span>
                    </section>
                  </li>
                </ul>
              </section>
            </div>
          </div>
        </aside>
        <div class="clear"></div>
      </div>

集成视频播放器

引入脚本文件和css文件

<link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css" />
2
<script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"></script>

初始化视频播放器

<body>
    <div  class="prism-player" id="J_prismPlayer"></div>
    <script>
        var player = new Aliplayer({
    
    
            id: 'J_prismPlayer',
            width: '100%',
            autoplay: false,
            cover: 'http://liveroom-img.oss-cn-qingdao.aliyuncs.com/logo.png',  
            //播放配置
        },function(player){
    
    
            console.log('播放器创建好了。')
        });

    </script>
</body>

播放地址播放
在Aliplayer的配置参数中添加如下属性

//播放方式一:支持播放地址播放,此播放优先级最高,此种方式不能播放加密视频
source : '你的视频播放地址',

启动浏览器运行,测试视频的播放

播放凭证播放

encryptType:'1',//如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
vid : '视频id',
playauth : '视频授权码',

注意:播放凭证有过期时间,默认值:100秒 。取值范围:100~3000。
设置播放凭证的有效期
在获取播放凭证的测试用例中添加如下代码

request.setAuthInfoTimeout(200L);

后端获取播放凭证

service-vod微服务中创建 VideoController.java
controller中创建 getVideoPlayAuth 接口方法

//根据视频id获取视频凭证
    @GetMapping("getPlayAuth/{id}")
    public ResultVo getPlayAuth(@PathVariable String id) {
    
    
        try {
    
    
            //创建初始化对象
            DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);
            //创建获取凭证request和response对象
            GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
            //向request设置视频id
            request.setVideoId(id);
            //调用方法得到凭证
            GetVideoPlayAuthResponse response = client.getAcsResponse(request);
            String playAuth = response.getPlayAuth();
            return ResultVo.ok().data("playAuth",playAuth);
        }catch(Exception e) {
    
    
            throw new GuliException(20001,"获取凭证失败");
        }
    }

修改service_edu下的VideoVo实体类

package com.atguigu.eduservice.entity.chapter;


import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@ApiModel(value = "小结信息")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VideoVo {
    
    
    private String id;
    private String title;

    private String videoSourceId;
}

前端播放器整合

修改超链接地址

<a :href="'/player/'+video.videoSourceId" target="_blank">


api

创建api模块 api/vod.js,从后端获取播放凭证

import request from '@/utils/request'
export default {
    
    
  getPlayAuth(vid) {
    
    
    return request({
    
    
      url: `/eduvod/video/getPlayAuth/${
    
    vid}`,
      method: 'get'
    })
  }

}

播放组件相关文档
集成文档:https://help.aliyun.com/document_detail/51991.html?spm=a2c4g.11186623.2.39.478e192b8VSdEn
在线配置:https://player.alicdn.com/aliplayer/setting/setting.html
功能展示:https://player.alicdn.com/aliplayer/presentation/index.html

layout布局

因为播放器的布局和其他页面的基本布局不一致,因此创建新的布局容器 layouts/video.vue

<template>
  <div class="guli-player">
    <div class="head">
      <a href="#" title="谷粒学院">
        <img class="logo" src="~/assets/img/logo.png" lt="谷粒学院">
    </a></div>
    <div class="body">
      <div class="content"><nuxt/></div>
    </div>
  </div>
</template>
<script>
export default {
    
    }
</script>

<style>
html,body{
    
    
  height:100%;
}
</style>

<style scoped>
.head {
    
    
  height: 50px;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

.head .logo{
    
    
  height: 50px;
  margin-left: 10px;
}

.body {
    
    
  position: absolute;
  top: 50px;
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
}
</style>

在pages下新建一个页面player,新建一个_vid.vue,使用动态路由

创建播放页面
创建 pages/player/_vid.vue

引入播放器js库和css样式

<template>
  <div>

    <!-- 阿里云视频播放器样式 -->
    <link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css" >
    <!-- 阿里云视频播放器脚本 -->
    <script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js" />

    <!-- 定义播放器dom -->
    <div id="J_prismPlayer" class="prism-player" />
  </div>
</template>

获取播放凭证

asyncData({
    
     params, error }) {
    
    
       return vod.getPlayAuth(params.vid)
        .then(response => {
    
    
            return {
    
     
                playAuth: response.data.data.playAuth,
                vid: params.vid
            }
        })
    },

创建播放器

  mounted() {
    
     //页面渲染之后  created
        new Aliplayer({
    
    
            id: 'J_prismPlayer',
            vid: this.vid, // 视频id
            playauth: this.playAuth, // 播放凭证
            encryptType: '1', // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
            width: '100%',
            height: '500px',
            // 以下可选设置
            cover: 'http://guli.shop/photo/banner/1525939573202.jpg', // 封面
            qualitySort: 'asc', // 清晰度排序

            mediaType: 'video', // 返回音频还是视频
            autoplay: false, // 自动播放
            isLive: false, // 直播
            rePlay: false, // 循环播放
            preload: true,
            controlBarVisibility: 'hover', // 控制条的显示方式:鼠标悬停
            useH5Prism: true, // 播放器类型:html5
        }, function(player) {
    
    
            console.log('播放器创建成功')
        })
    }

完整版

<template>
  <div>

    <!-- 阿里云视频播放器样式 -->
    <link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css" >
    <!-- 阿里云视频播放器脚本 -->
    <script charset="utf-8" type="text/javascript" src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js" />

    <!-- 定义播放器dom -->
    <div id="J_prismPlayer" class="prism-player" />
  </div>
</template>
<script>
import vod from '@/api/vod'

export default {
    
    
    layout: 'video',//应用video布局
    asyncData({
    
     params, error }) {
    
    
       return vod.getPlayAuth(params.vid)
        .then(response => {
    
    
            return {
    
     
                playAuth: response.data.data.playAuth,
                vid: params.vid
            }
        })
    },
    mounted() {
    
     //页面渲染之后  created
        new Aliplayer({
    
    
            id: 'J_prismPlayer',
            vid: this.vid, // 视频id
            playauth: this.playAuth, // 播放凭证
            encryptType: '1', // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
            width: '100%',
            height: '500px',
            // 以下可选设置
            cover: 'http://guli.shop/photo/banner/1525939573202.jpg', // 封面
            qualitySort: 'asc', // 清晰度排序

            mediaType: 'video', // 返回音频还是视频
            autoplay: false, // 自动播放
            isLive: false, // 直播
            rePlay: false, // 循环播放
            preload: true,
            controlBarVisibility: 'hover', // 控制条的显示方式:鼠标悬停
            useH5Prism: true, // 播放器类型:html5
        }, function(player) {
    
    
            console.log('播放器创建成功')
        })
    }

}
</script>

加入播放组件

例如加入弹幕,广告等等
功能展示:https://player.alicdn.com/aliplayer/presentation/index.html

猜你喜欢

转载自blog.csdn.net/qq_44866153/article/details/120954925