讲师列表页面
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"> </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)"
><</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)"
>></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 }}
{{ 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"> </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()">价格
<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"> </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)"><</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)">></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}} </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> </p>
<aside>
<span class="c-fff f-fM">购买数</span>
<br>
<h6 class="c-fff f-fM mt10">{{courseWebVo.buyCount}}</h6>
</aside>
</li>
<li>
<p> </p>
<aside>
<span class="c-fff f-fM">课时数</span>
<br>
<h6 class="c-fff f-fM mt10">20</h6>
</aside>
</li>
<li>
<p> </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"> </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