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->媒資管理
一、后端
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}]
????????????????})
????????},