3、Service类
//对课程进行分页查询
@Override
public Page <EduCourse> pageQuery(Integer current, Integer limit, CourseQuery courseQuery) {
Page <EduCourse> page = new Page <>(current,limit);
QueryWrapper <EduCourse> wrapper = new QueryWrapper <>();
String title = courseQuery.getTitle();
String subjectId = courseQuery.getSubjectId();
String subjectParentId = courseQuery.getSubjectParentId();
String teacherId = courseQuery.getTeacherId();
//判空,构造查询条件
if(!StringUtils.isEmpty(title)){
wrapper.like("title",title);
}
if(!StringUtils.isEmpty(subjectId)){
wrapper.eq("subject_id",subjectId);
}
if(!StringUtils.isEmpty(subjectParentId)){
wrapper.eq("subject_parent_id",subjectParentId);
}
if(!StringUtils.isEmpty(teacherId)){
wrapper.eq("teacher_id",teacherId);
}
wrapper.orderByDesc("gmt_create");
//进行分页查询
this.baseMapper.selectPage(page, wrapper);//分页查询后自动封装到page中
return page;
}
//根据id删除课程信息
@Override
public void removeCourse(String id) {
//1.删除小节
videoService.removeVideoByCourseId(id);
//2.删除章节
chapterService.removeChapterByCourseId(id);
//3.删除课程描述信息
courseDescriptionService.removeById(id);
//4.删除课程信息
this.baseMapper.deleteById(id);
}
五、课程列表 – 前端
1、定义api接口
//删除课程
removeCourse(id) {
return request({
url: `/eduservice/course/removeCourse/${id}`,
method: 'delete'
})
},
//分页查询课程
pageQuery(current, limit, courseQuery) {
return request({
url: `/eduservice/course/pageQuery/${current}/${limit}`,
method: 'post',
data: courseQuery
})
}
2、 前端页面—list.vue
<template>
<div class="app-container">
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<!-- 所属分类:级联下拉列表 -->
<!-- 一级分类 -->
<el-form-item label="课程类别">
<el-select
v-model="searchObj.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="searchObj.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="searchObj.title" placeholder="课程标题"/>
</el-form-item>
<!-- 讲师 -->
<el-form-item>
<el-select
v-model="searchObj.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="数据加载中"
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="创建时间" align="center">
<template slot-scope="scope">
{{ scope.row.gmtCreate.substr(0, 10) }}
</template>
</el-table-column>
<el-table-column label="发布时间" 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 prop="viewCount" label="播放次数" width="100" align="center" >
<template slot-scope="scope">
{{ scope.row.viewCount }}次
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template slot-scope="scope">
<router-link :to="'/course/info/'+scope.row.id">
<el-button type="text" size="mini" icon="el-icon-edit" >编辑课程信息</el-button>
</router-link>
<router-link :to="'/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" @click="removeCourse(scope.row.id)">删除</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>
3、页面样式
<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>
4、编写前端js
<script>
import course from '@/api/edu/course'
import subject from '@/api/edu/subject'
export default {
data() {
return {
listLoading: false, // 是否显示loading信息
list: null, // 数据列表
total: 0, // 总记录数
page: 1, // 页码
limit: 10, // 每页记录数
searchObj: {
subjectParentId: '',
subjectId: '',
title: '',
teacherId: ''
}, // 查询条件
teacherList: [], // 讲师列表
subjectNestedList: [], // 一级分类列表
subSubjectList: [] // 二级分类列表,
}
},
created() {
this.init()
},
methods: {
//编辑课程大纲
updateChapter(id){
this.$router.push({path:'/course/chapter/'+id})
},
//编辑课程基本信息
updateCourse(id){
this.$router.push({path:'/course/info/'+id})
},
removeCourse(id){
this.$confirm('此操作将永久删除该课程的所有内容,是否继续?','提示',{
confirmButtonText:'确定',
cancelButtonText:'取消',
type:'warning'
}).then(()=>{//点击确定
course.removeCourse(id).then((response)=>{
this.$message({
type:'success',
message:'删除成功!'
})
//回到列表页面
this.getList()
}).catch(()=>{
this.$message({
type:'error',
message:'删除失败!'
})
})
}).catch(() => { // 点击取消
this.$message({
type: 'info',
message: '已取消删除!'
})
})
},
//分页+条件查询
getList(page = 1){//page默认值为1,当使用分页组件时会传入新的page参数
this.page = page
course.pageQuery(this.page,this.limit,this.searchObj).then(response=>{
this.list = response.data.list
this.total = response.data.total
})
},
//查询表单重置方法
resetData(){
this.searchObj = {},
this.subSubjectList = []
},
//当一级分类下拉菜单改变时的方法
subjectLevelOneChanged(id){
// console.log(id);
for(var i = 0;i < this.subjectNestedList.length;i++){
if(this.subjectNestedList[i].id == id){
this.subSubjectList = this.subjectNestedList[i].children
}
}
},
//初始化方法
init(){
//1.查询一级分类
subject.getAllSubject().then(response=>{
this.subjectNestedList = response.data.list
})
//2.查询所有讲师
course.getTeacherList().then(response=>{
this.teacherList = response.data.items
})
//3.查询课程列表
this.getList()
}
}
}
</script>
五、页面效果图

六、阿里云视频点播服务
视频点播(ApsaraVideo for VoD)是集音视频采集、编辑、上传、自动化转码处理、媒体资源管理、分发加速于一体的一站式音视频点播解决方案。
1、开通视频点播
进入阿里云官网:https://www.aliyun.com/,找到视频点播

开通视频点播服务(选择按流量计费)

2、资费说明
https://www.aliyun.com/price/product?spm=a2c4g.11186623.2.12.7fbd59b9vmXVN6#/vod/detail
3、整体流程
使用视频点播实现音视频上传、存储、处理和播放的整体流程如下:

4、视频点播服务的基本使用
完整的参考文档 https://help.aliyun.com/product/29932.html?spm=a2c4g.11186623.6.540.3c356a58OEmVZJ
服务端:后端接口
客户端:浏览器、安卓、ios
API:阿里云提供固定的地址,只需要调用这个固定的地址,向地址传递参数,实现功能。
SDK:sdk对api方式进行封装,更方便使用。之前使用EayExcel调用阿里云提供类或者接口里面的方法实现视频功能。
5、使用Java代码具体使用SDK方式
注意:因为上传视频可以进行加密,加密之后,使用加密之后的地址不能进行视频播放,所以在数据库存储不存地址,而是存储视频id。
(1)在service下创建子模块service_vod模块
POM.xml