day14【首頁(yè)課程和名師功能】-02 首頁(yè)課程功能

01-課程頁(yè)面靜態(tài)效果整合

一、列表頁(yè)面

創(chuàng)建 pages/course/index.vue

二、詳情頁(yè)面

創(chuàng)建 pages/course/_id.vue



02-課程列表頁(yè)面

一、課程后端接口

1、課程列表

(1)課程列表vo類(條件查詢需要的對(duì)象)

@ApiModel(value = "課程查詢對(duì)象", description = "課程查詢對(duì)象封裝")

@Data

public class CourseFrontVo {

? ? @ApiModelProperty(value = "課程名稱")

? ? private String title;

? ? @ApiModelProperty(value = "講師id")

? ? private String teacherId;

? ? @ApiModelProperty(value = "一級(jí)類別id")

? ? private String subjectParentId;

? ? @ApiModelProperty(value = "二級(jí)類別id")

? ? private String subjectId;

? ? @ApiModelProperty(value = "銷量排序")

? ? private String buyCountSort;

? ? @ApiModelProperty(value = "最新時(shí)間排序")

? ? private String gmtCreateSort;

? ? @ApiModelProperty(value = "價(jià)格排序")

? ? private String priceSort;

}

(2)課程列表controller

@RestController

@CrossOrigin

@RequestMapping("/eduservice/coursefront")

public class CourseFrontController {

? ? @Autowired

? ? private EduCourseService courseService;

? ? //1 條件查詢帶分頁(yè)查詢課程

? ? @ApiOperation(value = "分頁(yè)課程列表")

? ? @PostMapping("pageCourseCondition/{current}/{limit}")

? ? public R pageCourseCondition(@PathVariable long limit,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @PathVariable long current,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @RequestBody(required = false) CourseFrontVo courseFrontVo){

? ? ? ? //@RequestBody(required = false)使用RequestBody必須是post提交,不添加required = false必須要有值,添加后表示可以沒(méi)有值

? ? ? ? Page<EduCourse> pageParam = new Page<EduCourse>(current,limit);

? ? ? ? Map<String, Object> map = courseService.pageListWeb(pageParam, courseFrontVo);

? ? ? ? return R.ok().data(map);

? ? }

}

//@RequestBody(required = false)使用RequestBody必須是post提交,不添加required = false必須要有值,添加后可以沒(méi)有值

(3)課程列表service

//1 條件查詢帶分頁(yè)查詢課程

? ? @Override

? ? public Map<String, Object> pageListWeb(Page<EduCourse> pageParam, CourseFrontVo courseFrontVo) {

? ? ? ? QueryWrapper<EduCourse> queryWrapper = new QueryWrapper<>();

? ? ? ? //判斷條件值是否為空,不為空拼接

? ? ? ? if (!StringUtils.isEmpty(courseFrontVo.getSubjectParentId())){//一級(jí)分類

? ? ? ? ? ? queryWrapper.eq("subject_parent_id",courseFrontVo.getSubjectParentId());

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(courseFrontVo.getSubjectId())){//二級(jí)分類

? ? ? ? ? ? queryWrapper.eq("subject_id",courseFrontVo.getSubjectId());

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(courseFrontVo.getBuyCountSort())){//銷售數(shù)量

? ? ? ? ? ? queryWrapper.orderByDesc("buy_count",courseFrontVo.getBuyCountSort());

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(courseFrontVo.getGmtCreateSort())){//創(chuàng)建時(shí)間

? ? ? ? ? ? queryWrapper.orderByDesc("gmt_create",courseFrontVo.getGmtCreateSort());

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(courseFrontVo.getPriceSort())){//價(jià)格

? ? ? ? ? ? queryWrapper.orderByDesc("price",courseFrontVo.getPriceSort());

? ? ? ? }

? ? ? ? baseMapper.selectPage(pageParam, queryWrapper);


? ? ? ? List<EduCourse> records = pageParam.getRecords();

? ? ? ? long pages = pageParam.getPages();

? ? ? ? long current = pageParam.getCurrent();

? ? ? ? long total = pageParam.getTotal();

? ? ? ? long size = pageParam.getSize();

? ? ? ? boolean hasNext = pageParam.hasNext(); //下一頁(yè)

? ? ? ? boolean hasPrevious = pageParam.hasPrevious(); //上一頁(yè)


? ? ? ? Map<String,Object> map = new HashMap<String,Object>();

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

? ? }

二、課程列表前端

1、定義api

api/course.js

import?request?from?'@/utils/request'

export?default?{

??//1?條件查詢帶分頁(yè)查詢課程

??getCourseList(current,limit,searchObj)?{

????return?request({

??????url:?`/eduservice/coursefront/pageCourseCondition/${current}/${limit}`,

??????method:?'post',

??????data:searchObj

????})

??},

??//查詢所有分類的方法

??getAllSubject(){

????return?request({

????????url:?`/eduservice/edu-subject/getAllSubject`,

????????method:?'get'

??????})

??}

}

2、頁(yè)面調(diào)用接口

pages/course/index.vue

<script>

import?courseApi?from?'@/api/course'

export?default?{

??data(){

????return{

??????page:1,

??????data:{},

??????subjectNestedList:?[],?//?一級(jí)分類列表

??????subSubjectList:?[],?//?二級(jí)分類列表

??????searchObj:?{},?//?查詢表單對(duì)象

??????oneIndex:-1,

??????twoIndex:-1,

??????buyCountSort:"",

??????gmtCreateSort:"",

??????priceSort:""

????}

??},

??created(){

????//獲取課程列表

????this.initCourseFirst()

????//獲取分類

????this.initSubject()

??},

??methods:{

????//1?查詢第一頁(yè)數(shù)據(jù)

????initCourseFirst(){

??????courseApi.getCourseList(1,8,this.searchObj).then(response=>{

????????this.data?=?response.data.data

??????})

????},

????//2?查詢所有一級(jí)分類

????initSubject(){

??????courseApi.getAllSubject().then(response=>{

????????this.subjectNestedList?=?response.data.data.list

??????})

????},

????//分頁(yè)切換方法

????gotoPage(page){

???????courseApi.getCourseList(page,8,this.searchObj).then(response=>{

????????this.data?=?response.data.data

??????})

????},


????//4?點(diǎn)擊某個(gè)一級(jí)分類,查詢對(duì)應(yīng)的二級(jí)分類

????searchOne(subjectParentId,index){

??????//把傳遞index值賦值給oneIndex,為了active樣式生效

??????this.oneIndex?=?index


??????//查詢一級(jí)分類,二級(jí)分類不需要值

??????this.twoIndex?=?-1

??????this.searchObj.subjectId?=?"";

??????this.subSubjectList?=?[];


??????//把一級(jí)分類點(diǎn)擊id值,賦值給searchObj

??????this.searchObj.subjectParentId?=?subjectParentId

??????//點(diǎn)擊某個(gè)一級(jí)分類進(jìn)行條件查詢

??????this.gotoPage(1)?//或者gotoPage(this.page)??this.page的默認(rèn)值為1


??????//拿著點(diǎn)擊一級(jí)分類id和所有一級(jí)分類id進(jìn)行比較,

??????//如果id相同,從一級(jí)分類里面獲取對(duì)應(yīng)的二級(jí)分類

??????for(let?i?=0;i<this.subjectNestedList.length;i++){

??????????//獲取每個(gè)一級(jí)分類

??????????var?oneSubject?=?this.subjectNestedList[i]

??????????//如果id值相同

??????????if(subjectParentId?==?oneSubject.id){

??????????????this.subSubjectList?=?oneSubject.children

??????????}

??????}

????},

??}

};

</script>

完善當(dāng)點(diǎn)擊一級(jí)分類時(shí),頁(yè)面中顯示的是該一級(jí)分類下的所有課程:

完善點(diǎn)擊添一級(jí)分類顯示樣式:

<style?scoped>

??.active?{

????background:?#bdbdbd;

??}

??.hide?{

????display:?none;

??}

??.show?{

????display:?block;

??}

</style>

如果oneIndex==index則添加樣式:

結(jié)果:

完善點(diǎn)擊某個(gè)二級(jí)分類實(shí)現(xiàn)查詢

結(jié)果:

完善排序方式顯示

<section?class="fl">

????????????<ol?class="js-tap?clearfix">

??????????????<li?:class="{'current?bg-orange':buyCountSort!=''}">

??????????????<!--?: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="價(jià)格"?href="javascript:void(0);"?@click="searchPrice()">價(jià)格&nbsp;

??????????????????<span?:class="{hide:priceSort==''}">↓</span>

????????????????</a>

??????????????</li>

????????????</ol>

??????????</section>

????//6?根據(jù)銷量進(jìn)行排序

????searchBuyCount(){

??????//設(shè)置對(duì)應(yīng)變量值,為了樣式生效

??????this.buyCountSort?=?"1"

??????this.gmtCreateSort?=?""

??????this.priceSort?=?""

??????//把值賦值到search0bj

??????this.searchObj.buyCountSort?=?this.buyCountSort

??????this.searchObj.gmtCreateSort?=?this.gmtCreateSort

??????this.searchObj.priceSort?=?this.priceSort


??????//調(diào)用方法查詢

??????this.gotoPage(1)

????},

????//7?最新排序

????searchGmtCreate(){

??????//設(shè)置對(duì)應(yīng)變量值,為了樣式生效

??????this.buyCountSort?=?""

??????this.gmtCreateSort?=?"1"

??????this.priceSort?=?""

??????//把值賦值到search0bj

??????this.searchObj.buyCountSort?=?this.buyCountSort

??????this.searchObj.gmtCreateSort?=?this.gmtCreateSort

??????this.searchObj.priceSort?=?this.priceSort

??????//調(diào)用方法查詢

??????this.gotoPage(1)

????},

????//8?價(jià)格排序

????searchPrice(){

??????//設(shè)置對(duì)應(yīng)變量值,為了樣式生效

??????this.buyCountSort?=?""

??????this.gmtCreateSort?=?""

??????this.priceSort?=?"1"

??????//把值賦值到search0bj

??????this.searchObj.buyCountSort?=?this.buyCountSort

??????this.searchObj.gmtCreateSort?=?this.gmtCreateSort

??????this.searchObj.priceSort?=?this.priceSort

??????//調(diào)用方法查詢

??????this.gotoPage(1)

????}

三、課程列表渲染

1、課程類別顯示

????<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>

2、無(wú)數(shù)據(jù)提示

添加:v-if="data.total==0"

?????????<!--?/無(wú)數(shù)據(jù)提示?開(kāi)始-->

??????????<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">沒(méi)有相關(guān)數(shù)據(jù),小編正在努力整理中...</span>

??????????</section>

??????????<!--?/無(wú)數(shù)據(jù)提示?結(jié)束-->

3、列表

????<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="開(kāi)始學(xué)習(xí)"?class="comm-btn?c-btn-1">開(kāi)始學(xué)習(xí)</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">免費(fèi)</i>

????????????????????</span>

????????????????????<span?class="fl?jgAttr?c-ccc?f-fA">

??????????????????????<i?class="c-999?f-fA">{{?item.viewCount?}}人學(xué)習(xí)</i>

??????????????????????|

??????????????????????<i?class="c-999?f-fA">9634評(píng)論</i>

????????????????????</span>

??????????????????</section>

????????????????</div>

??????????????</li>

????????????</ul>

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

??????????</article>

4、分頁(yè)頁(yè)面渲染

????<!--?公共分頁(yè)?開(kāi)始?-->

??????????<div>?????

????????????<div?class="paging">

??????????????<!--?undisable這個(gè)class是否存在,取決于數(shù)據(jù)屬性hasPrevious?-->

??????????????<a

????????????????:class="{undisable:?!data.hasPrevious}"

????????????????href="#"

????????????????title="首頁(yè)"

????????????????@click.prevent="gotoPage(1)">首頁(yè)</a>

??????????????<a

????????????????:class="{undisable:?!data.hasPrevious}"

????????????????href="#"

????????????????title="前一頁(yè)"

????????????????@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+'頁(yè)'"

????????????????href="#"

????????????????@click.prevent="gotoPage(page)">{{?page?}}</a>

??????????????<a

????????????????:class="{undisable:?!data.hasNext}"

????????????????href="#"

????????????????title="后一頁(yè)"

????????????????@click.prevent="gotoPage(data.current+1)">&gt;</a>

??????????????<a

????????????????:class="{undisable:?!data.hasNext}"

????????????????href="#"

????????????????title="末頁(yè)"

????????????????@click.prevent="gotoPage(data.pages)">末頁(yè)</a>

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

????????????</div>

??????????</div>

????????<!--?公共分頁(yè)?結(jié)束?-->



03-課程詳情頁(yè)

一、vo對(duì)象的定義

在項(xiàng)目中很多時(shí)候需要把model轉(zhuǎn)換成dto用于網(wǎng)站信息的展示,按前端的需要傳遞對(duì)象的數(shù)據(jù),保證model對(duì)外是隱私的,例如密碼之類的屬性能很好地避免暴露在外,同時(shí)也會(huì)減小數(shù)據(jù)傳輸?shù)捏w積。

CourseWebInfoVo.java(用于封裝課程的詳情信息)

@ApiModel(value="課程信息", description="網(wǎng)站課程詳情頁(yè)需要的相關(guān)字段")

@Data

public class CourseWebInfoVo {

? ? private String id;

? ? @ApiModelProperty(value = "課程標(biāo)題")

? ? private String title;

? ? @ApiModelProperty(value = "課程銷售價(jià)格,設(shè)置為0則可免費(fèi)觀看")

? ? private BigDecimal price;

? ? @ApiModelProperty(value = "總課時(shí)")

? ? private Integer lessonNum;

? ? @ApiModelProperty(value = "課程封面圖片路徑")

? ? private String cover;

? ? @ApiModelProperty(value = "銷售數(shù)量")

? ? private Long buyCount;

? ? @ApiModelProperty(value = "瀏覽數(shù)量")

? ? private Long viewCount;

? ? @ApiModelProperty(value = "課程簡(jiǎn)介")

? ? private String description;

? ? @ApiModelProperty(value = "講師ID")

? ? private String teacherId;

? ? @ApiModelProperty(value = "講師姓名")

? ? private String teacherName;

? ? @ApiModelProperty(value = "講師資歷,一句話說(shuō)明講師")

? ? private String intro;

? ? @ApiModelProperty(value = "講師頭像")

? ? private String avatar;

? ? @ApiModelProperty(value = "課程一級(jí)類別ID")

? ? private String subjectLevelOneId;

? ? @ApiModelProperty(value = "類別一級(jí)名稱")

? ? private String subjectLevelOne;

? ? @ApiModelProperty(value = "課程二級(jí)類別ID")

? ? private String subjectLevelTwoId;

? ? @ApiModelProperty(value = "類別二級(jí)名稱")

? ? private String subjectLevelTwo;

}

二、課程和講師信息的獲取

1、CourseFrontController

? ?? //根據(jù)課程id,編寫(xiě)sq1語(yǔ)句查詢課程信息

????@ApiOperation(value = "根據(jù)ID查詢課程")

? ? @GetMapping("getFrontCourseInfo/{courseId}")

? ? public R getFrontCourseInfo(@PathVariable String courseId){

? ? ? ? //根據(jù)課程id,編寫(xiě)sql語(yǔ)句查詢課程信息

? ? ? ? CourseWebInfoVo courseWebInfoVo = courseService.getBaseCourseInfo(courseId);

? ? ? ? //根據(jù)課程id查詢章節(jié)和小節(jié)

? ? ? ? List<ChapterVo> chapterVideoByCourseId = chapterService.getChapterVideoByCourseId(courseId);

? ? ? ? return R.ok().data("courseWebVo",courseWebInfoVo).data("chapterVideoList",chapterVideoByCourseId);

? ? }

2、EduCourseService

? ? //根據(jù)課程id,編寫(xiě)sq1語(yǔ)句查詢課程信息

? ? CourseWebInfoVo getBaseCourseInfo(String courseId);

3、EduCourseServiceImpl

????//根據(jù)課程id,編寫(xiě)sq1語(yǔ)句查詢課程信息

? ? @Override

? ? public CourseWebInfoVo getBaseCourseInfo(String courseId) {

? ? ? ? return baseMapper.getBaseCourseInfo(courseId);

? ? }

4、Mapper中關(guān)聯(lián)查詢課程和講師信息

EduCourseMapper.java

????//根據(jù)課程id,編寫(xiě)sq1語(yǔ)句查詢課程信息

? ? CourseWebInfoVo getBaseCourseInfo(String courseId);

EduCourseMapper.xml

????<!-- sql語(yǔ)句:根據(jù)課程id,編寫(xiě)sq1語(yǔ)句查詢課程信息 -->

? ? <select id="getBaseCourseInfo" resultType="com.atguigu.eduservice.entity.frontvo.CourseWebInfoVo">

? ? ? ? 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>

因?yàn)楝F(xiàn)在方法中只有一個(gè)參數(shù),當(dāng)只有一個(gè)參數(shù)時(shí),WHEREec.id=#{courseId}中courseId可以隨便寫(xiě)。

默認(rèn)xml文件不加載問(wèn)題:


三、前端js

1、api/course.js

? //?課程詳情的方法

??getCourseInfo(courseId){

????return?request({

????????url:?`/eduservice/coursefront/getFrontCourseInfo/${courseId}`,

????????method:?'get'

????})

??}

2、pages/course/_id.vue

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

四、頁(yè)面模板

pages/course/_id.vue

1、課程所屬分類

???<!--?課程所屬分類?開(kāi)始?-->

????<section?class="container">

??????<section?class="path-wrap?txtOf?hLh30">

????????<a?href="#"?title?class="c-999?fsize14">首頁(yè)</a>

????????\

????????<a?href="#"?title?class="c-999?fsize14">課程列表</a>

????????\

????????<span?class="c-333?fsize14">{{courseWebVo.subjectLevelOne}}</span>

????????\

????????<span?class="c-333?fsize14">{{courseWebVo.subjectLevelTwo}}</span>

??????</section>

??????<!--?/課程所屬分類?結(jié)束?-->

2、課程基本信息

??????<!--?課程基本信息?開(kāi)始?-->

??????<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">價(jià)格:</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">購(gòu)買數(shù)</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">課時(shí)數(shù)</span>

????????????????<br>

????????????????<h6?class="c-fff?f-fM?mt10">{{courseWebVo.lessonNum}}</h6>

??????????????</aside>

????????????</li>

????????????<li>

??????????????<p>&nbsp;</p>

??????????????<aside>

????????????????<span?class="c-fff?f-fM">瀏覽數(shù)</span>

????????????????<br>

????????????????<h6?class="c-fff?f-fM?mt10">{{courseWebVo.viewCount}}</h6>

??????????????</aside>

????????????</li>

??????????</ol>

????????</aside>

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

??????</div>

??????<!--?/課程基本信息?結(jié)束?-->

3、課程詳情介紹

在后端添加課程簡(jiǎn)介時(shí)可以添加樣式,但是?{{courseWebVo.description}}只是進(jìn)行了原樣輸出。

????????????????????<!--?將內(nèi)容中的html翻譯過(guò)來(lái)?-->

??????????????????????<p?v-html="courseWebVo.description">

????????????????????????{{courseWebVo.description}}

??????????????????????</p>

4、課程大綱

????????????<!--?課程大綱?開(kāi)始-->

????????????????<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="#"?title>

??????????????????????????????????<span?class="fr">

????????????????????????????????????<i?class="free-icon?vam?mr10"?v-if="video.free?===?true">免費(fèi)試聽(tīng)</i>

??????????????????????????????????</span>

??????????????????????????????????<em?class="lh-menu-i-2?icon16?mr5">&nbsp;</em>{{video.title}}

????????????????????????????????</a>

??????????????????????????????</li>

????????????????????????????</ol>

??????????????????????????</li>

????????????????????????</ul>

??????????????????????</menu>

????????????????????</div>

??????????????????</section>

????????????????</div>

????????????????<!--?/課程大綱?結(jié)束?-->

5、主講講師

???<!--?主講講師?開(kāi)始-->

????????????<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/'+courseWebVo.teacherId">

????????????????????????<img?:src="courseWebVo.avatar"?width="50"?height="50"?alt>

??????????????????????</a>

????????????????????</div>

????????????????????<section?class="hLh30?txtOf">

?????????????????????? <a?class="c-333?fsize16?fl"?:href="'/teacher/'+courseWebVo.teacherId"> {{courseWebVo.teacherName}}</a>

????????????????????</section>

????????????????????<section?class="hLh20?txtOf">

??????????????????????<span?class="c-999">{{courseWebVo.intro}}</span>

????????????????????</section>

??????????????????</li>

????????????????</ul>

??????????????</section>

????????????</div>

????????????<!--?/主講講師?結(jié)束?-->

最終顯示結(jié)果:



04-視頻播放測(cè)試

一、獲取播放地址播放

獲取播放地址

參考文檔:https://help.aliyun.com/document_detail/61064.html

前面的?03-使用服務(wù)端SDK?介紹了如何獲取非加密視頻的播放地址。直接使用03節(jié)的例子獲取加密視頻播放地址會(huì)返回如下錯(cuò)誤信息

Currently only the AliyunVoDEncryption stream exists, you must use the Aliyun player to play or set the value of ResultType to Multiple.

目前只有AliyunVoDEncryption流存在,您必須使用Aliyun player來(lái)播放或?qū)esultType的值設(shè)置為Multiple。

因此在testGetPlayInfo測(cè)試方法中添加?ResultType?參數(shù),并設(shè)置為true

privateParams.put("ResultType","Multiple");

此種方式獲取的視頻文件不能直接播放,必須使用阿里云播放器播放

二、視頻播放器

參考文檔:https://help.aliyun.com/document_detail/61109.html

1、視頻播放器介紹

阿里云播放器SDK(ApsaraVideo Player SDK)是阿里視頻服務(wù)的重要一環(huán),除了支持點(diǎn)播和直播的基礎(chǔ)播放功能外,深度融合視頻云業(yè)務(wù),如支持視頻的加密播放、安全下載、清晰度切換、直播答題等業(yè)務(wù)場(chǎng)景,為用戶提供簡(jiǎn)單、快速、安全、穩(wěn)定的視頻播放服務(wù)。

2、集成視頻播放器

參考文檔:https://help.aliyun.com/document_detail/51991.html

參考 【播放器簡(jiǎn)單使用說(shuō)明】一節(jié)

引入腳本文件和css文件

?????<link?rel="stylesheet"??/>

????<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('播放器創(chuàng)建好了。')

????????????});

????????</script>

</body>

3、播放地址播放

在Aliplayer的配置參數(shù)中添加如下屬性

????????????????//播放方式一:支持播放地址播放,此播放優(yōu)先級(jí)最高,此種方式不能播放加密視頻

????????????????source?:?'你的視頻播放地址',

測(cè)試:創(chuàng)建html文件(01播放地址播放.html)

<!DOCTYPE?html>

<html?lang="en">

<head>

????<meta?charset="UTF-8">

????<meta?name="viewport"?content="width=device-width,?initial-scale=1.0">

????<title>Document</title>


????<link?rel="stylesheet"??/>

????<script?charset="utf-8"?type="text/javascript"?src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"></script>

</head>

<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',

????????????????//播放配置

????????????????//播放方式一:支持播放地址播放,此播放優(yōu)先級(jí)最高,此種方式不能播放加密視頻

????????????????source?:?'https://outin-b2b9512bc4dc11ea89cf00163e1c60dc.oss-cn-shanghai.aliyuncs.com/sv/25884263-1734c67e05f/25884263-1734c67e05f.mp4?Expires=1595476184&OSSAccessKeyId=LTAIxSaOfEzCnBOj&Signature=wj2Q5wH1m2snNTmPyDSo6cD4YTU%3D',

????????????},function(player){

????????????????console.log('播放器創(chuàng)建好了。')

????????????});

????????</script>

</body>

</html>

啟動(dòng)瀏覽器運(yùn)行,測(cè)試視頻的播放:

4、播放憑證播放(推薦)

阿里云播放器支持通過(guò)播放憑證自動(dòng)換取播放地址進(jìn)行播放,接入方式更為簡(jiǎn)單,且安全性更高。播放憑證默認(rèn)時(shí)效為100秒(最大為3000秒),只能用于獲取指定視頻的播放地址,不能混用或重復(fù)使用。如果憑證過(guò)期則無(wú)法獲取播放地址,需要重新獲取憑證。

encryptType:'1',//如果播放加密視頻,則需設(shè)置encryptType=1,非加密視頻無(wú)需設(shè)置此項(xiàng)

vid:'視頻id',

playauth:'視頻授權(quán)碼',

注意:播放憑證有過(guò)期時(shí)間,默認(rèn)值:100秒?。取值范圍:100~3000。

設(shè)置播放憑證的有效期

在獲取播放憑證的測(cè)試用例中添加如下代碼

request.setAuthInfoTimeout(200L);

在線配置參考:https://player.alicdn.com/aliplayer/setting/setting.html

測(cè)試:創(chuàng)建html文件(02播放憑證播放.html)

playauth是根據(jù)視頻id獲取。

<!DOCTYPE?html>

<html?lang="en">

<head>

????<meta?charset="UTF-8">

????<meta?name="viewport"?content="width=device-width,?initial-scale=1.0">

????<title>Document</title>


????<link?rel="stylesheet"??/>

????<script?charset="utf-8"?type="text/javascript"?src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"></script>

</head>

<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',

????????????????//播放配置

????????????????//播放憑證播放

????????????????encryptType:'1',//如果播放加密視頻,則需設(shè)置encryptType=1,非加密視頻無(wú)需設(shè)置此項(xiàng)

????????????????vid?:?'07d8aac8a3b045c69cd91b84bdbedc19',

????????????????playauth?:?'eyJTZWN1cml0eVRva2VuIjoiQ0FJUzN3SjFxNkZ0NUIyeWZTaklyNWZrQ01uUnZMbEc0UFNETkdEZ3FITVVhc2RobjUvZ2pUejJJSGhKZVhOdkJPMGV0ZjQrbVdCWTdQY1lsck1xRXM0VUhST1lQSklwc01VSXJsUDRKcExGc3QySjZyOEpqc1V6aE5vMTFGaXBzdlhKYXNEVkVma3VFNVhFTWlJNS8wMGU2TC8rY2lyWVhEN0JHSmFWaUpsaFE4MEtWdzJqRjFSdkQ4dFhJUTBRazYxOUszemRaOW1nTGlidWkzdnhDa1J2MkhCaWptOHR4cW1qL015UTV4MzFpMXYweStCM3dZSHRPY3FjYThCOU1ZMVdUc3Uxdm9oemFyR1Q2Q3BaK2psTStxQVU2cWxZNG1YcnM5cUhFa0ZOd0JpWFNaMjJsT2RpTndoa2ZLTTNOcmRacGZ6bjc1MUN0L2ZVaXA3OHhtUW1YNGdYY1Z5R0dOLzZuNU9aUXJ6emI0WmhKZWVsQVJtWGpJRFRiS3VTbWhnL2ZIY1dPRGxOZjljY01YSnFBWFF1TUdxQ2QvTDlwdzJYT2x6NUd2WFZnUHRuaTRBSjVsSHA3TWVNR1YrRGVMeVF5aDBFSWFVN2EwNDQvNWVUWWFwazFNVWFnQUU1cXBMc2ZOQVB4S2lmQWRGbXZySjQyaWNaQVYyd3A4T05OODlVR1Q2NHEySkJnSE9NYlV3aHRYQUJvUmhBSXZLbVJtbVdIQnBwQ0hmRHB3cUxoNkRtUGw3bTQ0QUtrb0J0R0w0YmR2eUFMbGtBbWI0MWdWcXM2UERlVkUybTRHQ1BvRDNZNkFIUGJpYlpjWEJCQzNnaFpXOGhTa1dqMkJieFFKWHJEK09ZSFE9PSIsIkF1dGhJbmZvIjoie1wiQ0lcIjpcIkdCU2NldzJNQ0J4eHQ1d2MydXgyang0VTZzTFRESWtYMC9jMGpONnhiclFJUjR5MldxTHdLdzE4clJnRVZlTVJcXHJcXG5cIixcIkNhbGxlclwiOlwiYWovb2tGOC9CTFZOR0p2VEJlWHZWS3VYbE9oU1I3QldOVGRPRGVwVlB6az1cXHJcXG5cIixcIkV4cGlyZVRpbWVcIjpcIjIwMjAtMDctMjNUMDM6MTE6MThaXCIsXCJNZWRpYUlkXCI6XCIwN2Q4YWFjOGEzYjA0NWM2OWNkOTFiODRiZGJlZGMxOVwiLFwiU2lnbmF0dXJlXCI6XCJqcWRBRHp5OXliNkZJZmxLQlBDTHNyT3V4eVU9XCJ9IiwiVmlkZW9NZXRhIjp7IlN0YXR1cyI6Ik5vcm1hbCIsIlZpZGVvSWQiOiIwN2Q4YWFjOGEzYjA0NWM2OWNkOTFiODRiZGJlZGMxOSIsIlRpdGxlIjoiNiAtIFdoYXQgSWYgSSBXYW50IHRvIE1vdmUgRmFzdGVyIiwiQ292ZXJVUkwiOiJodHRwOi8vb3V0aW4tYjJiOTUxMmJjNGRjMTFlYTg5Y2YwMDE2M2UxYzYwZGMub3NzLWNuLXNoYW5naGFpLmFsaXl1bmNzLmNvbS8wN2Q4YWFjOGEzYjA0NWM2OWNkOTFiODRiZGJlZGMxOS9zbmFwc2hvdHMvNTkxZDRiYjM1MGQ1NDM4M2IzYWM4ZGVjYzI0ZGM0NGEtMDAwMDEuanBnP0V4cGlyZXM9MTU5NTQ3NzM3OCZPU1NBY2Nlc3NLZXlJZD1MVEFJeFNhT2ZFekNuQk9qJlNpZ25hdHVyZT13d0NieXh2R0gxeW1xM0g0d3RzMHlRTFMyelUlM0QiLCJEdXJhdGlvbiI6MTYuMjc2N30sIkFjY2Vzc0tleUlkIjoiU1RTLk5UUUNzZVFmZ1c2aDZGUUxzQWZITXBaS28iLCJBY2Nlc3NLZXlTZWNyZXQiOiJwNlNQdGZoOUhXS1FRMzZESERuOEg4QWlDTHRwM2tqODQ5V2hOeDRIUXZuIiwiUmVnaW9uIjoiY24tc2hhbmdoYWkiLCJDdXN0b21lcklkIjoxMTk5MDc0OTExNjk3NzgxfQ',????????????????

????????????},function(player){

????????????????console.log('播放器創(chuàng)建好了。')

????????????});

????????</script>

</body>

</html>

啟動(dòng)瀏覽器運(yùn)行,測(cè)試視頻的播放:



05-整合阿里云視頻播放器

一、后端獲取播放憑證

1、VodController

service-vod微服務(wù)中創(chuàng)建 VodController.java

controller中創(chuàng)建 getPlayAuth接口方法

????//根據(jù)視頻id獲取視頻憑證

? ? @GetMapping("getPlayAuth/{id}")

? ? public R getPlayAuth(@PathVariable String id){

? ? ? ? try {

? ? ? ? ? ? //創(chuàng)建初始化對(duì)象

? ? ? ? ? ? DefaultAcsClient client = InitObjectV.initVodClient(ConstantPropertiesUtil.ACCESS_KEY_ID,ConstantPropertiesUtil.ACCESS_KEY_SECRET);

? ? ? ? ? ? //創(chuàng)建獲取憑證request和response對(duì)象

? ? ? ? ? ? GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();

? ? ? ? ? ? //向request設(shè)置視頻id

? ? ? ? ? ? request.setVideoId(id);

? ? ? ? ? ? //調(diào)用方法得到憑證

? ? ? ? ? ? GetVideoPlayAuthResponse response = client.getAcsResponse(request);

? ? ? ? ? ? String playAuth = response.getPlayAuth();

? ? ? ? ? ? return R.ok().data("playAuth",playAuth);

? ? ? ? } catch (ClientException e) {

? ? ? ? ? ? throw new GuliException(20001,"獲取憑證失敗");

? ? ? ? }

? ? }

2、Swagger測(cè)試

二、前端播放器整合

1、點(diǎn)擊播放超鏈接

course/_id.vue

修改課時(shí)目錄超鏈接

2、layout

因?yàn)椴シ牌鞯牟季趾推渌?yè)面的基本布局不一致,因此創(chuàng)建新的布局容器 layouts/video.vue

<template>

??<div?class="guli-player">

????<div?class="head">

??????<a?href="#"?title="谷粒學(xué)院">

????????<img?class="logo"?src="~/assets/img/logo.png"?lt="谷粒學(xué)院">

??????</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>

3、api

創(chuàng)建api模塊 api/vod.js,從后端獲取播放憑證

import?request?from?'@/utils/request'

export?default?{

????//根據(jù)視頻id獲取視頻憑證

????getPlayAuth(vid)?{

????????return?request({

????????????url:?`/eduvod/video/getPlayAuth/${vid}`,

????????????method:?'get'

????????})

????}

}

4、播放組件相關(guān)文檔

集成文檔: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

5、創(chuàng)建播放頁(yè)面

創(chuàng)建pages/player/_vid.vue

(1)引入播放器js庫(kù)和css樣式

<template>

??<div>

????<!--?阿里云視頻播放器樣式?-->

????<link?rel="stylesheet"??>

????<!--?阿里云視頻播放器腳本?-->

????<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>

(2)獲取播放憑證

(3)創(chuàng)建播放器

?????/**

?????*?頁(yè)面渲染完成時(shí):此時(shí)js腳本已加載,Aliplayer已定義,可以使用

?????*?如果在created生命周期函數(shù)中使用,Aliplayer?is?not?defined錯(cuò)誤

?????*/

????mounted()?{

????????new?Aliplayer({

????????????id:?'J_prismPlayer',

????????????vid:?this.vid,?//?視頻id

????????????playauth:?this.playAuth,?//?播放憑證

????????????encryptType:?'1',?//?如果播放加密視頻,則需設(shè)置encryptType=1,非加密視頻無(wú)需設(shè)置此項(xiàng)

????????????width:?'100%',

????????????height:?'500px'

????????},?function(player)?{

????????????console.log('播放器創(chuàng)建成功')

????????})

????}

(4)其他常見(jiàn)的可選配置

????????//?以下可選設(shè)置

????????????cover:?'http://guli.shop/photo/banner/1525939573202.jpg',?//?封面

????????????qualitySort:?'asc',?//?清晰度排序

????????????mediaType:?'video',?//?返回音頻還是視頻

????????????autoplay:?false,?//?自動(dòng)播放

????????????isLive:?false,?//?直播

????????????rePlay:?false,?//?循環(huán)播放

????????????preload:?true,

????????????controlBarVisibility:?'hover',?//?控制條的顯示方式:鼠標(biāo)懸停

????????????useH5Prism:?true,?//?播放器類型:html5

6、加入播放組件

功能展示:https://player.alicdn.com/aliplayer/presentation/index.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容