日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2022年最新《谷粒学院开发教程》:5 - 章节管理

發布時間:2024/3/12 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2022年最新《谷粒学院开发教程》:5 - 章节管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
資料
資料地址
后臺管理系統目錄前臺展示系統目錄
1 - 構建工程篇7 - 渲染前臺篇
2 - 前后交互篇8 - 前臺登錄篇
3 - 文件上傳篇9 - 前臺課程篇
4 - 課程管理篇10 - 前臺支付篇
5 - 章節管理篇11 - 統計分析篇
6 - 微服務治理12 - 項目完結篇

目錄

  • 一、課程章節增刪改查
    • 1.1、后端接口
    • 1.2、前端實現
    • 1.3、添加章節
    • 1.4、修改章節
    • 1.5、刪除章節
  • 二、課程章節小節功能
    • 2.1、后端接口
    • 2.2、前端實現
    • 2.3、添加小節
    • 2.4、刪除小節
    • 2.5、修改小節
  • 三、課程發布信息預覽
    • 3.1、后端接口
    • 3.3、前端實現
  • 四、課程發布
    • 4.1、后端接口
    • 4.2、前端頁面
  • 五、課程列表
    • 5.1、后端接口
    • 5.2、前端實現
  • 六、課程刪除
    • 6.1、后端接口
    • 6.2、前端實現
  • 七、編輯基本信息及大綱
  • 八、阿里云視頻點播
    • 8.1、簡介
    • 8.2、使用
  • 九、使用服務端SDK
    • 9.1、簡介
    • 9.2、獲取視頻
    • 9.3、上傳視頻
  • 十、視頻點播微服務
    • 10.1、后端接口
    • 10.2、前端實現
    • 10.3、視頻刪除


一、課程章節增刪改查

1.1、后端接口

@Api(tags = "章節模塊") @CrossOrigin @RestController @RequestMapping("/eduservice/chapter") public class EduChapterController {@Autowiredprivate EduChapterService eduChapterService;@AutowiredEduCourseService eduCourseService;// 添加章節@PostMapping("addChapter")public R addChapter(@RequestBody EduChapter eduChapter) {eduChapterService.save(eduChapter);return R.ok();}// 根據章節id查詢@GetMapping("getChapter/{chapterId}")public R getChapter(@PathVariable String chapterId) {EduChapter eduChapter = eduChapterService.getById(chapterId);return R.ok().data("chapter", eduChapter);}// 修改章節@PostMapping("updateChapter")public R updateChapter(@RequestBody EduChapter eduChapter) {eduChapterService.updateById(eduChapter);return R.ok();}// 刪除章節 若存在小節則不可刪除@DeleteMapping("deleteById/{chapterId}")public R deleteById(@PathVariable String chapterId) {boolean flag = eduChapterService.deleteChapter(chapterId);if (flag) {return R.ok();} else {return R.error();}}} @Override public boolean deleteChapter(String chapterId) {QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();wrapper.eq("chapter_id", chapterId);int count = eduVideoService.count(wrapper);if (count > 0) {throw new LaptoyException(20001, "還有小節數據,不能刪除");} else {return this.removeById(chapterId);} }

1.2、前端實現

1、頁面代碼

<template><div class="app-container"><h2 style="text-align: center">發布新課程</h2><!-- 步驟條 --><el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;"><el-step title="填寫課程基本信息" /><el-step title="創建課程大綱" /><el-step title="最終發布" /></el-steps><!-- 章節數據折疊面板 --><el-collapse accordion v-for="chapter in chapterVideoList" :key="chapter.id"><!-- 按鈕組 --><el-button-group><el-button type="primary" size="mini" icon="el-icon-circle-plus">添加小節</el-button><el-button type="primary" size="mini" icon="el-icon-edit" @click="openEditChapter(chapter.id)"></el-button><el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(chapter.id)"></el-button></el-button-group><!-- 小節數據 --><el-collapse-item :title=chapter.title><div v-for="video in chapter.children" :key="video.id">{{ video.title }}<span class="acts"><el-button type="text">編輯</el-button><el-button type="text">刪除</el-button></span></div></el-collapse-item></el-collapse><!-- 底部按鈕 --><el-form label-width="120px"><el-form-item><el-button @click="dialogChapterFormVisible=true">添加章節</el-button><el-button @click="previous">上一步</el-button><el-button :disabled="saveBtnDisabled" type="primary" @click="next">下 一步</el-button></el-form-item></el-form><!-- 添加或修改章節彈框 --><el-dialog :visible.sync="dialogChapterFormVisible" title="添加章節"><el-form :model="chapter" label-width="120px"><el-form-item label="章節標題"><el-input v-model="chapter.title" /></el-form-item><el-form-item label="章節排序"><el-input-number v-model="chapter.sort" :min="0" controls-position="right" /></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogChapterFormVisible = false">取 消</el-button><el-button type="primary" @click="saveOrUpdate">確 定</el-button></div></el-dialog></div> </template> data() {return {dialogChapterFormVisible: false,chapter: {title: "",sort: 0},}; },

稍微優化了頁面


2、創建api - chapter.js

//添加章節 addChapter(chapter) {return request({url: `/eduservice/chapter/addChapter`,method: `post`,data: chapter}) }, //根據id查詢章節 updateChapterById(chapterId) {return request({url: `/eduservice/chapter/getChapter/${chapterId}`,method: `get`,}) }, //修改章節 updateChapter(chapter) {return request({url: `/eduservice/chapter/updateChapter`,method: `post`,data: chapter}) }, //刪除章節 deleteById(chapterId) {return request({url: `/eduservice/chapter/deleteById/${chapterId}`,method: `delete`,}) }

1.3、添加章節

saveChapter() {//設置課程id到chapter對象中,不指定課程id無法正常保存,因為數據庫字段為非空this.chapter.courseId = this.courseIdchapter.addChapter(this.chapter).then((resp) => {this.dialogChapterFormVisible = false;this.$message({message: "添加章節成功",type: "success",});this.chapter = {}this.getChapterVideoByCourseId()}); }, saveOrUpdate() {this.saveChapter() },

1.4、修改章節

1、點擊修改章節按鈕根據章節id回顯數據

<el-button type="primary" size="mini" icon="el-icon-edit" @click="openEditChapter(chapter.id)"></el-button>

2、修改方法

// 修改章節彈窗回顯數據 openEditChapter(id) {this.dialogChapterFormVisible = true;chapter.updateChapterById(id).then((resp) => {this.chapter = resp.data.data}) }, // 修改章節 updateChapter(id) {//設置課程id到chapter對象中,不指定課程id無法正常保存,因為數據庫字段為非空this.chapter.courseId = this.courseIdchapter.updateChapter(this.chapter).then((resp) => {this.dialogChapterFormVisible = false;this.$message({message: "修改章節成功",type: "success",});this.getChapterVideoByCourseId();}); },

1.5、刪除章節

<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(chapter.id)"></el-button> // 刪除章節 removeById(chapterId) {this.$confirm("此操作將永久刪除章節信息, 是否繼續?", "提示", {confirmButtonText: "確定",cancelButtonText: "取消",type: "warning",}).then(() => {chapter.deleteById(chapterId).then((resp) => {this.$message({type: "success",message: "刪除成功!",});this.getChapterVideoByCourseId();});}); },

二、課程章節小節功能

2.1、后端接口

@Api(tags = "小節模塊") @RestController @RequestMapping("/eduservice/video") @CrossOrigin //解決跨域問題 public class EduVideoController {@Autowiredprivate EduVideoService eduVideoService;//添加小節@PostMapping("/addVideo")public R addVideo(@RequestBody EduVideo eduVideo) {eduVideoService.save(eduVideo);return R.ok();}//刪除小節// TODO 后面這個方法需要完善,刪除小節的時候,同時也要把視頻刪除@DeleteMapping("/deleteVideo/{id}")public R deleteVideo(@PathVariable String id) {eduVideoService.removeById(id);return R.ok();}//修改小節@PostMapping("/updateVideo")public R updateVideo(@RequestBody EduVideo eduVideo) {eduVideoService.updateById(eduVideo);return R.ok();}//根據小節id查詢@GetMapping("/getVideoById/{videoId}")public R getVideoById(@PathVariable String videoId) {EduVideo eduVideo = eduVideoService.getById(videoId);return R.ok().data("data", eduVideo);} }

2.2、前端實現

1、頁面

<!-- 章節數據折疊面板 --> <el-collapse accordion v-for="chapter in chapterVideoList" :key="chapter.id"><!-- 按鈕組 --><el-button-group><el-button type="primary" size="mini" icon="el-icon-circle-plus" @click="openSaveVideoForm(chapter.id)">添加小節</el-button></el-button-group> </el-collapse><!--添加小節表單--> <el-dialog :visible.sync="dialogVideoFormVisible" title="添加小節"><el-form :model="video" label-width="120px"><el-form-item label="小節標題"><el-input v-model="video.title" /></el-form-item><el-form-item label="小節排序"><el-input-number v-model="video.sort" :min="0" controls-position="right" /></el-form-item><el-form-item label="是否免費"><el-radio-group v-model="video.free"><el-radio :label="true">免費</el-radio><el-radio :label="false">默認</el-radio></el-radio-group></el-form-item><el-form-item label="上傳視頻"><!-- TODO --></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogVideoFormVisible = false">取 消</el-button><el-button :disabled="saveVideoBtnDisabled" type="primary" @click="saveOrUpdateVideo">確 定</el-button></div> </el-dialog> data() {return {saveVideoBtnDisabled: false,dialogVideoFormVisible: false,video: {sort: 0,title: "",free: ""}}; },

2、API - src\api\teacher\video.js

import request from '@/utils/request' //引入已經封裝好的axios 和 攔截器export default {//添加小節addVideo(video) {return request({url: `/eduservice/video/addVideo`,method: `post`,data: video})},//根據id查詢小節getVideoById(videoId) {return request({url: `/eduservice/video/getVideoById/${videoId}`,method: `get`,})},//修改小節updateVideo(video) {return request({url: `/eduservice/video/updateVideo`,method: `post`,data: video})},//刪除小節deleteById(videoId) {return request({url: `/eduservice/video/deleteVideo/${videoId}`,method: `delete`,})}, }

2.3、添加小節

openSaveVideoForm(id) {this.dialogVideoFormVisible = truethis.video.courseId = this.courseIdthis.video.chapterId = id }, saveOrUpdateVideo(){if (this.video.id) {//修改小節} else {//新增小節this.saveVideo();} }, // 添加小節 saveVideo() {video.addVideo(this.video).then((resp) => {this.dialogVideoFormVisible = false;this.$message({message: "添加小節成功",type: "success",});this.video = {}this.getChapterVideoByCourseId();}); },

2.4、刪除小節

<!-- 章節數據折疊面板 --> <el-collapse accordion v-for="chapter in chapterVideoList" :key="chapter.id"><!-- 按鈕組 --><!-- 小節數據 --><el-collapse-item :title=chapter.title><div v-for="video in chapter.children" :key="video.id">{{ video.title }}<span class="acts"><el-button type="text">編輯</el-button><el-button type="text" @click="removeVideo(video.id)">刪除</el-button></span></div></el-collapse-item> </el-collapse> // 刪除小節 removeVideo(id) {this.$confirm("此操作將永久刪除小節信息, 是否繼續?", "提示", {confirmButtonText: "確定",cancelButtonText: "取消",type: "warning",}).then(() => {video.deleteById(id).then((resp) => {this.$message({type: "success",message: "刪除成功!",});this.getChapterVideoByCourseId();});}); },

2.5、修改小節

<!-- 章節數據折疊面板 --> <el-collapse accordion v-for="chapter in chapterVideoList" :key="chapter.id"><!-- 按鈕組 --><!-- 小節數據 --><el-collapse-item :title=chapter.title><div v-for="video in chapter.children" :key="video.id">{{ video.title }}<span class="acts"><el-button type="text" @click="openEditVideoForm(video.id)">編輯</el-button><el-button type="text" @click="removeVideo(video.id)">刪除</el-button></span></div></el-collapse-item> </el-collapse> // 展開編輯表單 openEditVideoForm(id) {this.dialogVideoFormVisible = true;video.getVideoById(id).then((resp) => {this.video = resp.data.data;}); },// 修改小節 updateVideo() {video.updateVideo(this.video).then((resp) => {this.dialogVideoFormVisible = false;this.$message({message: "修改小節成功",type: "success",});this.getChapterVideoByCourseId();}); },// 添加或修改小節 saveOrUpdateVideo() {if (this.video.id) {//修改小節this.updateVideo();} else {//新增小節this.saveVideo();} },

三、課程發布信息預覽

3.1、后端接口

1、創建 VO

@Data public class CoursePublishVo implements Serializable {private static final long serialVersionUID = 1L;private String id;//課程idprivate String title; //課程名稱private String cover; //封面private Integer lessonNum;//課時數private String subjectLevelOne;//一級分類private String subjectLevelTwo;//二級分類private String teacherName;//講師名稱private String price;//價格 ,只用于顯示}

2、控制層

// 根據課程id查詢課程確認信息 @GetMapping("/getPublishCourseInfo/{id}") public R getPublishCourseInfo(@PathVariable String id) {CoursePublishVo publishCourseInfo = eduCourseService.getPublishCourseInfo(id);return R.ok().data("data", publishCourseInfo); }

3、業務層

@Override public CoursePublishVo getPublishCourseInfo(String id) {return eduCourseMapper.getPublishCourseInfo(id); }

4、數據層

CoursePublishVo getPublishCourseInfo(String id); <select id="getPublishCourseInfo" resultType="com.laptoy.eduservice.entity.vo.CoursePublishVo">SELECT ec.id,ec.title,ec.cover,ec.lesson_num AS lessonNum,ec.price,s1.title AS subjectLevelOne,s2.title AS subjectLevelTwo,t.name AS teacherNameFROM edu_course ecLEFT JOIN edu_teacher t ON ec.teacher_id = t.idLEFT JOIN edu_subject s1 ON ec.subject_parent_id = s1.idLEFT JOIN edu_subject s2 ON ec.subject_id = s2.idWHERE ec.id = #{id} </select>

5、將xml文件放到 resources/xml 目錄下,并再YML文件指定

mybatis-plus:mapper-locations: /mapper/*.xml


3.3、前端實現

1、定義API - course.js

//課程確認信息顯示 getPublishCourseInfo(courseId){return request({url:"/eduservice/course/getpublishCourseInfo/"+courseId,method: 'get',}) }

2、頁面

<div class="ccInfo"><img :src="publishCourseInfo.cover" /><div class="main"><h2>{{ publishCourseInfo.title }}</h2><p class="gray"><span>共{{ publishCourseInfo.lessonNum }}課時</span></p><p><span>所屬分類:{{ publishCourseInfo.subjectLevelOne }} : {{ publishCourseInfo.subjectLevelTwo }}</span></p><p>課程講師:{{ publishCourseInfo.teacherName }}</p><h3 class="red">¥{{ publishCourseInfo.price }}</h3></div> </div>

3、方法

export default {data() {return {saveBtnDisabled: false,courseId: '',publishCourseInfo: {},};},methods: {//根據課程id查詢getPublishCourseInfo() {course.getPublishCourseInfo(this.courseId).then(resp => {this.publishCourseInfo = resp.data.dataconsole.log(this.publishCourseInfo)})},// 跳轉到上一步previous() {this.$router.push("/course/chapter/" + this.courseId);},publish() {this.$router.push("/course/list");}},created() {//獲取路由中的id值if (this.$route.params && this.$route.params.id) {this.courseId = this.$route.params.id//調用接口方法根據課程id查詢課程信息this.getPublishCourseInfo()}}, };

4、css

<style scoped> .ccInfo {background: #f5f5f5;padding: 20px;overflow: hidden;border: 1px dashed #ddd;margin-bottom: 40px;position: relative; } .ccInfo img {background: #d6d6d6;width: 500px;height: 278px;display: block;float: left;border: none; } .ccInfo .main {margin-left: 520px; } .ccInfo .main h2 {font-size: 28px;margin-bottom: 30px;line-height: 1;font-weight: normal; } .ccInfo .main p {margin-bottom: 10px;word-wrap: break-word;line-height: 24px;max-height: 48px;overflow: hidden; } .ccInfo .main p {margin-bottom: 10px;word-wrap: break-word;line-height: 24px;max-height: 48px;overflow: hidden; } .ccInfo .main h3 {left: 540px;bottom: 20px;line-height: 1;font-size: 28px;color: #d32f24;font-weight: normal;position: absolute; } </style>

5、測試



四、課程發布

4.1、后端接口

1、控制層

//課程最終發布 //修改課程狀態 @PostMapping("publishCourse/{id}") public R publishCourse(@PathVariable String id){EduCourse eduCourse = new EduCourse();eduCourse.setStatus("Normal"); //設置課程發布狀態eduCourse.setId(id);boolean flag = eduCourseService.updateById(eduCourse);if (flag){return R.ok();}else {return R.error();} }

4.2、前端頁面

1、API

//課程最終發布 publishCourse(courseId) {return request({url: "/eduservice/course/publishCourse/" + courseId,method: 'post',}) }

2、方法

//發布課程 publish() {this.$confirm("你確定要發布此課程, 是否繼續?", "提示", {confirmButtonText: "確定",cancelButtonText: "取消",type: "warning",}).then(() => {course.publishCourse(this.courseId).then((resp) => {this.$message({message: "課程發布成功",type: "success",});//跳轉課程列表頁面this.$router.push({ path: "/course/list" });});}); }

五、課程列表

5.1、后端接口

1、實體類作為模糊查詢條件

@ApiModel(value = "Course查詢對象", description = "課程查詢對象封裝") @Data public class CourseQuery implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "課程名稱,模糊查詢")private String title;@ApiModelProperty(value = "發布狀態 Normal已發布 Draft未發布")private String status; }

2、控制層

//多條件查詢課程帶分頁 @ApiOperation(value = "多條件查詢課程帶分頁") @PostMapping("/pageCourseCondition/{page}/{limit}") public R pageCourseCondition(@ApiParam(name = "page", value = "當前頁碼", required = true) @PathVariable Long page,@ApiParam(name = "limit", value = "每頁記錄數", required = true) @PathVariable Long limit,@RequestBody(required = false) CourseQuery courseQuery) {//通過封裝courseQuery對象來直接傳遞查詢條件//創建分頁page對象Page<EduCourse> pageParam = new Page<>(page, limit);//調用方法實現多條件分頁查詢eduCourseService.pageQuery(pageParam, courseQuery);//獲取查詢到的數據List<EduCourse> records = pageParam.getRecords();//獲取總記錄數long total = pageParam.getTotal();return R.ok().data("total", total).data("data", records); }

3、業務層

@Override public void pageQuery(Page<EduCourse> pageParam, CourseQuery courseQuery) {QueryWrapper<EduCourse> wrapper = new QueryWrapper<>();String title = courseQuery.getTitle();String status = courseQuery.getStatus();if (!StringUtils.isEmpty(title)) {wrapper.like("title", title);//參數1:數據庫字段名; 參數2:模糊查詢的值}if (!StringUtils.isEmpty(status)) {wrapper.eq("status", status);}wrapper.orderByDesc("gmt_create");baseMapper.selectPage(pageParam, wrapper); }

5.2、前端實現

1、頁面

<template><div><!--多條件查詢表單--><el-form :inline="true" class="demo-form-inline" style="margin-left: 20px; margin-top: 12px"><el-form-item label="課程名稱"><el-input v-model="courseQuery.title" placeholder="請輸入名稱"></el-input></el-form-item><el-form-item label="發布狀態"><el-select v-model="courseQuery.status" placeholder="課程狀態"><el-option label="已發布" :value="'Normal'"></el-option><el-option label="未發布" :value="'Draft'"></el-option></el-select></el-form-item><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-item></el-form><!-- 展示表格 --><el-table :data="list" style="width: 100%" height="620" border fit highlight-current-row element-loading-text="數據加載中"><el-table-column prop="date" label="序號" width="70" align="center"><template slot-scope="scope">{{ (page - 1) * limit + scope.$index + 1 }}</template></el-table-column><el-table-column prop="title" label="課程名稱" width="400"></el-table-column><el-table-column label="發布狀態" width="80"><template slot-scope="scope">{{ scope.row.status === "Normal" ? "已發布" : "未發布" }}</template></el-table-column><el-table-column prop="lessonNum" label="課時數" width="100" /><el-table-column prop="gmtCreate" label="添加時間" width="300" /><el-table-column prop="viewCount" label="瀏覽數量" width="200" /><el-table-column label="操作" align="center"><template slot-scope="scope"><router-link :to="'/teacher/edit/' + scope.row.id"><el-button type="primary" size="mini" icon="el-icon-edit" plain>編輯基本信息</el-button></router-link><router-link :to="'/teacher/edit/' + scope.row.id"><el-button type="info" size="mini" icon="el-icon-edit" plain>編輯課程大綱</el-button></router-link><el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(scope.row.id)" plain>點擊刪除課程</el-button></template></el-table-column></el-table><!--分頁組件--><el-pagination background layout="prev, pager, next,total,jumper" :total="total" :page-size="limit" style="padding: 30px 0; text-align: center" :current-page="page" @current-change="getList"></el-pagination></div> </template>

2、API - course.js

//課程列表多條件分頁查詢 //page:當前頁,limit:每頁記錄數,teacherQuery:條件對象 getCourseListPage(page, limit, courseQuery) {return request({url: `/eduservice/course/pageCourseCondition/${page}/${limit}`,method: 'post',data: courseQuery}) },

3、js

import course from "@/api/teacher/course.js";export default {data() {return {list: null, //查詢之后給接口返回的數據裝的集合page: 1, //當前頁limit: 10, //每頁顯示記錄數courseQuery: {}, //條件封裝對象total: 0, //總記錄數};},created() {this.getList();},methods: {getList(page = 1) {this.page = page;course.getCourseListPage(this.page, this.limit, this.courseQuery).then((resp) => {this.list = resp.data.data;this.total = resp.data.total;}) //請求成功.catch((err) => {console.log(err);}); //請求失敗},//清空方法resetData() {//表單輸入項數據清空this.courseQuery = {};//查詢所有課程數據this.getList();},}, };


六、課程刪除

6.1、后端接口

1、控制層

//課程列表中刪除課程方法 @DeleteMapping("/removeCourseById/{id}") public R removeCourseById(@PathVariable String id) {boolean flag = eduCourseService.removeCourse(id);if (flag) {return R.ok();} else {return R.error();} }

2、業務層

//刪除課程 @Transactional @Override public boolean removeCourse(String id) {//1、根據課程id刪除小節eduVideoService.removeVideoByCourseId(id);//2、根據課程id刪除章節部分eduChapterService.removeChapterByCourseId(id);//3、根據課程id刪除課程描述descriptionService.removeById(id);//4、根據課程id刪除課程本身boolean flag = this.removeById(id);if (flag) {return true;} else {throw new LaptoyException(20001, "刪除失敗");} }

3、刪除小節

//根據課程id刪除小節 // TODO 刪除小節,要刪除對應的視頻文件 @Override public void removeVideoByCourseId(String id) {QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();wrapper.eq("course_id", id);baseMapper.delete(wrapper); }

4、刪除章節

@Override public void removeChapterByCourseId(String id) {QueryWrapper<EduChapter> wrapper = new QueryWrapper<>();wrapper.eq("course_id",id);baseMapper.delete(wrapper); }

6.2、前端實現

1、API - course.js

//刪除課程 removeCourseById(courseId) {return request({url: "/eduservice/course/removeCourseById/" + courseId,method: 'delete',}) }

2、方法

<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(scope.row.id)" plain>點擊刪除課程</el-button><script> // 刪除課程 removeById(id) {this.$confirm("此操作將永久刪除該課程記錄, 是否繼續?", "提示", {confirmButtonText: "確定",cancelButtonText: "取消",type: "warning",}).then(() => {course.removeCourseById(id).then((resp) => {this.$message({type: "success",message: "刪除成功!",});this.getList();});}); }, </script>

七、編輯基本信息及大綱

1、頁面

<el-table-column label="操作" align="center"><template slot-scope="scope"><router-link :to="'/course/info/' + scope.row.id"><el-button type="primary" size="mini" icon="el-icon-edit" plain>編輯基本信息</el-button></router-link><router-link :to="'/course/chapter/' + scope.row.id"><el-button type="info" size="mini" icon="el-icon-edit" plain>編輯課程大綱</el-button></router-link><el-button type="danger" size="mini" icon="el-icon-delete" @click="removeById(scope.row.id)" plain>點擊刪除課程</el-button></template> </el-table-column>

2、添加路由

{path: 'info/:id',name: 'EduCourseInfoEdit',component: () => import('@/views/edu/course/info.vue'),meta: { title: '編輯課程基本信息', noCache: true },hidden: true }, {path: 'chapter/:id',name: 'EduCourseChapterEdit',component: () => import('@/views/edu/course/chapter.vue'),meta: { title: '編輯課程大綱', noCache: true },hidden: true },

八、阿里云視頻點播

8.1、簡介

視頻點播( ApsaraVideo for VoD )是集音視頻采集、編輯、上傳、自動化轉碼處理、媒體資源管理、分發加速于一體的一站式音視頻點播解決方案。

開通服務-按流量計費


8.2、使用

1、開啟 存儲管理

2、添加 轉碼模板組

3、上傳視頻


九、使用服務端SDK

9.1、簡介

1、簡介

  • sdk的方式將api進行了進一步的封裝,不用自己創建工具類。
  • 我們可以基于服務端SDK編寫代碼來調用點播API,實現對點播產品和服務的快速操作

2、功能介紹

  • SDK封裝了對API的調用請求和響應,避免自行計算較為繁瑣的 API簽名。
  • 支持所有點播服務的API,并提供了相應的示例代碼。
  • 支持7種開發語言,包括:Java、Python、PHP、.NET、Node.js、Go、C/C++。
  • 通常在發布新的API后,我們會及時同步更新SDK,所以即便您沒有找到對應API的示例代碼,也可以參考舊的示例自行實現調用。

9.2、獲取視頻

1、在 service模塊 新建微服務模塊 service_vod

2、POM

<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.alibaba</groupId><artifactId>fastjson</artifactId> </dependency> <dependency><groupId>org.json</groupId><artifactId>json</artifactId> </dependency> <dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId> </dependency>

3、測試獲取視頻播放地

//初始化類 public class InitObject {public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException {String regionId = "cn-shanghai"; // 點播服務接入區域DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);DefaultAcsClient client = new DefaultAcsClient(profile);return client;}public static void main(String[] args) throws ClientException {//1、根據視頻id獲取視頻播放地址//創建初始化對象DefaultAcsClient cl = InitObject.initVodClient("LTAI5tL5FrVJBuQadij4KRvJ", "Xs7dHUvxCdHLd0K5iFK7NWEbdUN7GG");//創建獲取視頻地址request對象和response對象GetPlayInfoResponse response = new GetPlayInfoResponse();GetPlayInfoRequest request = new GetPlayInfoRequest();//向request對象設置視頻id值request.setVideoId("1a383ac7aa7f4b8197714ca6f886e5be");//調用初始化對象里面的方法傳遞request,獲取數據response = cl.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");//VideoBase.Title = 6 - What If I Want to Move Faster.mp4} } PlayInfo.PlayURL = https://outin-327a9fa3dcae11ecbc2400163e1c8dba.oss-cn-shanghai.aliyuncs.com/sv/60fc3bbf-180ff24e597/60fc3bbf-180ff24e597.mp4?Expires=1653551691&OSSAccessKeyId=LTAIrkwb21KyGjJl&Signature=h0s4mbCbwFd8797gs1KXWxJAUpU%3D VideoBase.Title = 視頻點播控制臺 - Google Chrome 2022-05-25 21-26-51.mp4

3、測試獲取視頻播放憑證(加密視頻)

public static void main(String[] args) throws ClientException {//創建初始化對象DefaultAcsClient cl = InitObject.initVodClient("LTAI5tL5FrVJBuQadij4KRvJ", "Xs7dHUvxCdHLd0K5iFK7NWEbdUN7GG");//創建獲取視頻地址request對象和response對象GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();//向request對象設置視頻id值request.setVideoId("1a383ac7aa7f4b8197714ca6f886e5be");GetVideoPlayAuthResponse response = cl.getAcsResponse(request);//播放憑證System.out.print("PlayAuth = " + response.getPlayAuth() + "\n");//VideoMeta信息System.out.print("VideoMeta.Title = " + response.getVideoMeta().getTitle() + "\n"); } PlayAuth = eyJTZWN1cml0eVRva2VuIjoiQ0FJU2h3TjFxNkZ0NUIyeWZTaklyNWJESGZqVG40eHA0cUM1ZWw3WTFuay9kZUZHdWJmOW1qejJJSDlJZEhWb0FPOGZ2dlUwbTJ0WTdQc1psck1xR3NFZUhoZWJONUlwdDg0T29GMzlKcExGc3QySjZyOEpqc1VZcDVBQTdFYXBzdlhKYXNEVkVmbDJFNVhFTWlJUi8wMGU2TC8rY2lyWXBUWEhWYlNDbFo5Z2FQa09Rd0M4ZGtBb0xkeEtKd3hrMnQxNFVtWFdPYVNDUHdMU2htUEJMVXhtdldnR2wyUnp1NHV5M3ZPZDVoZlpwMXI4eE80YXhlTDBQb1AyVjgxbExacGxlc3FwM0k0U2M3YmFnaFpVNGdscjhxbHg3c3BCNVN5Vmt0eVdHVWhKL3phTElvaXQ3TnBqZmlCMGVvUUFQb3BGcC9YNmp2QWF3UExVbTliWXhncGhCOFIrWGo3RFpZYXV4N0d6ZW9XVE84MCthS3p3TmxuVXo5bUxMZU9WaVE0L1ptOEJQdzQ0RUxoSWFGMElVRTF5R21DQ2QvWDRvZ3VSUDF6N0VwTG9pdjltamNCSHFIeno1c2VQS2xTMVJMR1U3RDBWSUpkVWJUbHphRUpHZ1RTNExmWldJbGNUS0FNOVd1MlBNYXgzYlFGRHI1M3ZzVGJiWHpaYjBtcHR1UG56ZDE0Sk9CS2cxMUtVR29BQlUrY0Q3SXpmeDIvSHJmNXA2cWdSa2UvdDNaMjFPUXF1NkRsSkV3VnpPL2poWngva3JNNitGNWlEK25kT1JHQitZbDJtcTN6SlBnclQxNVdveE5QdXJndy9xbWNib1BWR3dtV01qa3RKOXo0YS90TnA0SWNLRGxKQStvOWFvOWdLbUpPZWJFMnZXT1FicE1LbGFmOER6Q1JCMTl5NmZDUi9qWDFObndub3RTQT0iLCJBdXRoSW5mbyI6IntcIkNJXCI6XCJLenVKNUlCVmRIc0E2eTNlTXFDbS9vYXVOMFZwVFBmYkU0L1VaUUt5c0dhVzc3MjRTWEZQejVyUHlyOGRSN0VaZXVFenpEdndDcDRIY2NoZFlkMjdMVy8yK0R2S1lySXRsVGxlTCtUa0lsZz1cIixcIkNhbGxlclwiOlwiNldQZVY4MkttMDlUbGNGUzVWeDB0SjUxY2pCWEVYb2FuZEk4dEU4OENjWT1cIixcIkV4cGlyZVRpbWVcIjpcIjIwMjItMDUtMjZUMDc6MDQ6NTZaXCIsXCJNZWRpYUlkXCI6XCIxYTM4M2FjN2FhN2Y0YjgxOTc3MTRjYTZmODg2ZTViZVwiLFwiU2lnbmF0dXJlXCI6XCI3Vjhza3RPTnRIK1NBZGV0bVFWRk9CU29vRmc9XCJ9IiwiVmlkZW9NZXRhIjp7IlN0YXR1cyI6Ik5vcm1hbCIsIlZpZGVvSWQiOiIxYTM4M2FjN2FhN2Y0YjgxOTc3MTRjYTZmODg2ZTViZSIsIlRpdGxlIjoi6KeG6aKR54K55pKt5o6n5Yi25Y+wIC0gR29vZ2xlIENocm9tZSAyMDIyLTA1LTI1IDIxLTI2LTUxLm1wNCIsIkNvdmVyVVJMIjoiaHR0cDovL291dGluLTMyN2E5ZmEzZGNhZTExZWNiYzI0MDAxNjNlMWM4ZGJhLm9zcy1jbi1zaGFuZ2hhaS5hbGl5dW5jcy5jb20vMWEzODNhYzdhYTdmNGI4MTk3NzE0Y2E2Zjg4NmU1YmUvc25hcHNob3RzLzNmOTg0ZTE0YjU5OTQxNTM5ODhmNDdiMGI1MDQxMDZhLTAwMDAxLmpwZz9FeHBpcmVzPTE2NTM1NTIxOTYmT1NTQWNjZXNzS2V5SWQ9TFRBSXJrd2IyMUt5R2pKbCZTaWduYXR1cmU9c040UEljem9UbUFPSFJzaHhRTXhMd3pxc09vJTNEIiwiRHVyYXRpb24iOjUuMzE3N30sIkFjY2Vzc0tleUlkIjoiU1RTLk5VdlZCZ3JTSFViUnh4aTJ5anlualZyVngiLCJBY2Nlc3NLZXlTZWNyZXQiOiI3dzRnaWtuSEFlbndCTVYxN2hqbXNqekw4cUZIdlRmZ0tHNjFtWDJ1cVdKcCIsIlJlZ2lvbiI6ImNuLXNoYW5naGFpIiwiQ3VzdG9tZXJJZCI6MTk2MzMzNzIxMTEyMTk2NH0= VideoMeta.Title = 視頻點播控制臺 - Google Chrome 2022-05-25 21-26-51.mp4

9.3、上傳視頻

1、POM - 默認找不到該依賴

<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-sdk-vod-upload</artifactId> </dependency>

2、將資料的 5-lib/aliyun-java-vod-upload-1.4.11.jar 放到maven倉庫bin目錄下并執行如下命令安裝上述依賴

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

3、測試

@Test public void testFileUpload() {String accessKeyId = "LTAI5tL5FrVJBuQadij4KRvJ";String accessKeySecret = "Xs7dHUvxCdHLd0K5iFK7NWEbdUN7GG";String title = "My Upload Video"; //上傳之后文件的名稱String fileName = "C:\\Users\\lapto\\Desktop\\myVideo.mp4"; //本地文件的路徑和名稱UploadVideoRequest request = new UploadVideoRequest(accessKeyId, accessKeySecret, title, fileName);/* 可指定分片上傳時每個分片的大小,默認為2M字節 */request.setPartSize(2 * 1024 * 1024L);/* 可指定分片上傳時的并發線程數,默認為1,(注:該配置會占用服務器CPU資源,需根據服務器情況指定)*/request.setTaskNum(1);UploadVideoImpl uploader = new UploadVideoImpl();UploadVideoResponse response = uploader.uploadVideo(request);if (response.isSuccess()) {System.out.print("VideoId=" + response.getVideoId() + "\n"); //獲取到上傳視頻的id} else {/* 如果設置回調URL無效,不影響視頻上傳,可以返回VideoId同時會返回錯誤碼。其他情況上傳失敗時,VideoId為空,此時需要根據返回錯誤碼分析具體錯誤原因 */System.out.print("VideoId=" + response.getVideoId() + "\n");System.out.print("ErrorCode=" + response.getCode() + "\n");System.out.print("ErrorMessage=" + response.getMessage() + "\n");} }


十、視頻點播微服務

10.1、后端接口

1、service_vod微服務 主啟動類

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @ComponentScan(basePackages = {"com.laptoy"}) //用于掃描swagger public class Service_vod_Main8003 {public static void main(String[] args) {SpringApplication.run(Service_vod_Main8003.class, args);} }

2、YML

# 服務端口號 server.port=8003 # 服務名 spring.application.name=service-vod # nacos注冊中心 spring.cloud.nacos.discovery.server-addr=120.76.55.55:8848 # 環境設置 dev test prod spring.profiles.active=dev # 最大上傳單個文件大小:默認1M spring.servlet.multipart.max-file-size=1024MB # 最大置總上傳的數據大小 :默認10M spring.servlet.multipart.max-request-size=1024MB # 阿里云 vod aliyun.vod.file.keyid=LTAI5tL5FrVJBuQadij4KRvJ aliyun.vod.file.keysecret=Xs7dHUvxCdHLd0K5iFK7NWEbdUN7GG

3、控制層

@RestController @CrossOrigin @RequestMapping("/eduvod/video") public class VodController {@Autowiredprivate VodService vodService;//上傳視頻到阿里云@PostMapping("/uploadAliyunVideo")public R uploadAliyunVideo(MultipartFile file) {//返回上傳視頻的idString videoId = vodService.uploadVideoAliyun(file);return R.ok().data("data", videoId);}}

4、業務層

@Service public class VodServiceImpl implements VodService {@Value("${aliyun.vod.file.keyid}")private String accessKeyId;@Value("${aliyun.vod.file.keysecret}")private String accessKeySecret;@Overridepublic String uploadVideoAliyun(MultipartFile file) {try {//fileName:上傳文件原始名稱String fileName = file.getOriginalFilename();//title:上傳之后顯示名稱String title = fileName.substring(0, fileName.lastIndexOf("."));//inputStream:上傳文件的輸入流InputStream inputStream = file.getInputStream();UploadStreamRequest request = new UploadStreamRequest(accessKeyId, accessKeySecret, title, fileName, inputStream);UploadVideoImpl uploader = new UploadVideoImpl();UploadStreamResponse response = uploader.uploadStream(request);System.out.print("RequestId=" + response.getRequestId() + "\n"); //請求視頻點播服務的請求IDString videoId = null;if (response.isSuccess()) {videoId = response.getVideoId();} else { //如果設置回調URL無效,不影響視頻上傳,可以返回VideoId同時會返回錯誤碼。其他情況上傳失敗時,VideoId為空,此時需要根據返回錯誤碼分析具體錯誤原因videoId = response.getVideoId();}return videoId;} catch (Exception e) {e.printStackTrace();return null;}}}

5、測試


10.2、前端實現

1、nginx.conf 添加配置并重啟 nginx

http { <--文件上傳最大大小 --> client_max_body_size 1024m;server {listen 9001;server_name localhost;...location ~ /eduvod/ {proxy_pass http://localhost:8003;}} }

2、頁面

<el-form-item label="上傳視頻"><el-upload class="upload-demo" :on-success="handleVodUploadSuccess" :before-remove="beforeVodRemove" :file-list="fileList" :action="BASE_API + '/eduvod/video/uploadAliyunVideo'" :limit="1" ><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、js

data() {return {video: {sort: 0,title: "",free: "",videoSourceId: ""},fileList: [], //上傳文件列表BASE_API: process.env.BASE_API, // 接口API地址}; }, methods: {// 上傳成功執行方法handleVodUploadSuccess(response, file, fileList) {this.video.videoSourceId = response.data.data},beforeVodRemove(file, fileList) {return this.$confirm(`確定移除 ${file.name}?`);}, }

10.3、視頻刪除

1、控制層

// 根據視頻id刪除阿里云視頻 @DeleteMapping("/removeAliyunVideoById/{id}") public R removeAliyunVideoById(@PathVariable String id) {vodService.removeAliyunVideoById(id);return R.ok(); }

2、業務層

// 根據id刪除阿里云視頻 @Override public void removeAliyunVideoById(String id) {try {DefaultAcsClient client = initVodClient(accessKeyId, accessKeySecret);DeleteVideoRequest request = new DeleteVideoRequest();request.setVideoIds(id);DeleteVideoResponse response = client.getAcsResponse(request);System.out.println("RequestId = " + response.getRequestId() + "\n");} catch (ClientException e) {throw new LaptoyException(20001, "視頻刪除失敗");} }public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws ClientException {String regionId = "cn-shanghai"; // 點播服務接入區域DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);DefaultAcsClient client = new DefaultAcsClient(profile);return client; }

總結

以上是生活随笔為你收集整理的2022年最新《谷粒学院开发教程》:5 - 章节管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。