day09項目【課程列表和整合阿里云視頻點播】

1 課程列表和課程刪除

01-課程列表的顯示

課程列表顯示:

課程列表(參考講師列表花沉,完善條件查詢和分頁):

一柳爽、后端實現(xiàn)

1、定義搜索對象

CourseQuery:

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

@Data

public class CourseQuery {

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

? ? private String title;

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

? ? private String teacherId;

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

? ? private String subjectParentId;

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

? ? private String subjectId;

}

2碱屁、定義web層方法

????//條件查詢帶分頁的方法

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

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

? ? public R pageCourseCondition(@ApiParam(name = "current", value = "當前頁碼", required = true) @PathVariable long current,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @ApiParam(name = "limit", value = "每頁記錄數(shù)", required = true) @PathVariable long limit,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @RequestBody(required = false) CourseQuery courseQuery){

? ? ? ? //創(chuàng)建page對象

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

? ? ? ? courseService.pageQuery(pageParam,courseQuery);

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

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

? ? ? ? //調(diào)用方法實現(xiàn)條件查詢分頁

? ? ? ? return R.ok().data("rows",records).data("total",total);

? ? }

3磷脯、定義service方法

接口

void pageQuery(Page<EduCourse> pageParam, CourseQuery courseQuery);

實現(xiàn)

@Override

? ? public void pageQuery(Page<EduCourse> pageParam, CourseQuery courseQuery) {

? ? ? ? //構(gòu)建條件

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

? ? ? ? courseQueryWrapper.orderByDesc("gmt_create");

? ? ? ? //wrapper

? ? ? ? if (courseQuery == null){

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

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? String title = courseQuery.getTitle();

? ? ? ? String teacherId = courseQuery.getTeacherId();

? ? ? ? String subjectParentId = courseQuery.getSubjectParentId();

? ? ? ? String subjectId = courseQuery.getSubjectId();

? ? ? ? if (!StringUtils.isEmpty(title)){

? ? ? ? ? ? courseQueryWrapper.like("title",title);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(teacherId)){

? ? ? ? ? ? courseQueryWrapper.eq("teacher_id",teacherId);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(subjectParentId)){

? ? ? ? ? ? courseQueryWrapper.eq("subject_parent_id",subjectParentId);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(subjectId)){

? ? ? ? ? ? courseQueryWrapper.eq("subject_id",subjectId);

? ? ? ? }

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

? ? }

二、前端分頁查詢列表

1娩脾、定義api

course.js

?//課程列表(條件查詢分頁)

????//current當前頁赵誓,limit每頁記錄數(shù),teacherQuery條件對象

????getCoursePageList(current,limit,courseQuery){

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

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

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

????????????data:courseQuery

????????})

????}

2柿赊、組件中的js

src/views/edu/list.vue

<script>

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

import?teacher?from?'@/api/edu/teacher'

import?subject?from?'@/api/edu/subject'

export?default?{

????data(){

????????return?{

????????????listLoading:?true,?//?是否顯示loading信息

????????????list:null,

????????????page:1,//當前頁

????????????limit:10,//每頁記錄數(shù)

????????????total:0,//總記錄數(shù)

????????????courseQuery:{},//條件封裝對象

????????????teacherList:?[],?//?講師列表

????????????subjectNestedList:?[],?//?一級分類列表

????????????subSubjectList:?[]?//?二級分類列表,

????????}

????},

????created(){

????????this.getList()

????????//?初始化分類列表

????????this.initSubjectList()

????????//?獲取講師列表

????????this.initTeacherList()

????},

????methods:{

????????getList(page=1)?{

????????????this.page?=?page

????????????this.listLoading?=?true

????????????course.getCoursePageList(this.page,this.limit,this.courseQuery)

????????????????.then(response=>{

????????????????????if?(response.success?===?true)?{

????????????????????????this.list?=?response.data.rows

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

????????????????????}???

????????????????????this.listLoading?=?false

????????????????})

????????????????.catch(error?=>{//請求失敗

????????????????????console.log(error)

????????????????})

????????},

????????initTeacherList()?{

????????????teacher.getTeacherList()

????????????????.then(response?=>?{

????????????????????this.teacherList?=?response.data.items

????????????????})

????????},

????????initSubjectList()?{

????????????subject.getSubjectList()

????????????????.then(response?=>?{

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

????????????????})

????????},

????????subjectLevelOneChanged(value){

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

????????????????????if?(this.subjectNestedList[i].id?===?value)?{

????????????????????this.subSubjectList?=?this.subjectNestedList[i].children

????????????????????this.searchObj.subjectId?=?''

????????????????????}

????????????????}

????????},

????????resetData(){//清空方法

????????????//表單輸入項數(shù)據(jù)清空

????????????this.courseQuery?=?{}

????????????this.subSubjectList?=?[]?//?二級分類列表

????????????//查詢所有講師數(shù)據(jù)

????????????this.getList()

????????},

????}

}

</script>

3俩功、組件模板

查詢表單、表格和分頁:表格添加了 row-class-name="myClassList" 樣式定義

<template>

????<div?class="app-container">

????????<!--查詢表單-->

????????<el-form?:inline="true"?class="demo-form-inline">

????????<!--?所屬分類:級聯(lián)下拉列表?-->

????????<!--?一級分類?-->

????????<el-form-item?label="課程類別">

????????????<el-select

????????????v-model="courseQuery.subjectParentId"

????????????placeholder="請選擇"

????????????@change="subjectLevelOneChanged">

????????????<el-option

????????????????v-for="subject?in?subjectNestedList"

????????????????:key="subject.id"

????????????????:label="subject.title"

????????????????:value="subject.id"/>

????????????</el-select>


????????????<!--?二級分類?-->

????????????<el-select?v-model="courseQuery.subjectId"?placeholder="請選擇">

????????????<el-option

????????????????v-for="subject?in?subSubjectList"

????????????????:key="subject.id"

????????????????:label="subject.title"

????????????????:value="subject.id"/>

????????????</el-select>

????????</el-form-item>


????????<!--?標題?-->

????????<el-form-item>

????????????<el-input?v-model="courseQuery.title"?placeholder="課程標題"/>

????????</el-form-item>

????????<!--?講師?-->

????????<el-form-item>

????????????<el-select

????????????v-model="courseQuery.teacherId"

????????????placeholder="請選擇講師">

????????????<el-option

????????????????v-for="teacher?in?teacherList"

????????????????:key="teacher.id"

????????????????:label="teacher.name"

????????????????:value="teacher.id"/>

????????????</el-select>

????????</el-form-item>


????????<el-button?type="primary"?icon="el-icon-search"?@click="getList()">查詢</el-button>

????????<el-button?type="default"?@click="resetData()">清空</el-button>

????????</el-form>

????????<!--?表格?-->

????????<el-table

????????????v-loading="listLoading"

????????????:data="list"

????????????element-loading-text="數(shù)據(jù)加載中"

????????????border

????????????fit

????????????highlight-current-row

????????????row-class-name="myClassList">


????????????<el-table-column

????????????????label="序號"

????????????????width="70"

????????????????align="center">

????????????????<template?slot-scope="scope">

????????????????{{?(page?-?1)?*?limit?+?scope.$index?+?1?}}

????????????????</template>

????????????</el-table-column>

????????????<el-table-column?label="課程信息"?width="470"?align="center">

????????????????<template?slot-scope="scope">

????????????????<div?class="info">

????????????????????<div?class="pic">

????????????????????????<img?:src="scope.row.cover"?alt="scope.row.title"?width="150px">

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

????????????????????<div?class="title">

????????????????????<a?href="">{{?scope.row.title?}}</a>

????????????????????<p>{{?scope.row.lessonNum?}}課時</p>

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

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


????????????????</template>

????????????</el-table-column>


????????????<el-table-column?label="創(chuàng)建時間"?align="center">

????????????????<template?slot-scope="scope">

????????????????{{?scope.row.gmtCreate.substr(0,?10)?}}

????????????????</template>

????????????</el-table-column>

????????????<el-table-column?label="發(fā)布時間"?align="center">

????????????????<template?slot-scope="scope">

????????????????{{?scope.row.gmtModified.substr(0,?10)?}}

????????????????</template>

????????????</el-table-column>

????????????<el-table-column?label="價格"?width="100"?align="center"?>

????????????????<template?slot-scope="scope">

????????????????{{?Number(scope.row.price)?===?0???'免費'?:

????????????????'¥'?+?scope.row.price.toFixed(2)?}}

????????????????</template>

????????????</el-table-column>

????????????<el-table-column?prop="buyCount"?label="付費學員"?width="100"?align="center"?>

????????????????<template?slot-scope="scope">

????????????????{{?scope.row.buyCount?}}人

????????????????</template>

????????????</el-table-column>


????????????<el-table-column?label="操作"?width="150"?align="center">

????????????????<template?slot-scope="scope">

????????????????<router-link?:to="'/edu/course/info/'+scope.row.id">

????????????????????<el-button?type="text"?size="mini"?icon="el-icon-edit">編輯課程信息</el-button>

????????????????</router-link>

????????????????<router-link?:to="'/edu/course/chapter/'+scope.row.id">

????????????????????<el-button?type="text"?size="mini"?icon="el-icon-edit">編輯課程大綱</el-button>

????????????????</router-link>

????????????????<el-button?type="text"?size="mini"?icon="el-icon-delete">刪除</el-button>

????????????????</template>

????????????</el-table-column>

????????</el-table>

????????<!--?分頁?-->

????????<el-pagination

????????:current-page="page"

????????:page-size="limit"

????????:total="total"

????????style="padding:?30px?0;?text-align:?center;"

????????layout="total,?prev,?pager,?next,?jumper"

????????@current-change="getList"

????????/>

????</div>

</template>

4碰声、css的定義

<style?scoped>

.myClassList?.info?{

????width:?450px;

????overflow:?hidden;

}

.myClassList?.info?.pic?{

????width:?150px;

????height:?90px;

????overflow:?hidden;

????float:?left;

}

.myClassList?.info?.pic?a?{

????display:?block;

????width:?100%;

????height:?100%;

????margin:?0;

????padding:?0;

}

.myClassList?.info?.pic?img?{

????display:?block;

????width:?100%;

}

.myClassList?td?.info?.title?{

????width:?280px;

????float:?right;

????height:?90px;

}

.myClassList?td?.info?.title?a?{

????display:?block;

????height:?48px;

????line-height:?24px;

????overflow:?hidden;

????color:?#00baf2;

????margin-bottom:?12px;

}

.myClassList?td?.info?.title?p?{

????line-height:?20px;

????margin-top:?5px;

????color:?#818181;

}

</style>

分頁失敗原因:

測試:

編輯:即可完成點擊“編輯課程信息”和“編輯課程大綱”跳轉(zhuǎn)到相應(yīng)的頁面進行編輯


02-刪除課程

一诡蜓、后端實現(xiàn)

1、web層

定義刪除api方法:EduCourseController.java

????//根據(jù)ID刪除課程

? ? @ApiOperation(value = "根據(jù)ID刪除課程")

? ? @DeleteMapping("deleteCourse/{courseId}")

? ? public R deleteCourse(@ApiParam(name = "id", value = "課程ID", required = true)

? ? ? ? ? ? ? ? ? ? ? ? ? ? @PathVariable String courseId){

? ? ? ? courseService.removeCourse(courseId);

? ? ? ? return R.ok();

? ? }

2胰挑、service層

如果用戶確定刪除蔓罚,則首先刪除video記錄,然后刪除chapter記錄瞻颂,最后刪除Course記錄

//當前在課程實現(xiàn)類EduCourseServiceImpl中豺谈,刪除小節(jié)和章節(jié)需要在其實現(xiàn)類中刪除,因此首先將相關(guān)的Service進行注入

????@Autowired

? ? private EduVideoService videoService;

? ? @Autowired

? ? private EduChapterService chapterService;

2.1贡这、在VideoService中定義根據(jù)courseId刪除video業(yè)務(wù)方法

接口:

void removeVideoByCourseId(String courseId);

實現(xiàn):

????// 1 根據(jù)課程id刪除小節(jié)

? ? //TODO 刪除小節(jié)茬末,刪除對應(yīng)視頻文件

? ? @Override

? ? public void removeVideoByCourseId(String courseId) {

? ? ? ? //需要根據(jù)小節(jié)id進行刪除,但是傳遞過來的是課程id盖矫,因此需要傳遞對象

? ? ? ? QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();

? ? ? ? wrapper.eq("course_id",courseId);

? ? ? ? baseMapper.delete(wrapper);

? ? }

2.2丽惭、在ChapterService中定義根據(jù)courseId刪除chapter業(yè)務(wù)方法

接口:

void removeChapterByCourseId(String courseId);

實現(xiàn):

????//根據(jù)課程id刪除章節(jié)

? ? @Override

? ? public void removeChapterByCourseId(String courseId) {

? ? ? ? QueryWrapper<EduChapter> wrapper = new QueryWrapper<>();

? ? ? ? wrapper.eq("course_id",courseId);

? ? ? ? baseMapper.delete(wrapper);

? ? }

2.3击奶、刪除當前course記錄

接口:CourseService.java

????//根據(jù)ID刪除課程

? ? void removeCourse(String courseId);

實現(xiàn):CourseServiceImpl.java

????//根據(jù)ID刪除課程

? ? @Override

? ? public void removeCourse(String courseId) {

? ? ? ? //1 根據(jù)課程id刪除小節(jié)

? ? ? ? videoService.removeVideoByCourseId(courseId);

? ? ? ? //2 根據(jù)課程id刪除章節(jié)

? ? ? ? chapterService.removeChapterByCourseId(courseId);

? ? ? ? //3 根據(jù)課程id刪除描述

? ? ? ? courseDescriptionService.removeById(courseId);

? ? ? ? //4 根據(jù)課程id刪除課程本身

? ? ? ? int result = baseMapper.deleteById(courseId);

? ? ? ? if(result == 0) { //失敗返回

? ? ? ? ? ? throw new GuliException(20001,"刪除失敗");

? ? ? ? }

? ? }

測試:

測試刪除失敗:

成功:

二吐根、前端實現(xiàn)

刪除按鈕(完善):

1正歼、定義api

course.js中添加刪除方法

?????//根據(jù)ID刪除課程

????removeById(courseId){

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

????????????url:`/eduservice/course/deleteCourse/${courseId}`,

????????????method:'delete'

????????})

????}

2、修改刪除按鈕

src/api/edu/course.js 刪除按鈕注冊click事件

<el-button?type="text"?size="mini"?icon="el-icon-delete"?@click="removeDataById(scope.row.id)">刪除</el-button>

3拷橘、編寫刪除方法

removeDataById(id){

????????????//?debugger

????????????this.$confirm('此操作將永久刪除該課程,以及該課程下的章節(jié)和視頻喜爷,是否繼續(xù)?',?'提示',?{

????????????????confirmButtonText:?'確定',

????????????????cancelButtonText:?'取消',

????????????????type:?'warning'

????????????}).then(()?=>?{

????????????????return?course.removeById(id)

????????????}).then(()?=>?{

????????????????this.getList()

????????????????this.$message({

????????????????????type:?'success',

????????????????????message:?'刪除成功!'

????????????????})

????????????}).catch((response)?=>?{?//?失敗

????????????????if?(response?===?'cancel')?{

????????????????????this.$message({

????????????????????????type:?'info',

????????????????????????message:?'已取消刪除'

????????????????????})

????????????????}

????????????})

????????},


2 阿里云視頻點播

01-視頻點播簡介

一冗疮、阿里云視頻點播技術(shù)能力盤點

參考文章:

https://blog.csdn.net/qq_33857573/article/details/79564255

視頻點播(ApsaraVideo for VoD)是集音視頻采集、編輯檩帐、上傳术幔、自動化轉(zhuǎn)碼處理、媒體資源管理湃密、分發(fā)加速于一體的一站式音視頻點播解決方案诅挑。

1、應(yīng)用場景

????音視頻網(wǎng)站:無論是初創(chuàng)視頻服務(wù)企業(yè)泛源,還是已擁有海量視頻資源拔妥,可定制化的點播服務(wù)幫助客戶快速搭建擁有極致觀看體驗、安全可靠的視頻點播應(yīng)用达箍。

????短視頻:集音視頻拍攝没龙、特效編輯、本地轉(zhuǎn)碼缎玫、高速上傳硬纤、自動化云端轉(zhuǎn)碼、媒體資源管理赃磨、分發(fā)加速筝家、播放于一體的完整短視頻解決方案。目前已幫助1000+APP快速實現(xiàn)手機短視頻功能邻辉。

????直播轉(zhuǎn)點播:將直播流同步錄制為點播視頻溪王,用于回看。并支持媒資管理恩沛、媒體處理(轉(zhuǎn)碼及內(nèi)容審核/智能首圖等AI處理)在扰、內(nèi)容制作(云剪輯)、CDN分發(fā)加速等一系列操作雷客。

????在線教育:為在線教育客戶提供簡單易用芒珠、安全可靠的視頻點播服務(wù)〗寥梗可通過控制臺/API等多種方式上傳教學視頻皱卓,強大的轉(zhuǎn)碼能力保證視頻可以快速發(fā)布裹芝,覆蓋全網(wǎng)的加速節(jié)點保證學生觀看的流暢度。防盜鏈娜汁、視頻加密等版權(quán)保護方案保護教學內(nèi)容不被竊取嫂易。

????視頻生產(chǎn)制作:提供在線可視化剪輯平臺及豐富的OpenAPI,幫助客戶高效處理掐禁、制作視頻內(nèi)容怜械。除基礎(chǔ)的剪切拼接、混音傅事、遮標缕允、特效、合成等一系列功能外蹭越,依托云剪輯及點播一體化服務(wù)還可實現(xiàn)標準化障本、智能化剪輯生產(chǎn),大大降低視頻制作的檻响鹃,縮短制作時間驾霜,提升內(nèi)容生產(chǎn)效率。

????內(nèi)容審核:應(yīng)用于短視頻平臺买置、傳媒行業(yè)審核等場景粪糙,幫助客戶從從語音、文字堕义、視覺等多維度精準識別視頻猜旬、封面、標題或評論的違禁內(nèi)容進行AI智能審核與人工審核倦卖。

2洒擦、功能介紹

二、開通視頻點播云平臺

1怕膛、選擇視頻點播服務(wù)

產(chǎn)品->企業(yè)應(yīng)用->視頻云->視頻點播

2熟嫩、開通視頻點播

3、選擇按使用流量計費

4褐捻、資費說明

https://www.aliyun.com/price/product?spm=a2c4g.11186623.2.12.7fbd59b9vmXVN6#/vod/detail

????后付費

????套餐包

????欠費說明

????計費案例:https://help.aliyun.com/document_detail/64032.html?spm=a2c4g.11186623.4.3.363db1bcfdvxB5

5掸茅、整體流程

使用視頻點播實現(xiàn)音視頻上傳、存儲柠逞、處理和播放的整體流程如下:

????用戶獲取上傳授權(quán)昧狮。

????VoD下發(fā) 上傳地址和憑證 及 VideoId。

????用戶上傳視頻保存視頻ID(VideoId)板壮。

????用戶服務(wù)端獲取播放憑證逗鸣。

????VoD下發(fā)帶時效的播放憑證。

????用戶服務(wù)端將播放憑證下發(fā)給客戶端完成視頻播放。

三撒璧、視頻點播服務(wù)的基本使用

完整的參考文檔

https://help.aliyun.com/product/29932.html?spm=a2c4g.11186623.6.540.3c356a58OEmVZJ

1透葛、設(shè)置轉(zhuǎn)碼格式

選擇全局設(shè)置 > 轉(zhuǎn)碼設(shè)置,單擊添加轉(zhuǎn)碼模板組卿樱。

在視頻轉(zhuǎn)碼模板組頁面僚害,根據(jù)業(yè)務(wù)需求選擇封裝格式和清晰度。

或直接將已有的模板設(shè)置為默認即可

2繁调、分類管理

選擇全局設(shè)置 > 分類管理

3萨蚕、上傳視頻文件

選擇媒資庫 > 音視頻,單擊上傳音視頻

4涉馁、配置域名

音視頻上傳完成后门岔,必須配一個已備案的域名,并完成CNAME綁定

得到CNAME

在購買域名的服務(wù)商處的管理控制臺配置域名解析

5烤送、在控制臺查看視頻

此時視頻可以在阿里云控制臺播放

6、獲取web播放器代碼

阿里云視頻點播概念:

????之前上傳文件糠悯,保存的是上傳文件之后的地址帮坚,但是在小節(jié)中保存視頻的時候,而是保存的是視頻的id互艾,并不保存視頻的地址试和,這是因為如果視頻沒有進行加密保存地址是可以的,但是如果視頻加密纫普,加密視頻地址是不能播放的阅悍,在實際項目中,視頻是需要加密的昨稼。

? ? 如果視頻不進行加密节视,那別人得到地址那視頻就可以播放,可以不付費就可以觀看假栓。

????保存的是視頻的id既可以得到視頻播放的地址寻行,也可以得到視頻播放的憑證(既可以播放加密視頻也可以播放不加密視頻)。


02-使用服務(wù)端SDK

一匾荆、服務(wù)端SDK

1拌蜘、簡介

sdk的方式將api進行了進一步的封裝,不用自己創(chuàng)建工具類牙丽。

我們可以基于服務(wù)端SDK編寫代碼來調(diào)用點播API简卧,實現(xiàn)對點播產(chǎn)品和服務(wù)的快速操作

2烤芦、功能介紹

????SDK封裝了對API的調(diào)用請求和響應(yīng)举娩,避免自行計算較為繁瑣的 API簽名。

????支持所有點播服務(wù)的API,并提供了相應(yīng)的示例代碼晓铆。

????支持7種開發(fā)語言勺良,包括:Java、Python骄噪、PHP尚困、.NET、Node.js链蕊、Go事甜、C/C++。

????通常在發(fā)布新的API后滔韵,我們會及時同步更新SDK逻谦,所以即便您沒有找到對應(yīng)API的示例代碼,也可以參考舊的示例自行實現(xiàn)調(diào)用陪蜻。

二邦马、使用SDK

在service創(chuàng)建子模塊service_ vod ,引入相關(guān)依賴到3 整合阿里云視頻點播 01-視頻點播微服務(wù)的創(chuàng)建筆記進行復制

1宴卖、安裝

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

添加maven倉庫的配置和依賴到pom

<repositories>

? ? ? ? <repository>

? ? ? ? ? ? <id>sonatype-nexus-staging</id>

? ? ? ? ? ? <name>Sonatype Nexus Staging</name>

? ? ? ? ? ? <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>

? ? ? ? ? ? <releases>

? ? ? ? ? ? ? ? <enabled>true</enabled>

? ? ? ? ? ? </releases>

? ? ? ? ? ? <snapshots>

? ? ? ? ? ? ? ? <enabled>true</enabled>

? ? ? ? ? ? </snapshots>

? ? ? ? </repository>

? ? </repositories>

<dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.aliyun</groupId>

? ? ? ? ? ? <artifactId>aliyun-java-sdk-core</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.aliyun.oss</groupId>

? ? ? ? ? ? <artifactId>aliyun-sdk-oss</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.aliyun</groupId>

? ? ? ? ? ? <artifactId>aliyun-java-sdk-vod</artifactId>

? ? ? ? </dependency>

<!--? ? ? ? <dependency>-->

<!--? ? ? ? ? ? <groupId>com.aliyun</groupId>-->

<!--? ? ? ? ? ? <artifactId>aliyun-sdk-vod-upload</artifactId>-->

<!--? ? ? ? </dependency>-->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.alibaba</groupId>

? ? ? ? ? ? <artifactId>fastjson</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.json</groupId>

? ? ? ? ? ? <artifactId>json</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.google.code.gson</groupId>

? ? ? ? ? ? <artifactId>gson</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>joda-time</groupId>

? ? ? ? ? ? <artifactId>joda-time</artifactId>

? ? ? ? </dependency>

? ? </dependencies>

2滋将、初始化

public class InitObject {

? ? public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException {

? ? ? ? String regionId = "cn-shanghai";? // 點播服務(wù)接入?yún)^(qū)域

? ? ? ? DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);

? ? ? ? DefaultAcsClient client = new DefaultAcsClient(profile);

? ? ? ? return client;

? ? }

}

3、獲取視頻播放地址

public class VodSdkTest {

? ? public static void main(String[] args) throws Exception {

? ? ? ? //1 根據(jù)視頻id獲取視頻播放地址

? ? ? ? //獲取初始化對象

? ? ? ? DefaultAcsClient client = InitObject.initVodClient("LTAI4GKJXUR4VuFMrtnzzWBG","yiEPUWzpivYpYTG8o0tVW4UFqE2EQh");

? ? ? ? //創(chuàng)建獲取視頻地址的request和response

? ? ? ? GetPlayInfoResponse response = new GetPlayInfoResponse();

? ? ? ? GetPlayInfoRequest request = new GetPlayInfoRequest();

? ? ? ? //向request對象里面設(shè)置視頻id

? ? ? ? request.setVideoId("7d92de4882d44b24985862e5c368b195");

? ? ? ? //調(diào)用初始化對象里面的方法症昏,傳遞request,獲取數(shù)據(jù)

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

? ? ? ? List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

? ? ? ? //播放地址

? ? ? ? for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) {

? ? ? ? ? ? System.out.print("PlayInfo.PlayURL = " + playInfo.getPlayURL() + "\n");

? ? ? ? }

? ? ? ? //Base信息

? ? ? ? System.out.print("VideoBase.Title = " + response.getVideoBase().getTitle() + "\n");

? ? }

}

https://help.aliyun.com/document_detail/61064.html?spm=a2c4g.11186623.6.910.65487bdcUJ2Djx

4随闽、獲取視頻播放憑證

public class VodSdkTest {

? ? public static void main(String[] args) throws Exception {

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

? ? ? ? //初始化客戶端、請求對象和相應(yīng)對象

? ? ? ? DefaultAcsClient client = InitObject.initVodClient("LTAI4GKJXUR4VuFMrtnzzWBG","yiEPUWzpivYpYTG8o0tVW4UFqE2EQh");

? ? ? ? GetVideoPlayAuthResponse response = new GetVideoPlayAuthResponse();

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

? ? ? ? request.setVideoId("7d92de4882d44b24985862e5c368b195");

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

? ? ? ? System.out.print("PlayAuth = " + response.getPlayAuth() + "\n");

? ? }

}


03-文件上傳測試

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

一肝谭、安裝SDK

1掘宪、配置pom

2、安裝非開源jar包

在本地Maven倉庫中安裝jar包:

下載視頻上傳SDK攘烛,解壓魏滚,命令行進入lib目錄,執(zhí)行以下代碼

mvn install:install-file-DgroupId=com.aliyun-DartifactId=aliyun-sdk-vod-upload-Dversion=1.4.11-Dpackaging=jar-Dfile=aliyun-java-vod-upload-1.4.11.jar

把該文件下的生成的包復制到工作目錄下:

然后在pom中引入jar包医寿,版本號已經(jīng)在整個項目的pom中指定

????????<dependency>

? ? ? ? ? ? <groupId>com.aliyun</groupId>

? ? ? ? ? ? <artifactId>aliyun-sdk-vod-upload</artifactId>

? ? ? ? </dependency>

二栏赴、測試

1、創(chuàng)建測試文件

2靖秩、測試本地文件上傳

public class VodSdkTest {

? ? public static void main(String[] args) throws Exception {

? ? ? ? //本地文件上傳接口

? ? ? ? String accessKeyId = "LTAI4GKJXUR4VuFMrtnzzWBG";

? ? ? ? String accessKeySecret = "yiEPUWzpivYpYTG8o0tVW4UFqE2EQh";

? ? ? ? String title = "6 - What If I Want to Move Faster-upload by sdk";//上傳之后文件名稱

? ? ? ? String fileName = "E:/6 - What If I Want to Move Faster.mp4";//本地文件路徑和名稱

? ? ? ? UploadVideoRequest request = new UploadVideoRequest(accessKeyId, accessKeySecret, title, fileName);

? ? ? ? /* 可指定分片上傳時每個分片的大小须眷,默認為2M字節(jié) */

? ? ? ? request.setPartSize(2 * 1024 * 1024L);

? ? ? ? /* 可指定分片上傳時的并發(fā)線程數(shù),默認為1沟突,(注:該配置會占用服務(wù)器CPU資源花颗,需根據(jù)服務(wù)器情況指定)*/

? ? ? ? request.setTaskNum(1);

? ? ? ? UploadVideoImpl uploader = new UploadVideoImpl();

? ? ? ? UploadVideoResponse response = uploader.uploadVideo(request);

? ? ? ? if (response.isSuccess()) {

? ? ? ? ? ? System.out.print("VideoId=" + response.getVideoId() + "\n");

? ? ? ? } else {

? ? ? ? ? ? /* 如果設(shè)置回調(diào)URL無效,不影響視頻上傳惠拭,可以返回VideoId同時會返回錯誤碼扩劝。其他情況上傳失敗時庸论,VideoId為空,此時需要根據(jù)返回錯誤碼分析具體錯誤原因 */

? ? ? ? ? ? System.out.print("VideoId=" + response.getVideoId() + "\n");

? ? ? ? ? ? System.out.print("ErrorCode=" + response.getCode() + "\n");

? ? ? ? ? ? System.out.print("ErrorMessage=" + response.getMessage() + "\n");

? ? ? ? }

? ? }



3 整合阿里云視頻點播

01-視頻點播微服務(wù)的創(chuàng)建

一棒呛、創(chuàng)建視頻點播微服務(wù)

1聂示、創(chuàng)建微服務(wù)模塊

Artifact:service-vod

2、引入依賴

3簇秒、application.properties

# 服務(wù)端口

server.port=8003

# 服務(wù)名

spring.application.name=service-vod

# 環(huán)境設(shè)置:dev鱼喉、test、prod

spring.profiles.active=dev

#阿里云 vod

#不同的服務(wù)器趋观,地址不同

aliyun.vod.file.keyid=LTAI4GKJXUR4VuFMrtnzzWBG

aliyun.vod.file.keysecret=yiEPUWzpivYpYTG8o0tVW4UFqE2EQh

4扛禽、啟動類

VodApplication.java

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//在vod中,我們只是做視頻的相關(guān)操作皱坛,并沒有操作數(shù)據(jù)庫

@ComponentScan(basePackages={"com.atguigu"})//包的掃描規(guī)則

public class VodApplication {

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(VodApplication.class,args);

? ? }

}

二编曼、整合阿里云vod實現(xiàn)視頻上傳

1、創(chuàng)建常量類

ConstantPropertiesUtil.java

@Component

public class ConstantPropertiesUtil implements InitializingBean {

? ? @Value("${aliyun.vod.file.keyid}")

? ? private String keyId;

? ? @Value("${aliyun.vod.file.keysecret}")

? ? private String keySecret;


? ? //定義公開靜態(tài)常量

? ? public static String ACCESS_KEY_ID;

? ? public static String ACCESS_KEY_SECRET;

? ? @Override

? ? public void afterPropertiesSet() throws Exception {

? ? ? ? ACCESS_KEY_ID = keyId;

? ? ? ? ACCESS_KEY_SECRET = keySecret;

? ? }

}

2剩辟、創(chuàng)建controller掐场、service

VodController.java

@Api(description="阿里云視頻點播微服務(wù)")

@RestController

@RequestMapping("/eduvod/video")

@CrossOrigin

public class VodController {

? ? @Autowired

? ? private VodService vodService;

? ? //上傳視頻到阿里云

? ? @PostMapping("uploadAlyiVideo")

? ? public R uploadAlyiVideo(MultipartFile file){ //MultipartFile對象獲取上傳的文件

? ? ? ? //上傳視頻返回視頻的id

? ? ? ? String videoId = vodService.uploadVideoAly(file);

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

? ? }

}

VodService.java

package com.atguigu.vod.service;

import org.springframework.web.multipart.MultipartFile;

public interface VodService {

? ? String uploadVideoAly(MultipartFile file);

}

VodServiceImpl.java

@Service

public class VodServiceImpl implements VodService {

? ? @Override

? ? public String uploadVideoAly(MultipartFile file) {

? ? ? ? try {

? ? ? ? ? ? //如01.MP4

? ? ? ? ? ? String fileName = file.getOriginalFilename();

? ? ? ? ? ? //01

? ? ? ? ? ? String title = fileName.substring(0,fileName.lastIndexOf("."));

? ? ? ? ? ? InputStream inputStream = file.getInputStream();

? ? ? ? ? ? UploadStreamRequest request = new UploadStreamRequest(ConstantPropertiesUtil.ACCESS_KEY_ID, ConstantPropertiesUtil.ACCESS_KEY_SECRET, title, fileName, inputStream);

? ? ? ? ? ? UploadVideoImpl uploader = new UploadVideoImpl();

? ? ? ? ? ? UploadStreamResponse response = uploader.uploadStream(request);

? ? ? ? ? ? String videoId = response.getVideoId(); //請求視頻點播服務(wù)的請求ID

? ? ? ? ? ? if (response.isSuccess()) {

? ? ? ? ? ? ? ? videoId = response.getVideoId();

? ? ? ? ? ? } else { //如果設(shè)置回調(diào)URL無效,不影響視頻上傳贩猎,可以返回VideoId同時會返回錯誤碼刻肄。其他情況上傳失敗時,VideoId為空融欧,此時需要根據(jù)返回錯誤碼分析具體錯誤原因

? ? ? ? ? ? ? ? videoId = response.getVideoId();

? ? ? ? ? ? }

? ? ? ? ? ? return videoId;

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? return null;

? ? ? ? }

? ? }

}

3、啟動后端vod微服務(wù)

4卦羡、swagger測試?

org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.

解決辦法:在配置文件中添加如下配置

# 最大上傳單個文件大性肓蟆:默認1M

spring.servlet.multipart.max-file-size=1024MB

# 最大置總上傳的數(shù)據(jù)大小 :默認10M

spring.servlet.multipart.max-request-size=1024MB

測試:


02-前端整合視頻上傳

一、配置nginx反向代理

將接口地址加入nginx配置:

? ? ?? location ~ /eduvod/ {

? ? ? ? ? ? proxy_pass http://localhost:8003;

? ? ? ? }

配置nginx上傳文件大小绿饵,否則上傳時會有?413 (Request Entity Too Large)?異常:

打開nginx主配置文件nginx.conf欠肾,找到http{},添加:

client_max_body_size 1024m;

重啟nginx:

nginx.exe -s stop

二拟赊、前端實現(xiàn)

1刺桃、數(shù)據(jù)定義

fileList: [],//上傳文件列表

BASE_API: process.env.BASE_API // 接口API地址

2、整合上傳組件

?????????<el-form-item?label="上傳視頻">

????????????????<el-upload

????????????????????:on-success="handleVodUploadSuccess"

????????????????????:on-remove="handleVodRemove"

????????????????????:before-remove="beforeVodRemove"

????????????????????:on-exceed="handleUploadExceed"

????????????????????:file-list="fileList"

????????????????????:action="BASE_API+'/eduvod/video/uploadAlyiVideo'"

????????????????????:limit="1"

????????????????????class="upload-demo">

????????????????<el-button?size="small"?type="primary">上傳視頻</el-button>

????????????????<el-tooltip?placement="right-end">

????????????????????<div?slot="content">最大支持1G吸祟,<br>

????????????????????????支持3GP瑟慈、ASF、AVI屋匕、DAT葛碧、DV、FLV过吻、F4V进泼、<br>

????????????????????????GIF、M2T、M4V乳绕、MJ2团秽、MJPEG、MKV歌亲、MOV妓布、MP4、<br>

????????????????????????MPE呻纹、MPG堆生、MPEG、MTS雷酪、OGG淑仆、QT、RM哥力、RMVB蔗怠、<br>

????????????????????????SWF、TS吩跋、VOB寞射、WMV、WEBM?等視頻格式上傳</div>

????????????????????<i?class="el-icon-question"/>

????????????????</el-tooltip>

????????????????</el-upload>

????????????</el-form-item>

3锌钮、方法定義

//在上傳接口中桥温,上傳成功后返回視頻id(videoId)

//上傳成功之后得到視頻id,最終把視頻id加到數(shù)據(jù)庫中

?handleVodUploadSuccess(response,?file,?fileList){

????????????//上傳id名稱賦值

????????????this.video.videoSourceId?=?response.data.videoId

????????},

//上傳之前:設(shè)置一個提示

handleUploadExceed(files,?fileList){

????????????this.$message.warning('想要重新上傳視頻梁丘,請先刪除已上傳的視頻')

},

測試:

將視頻名稱存儲到數(shù)據(jù)庫表:

定義:

videoOriginalName:'',?//視頻名稱

?//上傳視頻成功調(diào)用的方法侵浸,返回視頻id因此需要response

????????handleVodUploadSuccess(response,?file,?fileList){

????????????//上傳id名稱賦值

????????????this.video.videoSourceId?=?response.data.videoId

????????????//上傳視頻名稱賦值

????????????this.video.videoOriginalName?=?file.name

????????},

測試:


03-刪除云端視頻

文檔:服務(wù)端SDK->Java SDK->媒資管理

https://help.aliyun.com/document_detail/61065.html?spm=a2c4g.11186623.6.831.654b3815cIxvma#h2--div-id-deletevideo-div-7

一、后端

VodController.java

//根據(jù)視頻id刪除阿里云視頻

? ? @DeleteMapping("removeAlyVideo/{id}")

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

? ? ? ? try {

? ? ? ? ? ? //初始化對象

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

? ? ? ? ? ? //創(chuàng)建刪除視頻request對象

? ? ? ? ? ? DeleteVideoRequest request = new DeleteVideoRequest();

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

? ? ? ? ? ? request.setVideoIds(id);

? ? ? ? ? ? //調(diào)用初始化對象的方法實現(xiàn)刪除

? ? ? ? ? ? client.getAcsResponse(request);

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

? ? ? ? } catch (ClientException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? throw new GuliException(20001,"刪除視頻失敗");

? ? ? ? }

? ? }

二氛谜、前端

1掏觉、定義api

api/edu/video.js

????//根據(jù)視頻id刪除阿里云視頻

????deleteAliyunvod(id){

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

????????????url:`/eduvod/video/removeAlyVideo/${id}`,

????????????method:'delete'

????????})

????}

2、組件方法

views/edu/course/chapter.vue

????handleVodRemove(file,?fileList){

????????????video.deleteAliyunvod(this.video.videoSourceId)

?????????????????.then(response=>{

??????????????????????this.$message({

????????????????????????type:?'success',??

????????????????????????message:?"刪除成功"

????????????????????})

?????????????????})?

????????},

????????beforeVodRemove(file,?fileList){

?????????????return?this.$confirm(`確定移除?${file.name}值漫?`)

????????},

????????視頻點擊刪除澳腹,但是數(shù)據(jù)庫中還是把視頻名稱和id加入進來,這是因為在過程中先做了上傳杨何,上傳之后視頻名稱和id賦值到video對象中了酱塔,我們做的刪除只是刪除了阿里云中的視頻,但是video中的數(shù)據(jù)還存在晚吞。

????????解決:

??handleVodRemove(file,?fileList){

????????????video.deleteAliyunvod(this.video.videoSourceId)

?????????????????.then(response=>{

??????????????????????this.$message({

????????????????????????type:?'success',??

????????????????????????message:?"刪除成功"

????????????????????})

????????????????????//把文件列表清空

????????????????????this.fileList?=?[]

????????????????????//把video視頻id和視頻名稱值清空

????????????????????//上傳視頻id賦值

????????????????????this.video.videoSourceId?=?''

????????????????????//上傳視頻名稱賦值

????????????????????this.video.videoOriginalName?=?''

?????????????????})?

????????},


04-視頻文件回顯


???????//方法中需要小節(jié)id

????????openEditVideo(videoId){

????????????//彈框

????????????this.dialogVideoFormVisible?=?true

????????????//調(diào)用接口

????????????video.getVideo(videoId)

????????????????.then(response=>{

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

????????????????????//?this.fileList?=?[{'name':this.video.videoOriginalName}]

????????????????})

????????},


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末延旧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子槽地,更是在濱河造成了極大的恐慌迁沫,老刑警劉巖芦瘾,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異集畅,居然都是意外死亡近弟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門挺智,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祷愉,“玉大人,你說我怎么就攤上這事赦颇《” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵媒怯,是天一觀的道長订讼。 經(jīng)常有香客問我,道長扇苞,這世上最難降的妖魔是什么欺殿? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮鳖敷,結(jié)果婚禮上脖苏,老公的妹妹穿的比我還像新娘。我一直安慰自己定踱,他們只是感情好棍潘,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崖媚,像睡著了一般蜒谤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上至扰,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音资锰,去河邊找鬼敢课。 笑死,一個胖子當著我的面吹牛绷杜,可吹牛的內(nèi)容都是我干的直秆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼鞭盟,長吁一口氣:“原來是場噩夢啊……” “哼圾结!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起齿诉,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤筝野,失蹤者是張志新(化名)和其女友劉穎晌姚,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歇竟,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡挥唠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了焕议。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宝磨。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盅安,靈堂內(nèi)的尸體忽然破棺而出唤锉,到底是詐尸還是另有隱情,我是刑警寧澤别瞭,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布窿祥,位于F島的核電站,受9級特大地震影響畜隶,放射性物質(zhì)發(fā)生泄漏壁肋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一籽慢、第九天 我趴在偏房一處隱蔽的房頂上張望浸遗。 院中可真熱鬧,春花似錦箱亿、人聲如沸跛锌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽髓帽。三九已至,卻和暖如春脑豹,著一層夾襖步出監(jiān)牢的瞬間郑藏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工瘩欺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留必盖,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓俱饿,卻偏偏與公主長得像歌粥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拍埠,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350