@RestController
@RequestMapping("/eduservice/course")
@CrossOrigin
public class EduCourseController {
@Autowired
private EduCourseService courseService;
// 课程最终发布
// 修改课程状态
@PostMapping("publishCourse/{id}")
public R publishCourse(@PathVariable String id) {
EduCourse eduCourse = new EduCourse();
eduCourse.setId(id);
eduCourse.setStatus("Normal"); // 设置课程发布状态
courseService.updateById(eduCourse);
return R.ok();
}
}
// src\api\edu\course.js
import request from '@/utils/request'
export default {
// 课程最终发布
publishCourse(id) {
return request({
url: '/eduservice/course/publishCourse/' + id,
method: 'post',
})
}
}
// src\views\edu\course\publish.vue
<script>
import course from '@/api/edu/course'
export default {
methods: {
publish() {
course.publishCourse(this.courseId)
.then(response => {
// 提示
this.$message({
type: 'success',
message: '课程发布成功!'
});
// 跳转课程列表页面
this.$router.push({ path: '/course/list' })
})
}
}
}
script>
@RestController
@RequestMapping("/eduservice/course")
@CrossOrigin
public class EduCourseController {
@Autowired
private EduCourseService courseService;
// 课程列表 基本实现
// TODO 完善条件查询带分页
@GetMapping
public R getCourseList() {
List<EduCourse> list = courseService.list(null);
return R.ok().data("list",list);
}
}
// src\api\edu\course.js
import request from '@/utils/request'
export default {
// TODO 课程列表
getListCourse() {
return request({
url: '/eduservice/course',
method: 'get'
})
}
}
// src\views\edu\course\list.vue
<template>
<div class="app-container">
课程列表
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-input v-model="courseQuery.title" placeholder="课程名称"/>
el-form-item>
<el-form-item>
<el-select v-model="courseQuery.status" clearable placeholder="课程状态">
<el-option :value="Normal" label="已发布"/>
<el-option :value="Draft" label="未发布"/>
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
:data="list"
border
fit
highlight-current-row>
<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 prop="title" label="课程名称" width="80" />
<el-table-column label="课程状态" width="80">
<template slot-scope="scope">
{{ scope.row.status==='Normal'?'已发布':'未发布' }}
template>
el-table-column>
<el-table-column prop="lessonNum" label="课时数" />
<el-table-column prop="gmtCreate" label="添加时间" width="160"/>
<el-table-column prop="viewCount" label="浏览数量" width="60" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<router-link :to="'/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">编辑课程基本信息el-button>
router-link>
<router-link :to="'/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">编辑课程大纲信息el-button>
router-link>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(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>
<script>
// 引入调用course.js文件
import course from '@/api/edu/course'
export default {
// 写核心代码位置
data() { // 定义变量和初始值
return {
list: null, // 查询之后接口返回的集合
page: 1, // 当前页
limit: 10, // 每页记录数
total: 0, // 总记录数
courseQuery: {} // 条件封装对象
}
},
created() { // 页面渲染之前执行,一般调用methods定义的方法
this.getList()
},
methods: { // 创建具体的方法,调用teacher.js定义的方法
// 讲师列表的方法
getList() {
course.getListCourse()
.then(response => { // 请求成功
// response 接口返回的数据
// console.log(response);
this.list= response.data.list
})
},
resetData() { // 清空的方法
// 表单输入项数据清空
this.courseQuery = {}
// 查询所有讲师数据
this.getList()
},
}
}
script>
@RestController
@RequestMapping("/eduservice/course")
@CrossOrigin
public class EduCourseController {
@Autowired
private EduCourseService courseService;
// 删除课程
@DeleteMapping("{courseId}")
public R deleteCourse(@PathVariable String courseId) {
courseService.removeCourse(courseId);
return R.ok();
}
}
@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {
// 课程描述注入
@Autowired
private EduCourseDescriptionService courseDescriptionService;
// 注入小节和章节service
@Autowired
private EduVideoService eduVideoService;
@Autowired
private EduChapterService eduChapterService;
// 删除课程
@Override
public void removeCourse(String courseId) {
// 1.根据课程id删除小节
eduVideoService.removeVideoByCourseId(courseId);
// 2.根据课程id删除章节
eduChapterService.removeChapterByCourseId(courseId);
// 3.根据课程id删除描述
courseDescriptionService.removeById(courseId);
// 4.根据课程id删除课程本身
int result = baseMapper.deleteById(courseId);
if(result == 0) { // 失败返回
throw new LemonException(20001, "删除失败");
}
}
}
public interface EduVideoService extends IService<EduVideo> {
void removeVideoByCourseId(String courseId);
}
@Service
public class EduVideoServiceImpl extends ServiceImpl<EduVideoMapper, EduVideo> implements EduVideoService {
// 根据课程id删除小节
// TODO 删除小节,删除对应视频文件
@Override
public void removeVideoByCourseId(String courseId) {
QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();
wrapper.eq("course_id", courseId);
baseMapper.delete(wrapper);
}
}
public interface EduChapterService extends IService<EduChapter> {
// 根据课程id删除章节
void removeChapterByCourseId(String courseId);
}
@Service
public class EduChapterServiceImpl extends ServiceImpl<EduChapterMapper, EduChapter> implements EduChapterService {
@Autowired
private EduVideoService videoService; // 注入小节service
// 根据课程id删除章节
@Override
public void removeChapterByCourseId(String courseId) {
QueryWrapper<EduChapter> wrapper = new QueryWrapper<>();
wrapper.eq("course_id", courseId);
baseMapper.delete(wrapper);
}
}
创建视频点播微服务
<dependencies>
<dependency>
<groupId>com.aliyungroupId>
<artifactId>aliyun-java-sdk-coreartifactId>
dependency>
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
dependency>
<dependency>
<groupId>com.aliyungroupId>
<artifactId>aliyun-java-sdk-vodartifactId>
dependency>
<dependency>
<groupId>com.aliyungroupId>
<artifactId>aliyun-sdk-vod-uploadartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
dependency>
<dependency>
<groupId>org.jsongroupId>
<artifactId>jsonartifactId>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
dependency>
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
dependency>
dependencies>
测试
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 class TestVod {
public static void main(String[] args) throws Exception{
// 1.根据视频id获取视频播放地址
// 创建初始化对象
DefaultAcsClient client = InitObject.initVodClient("秘钥", "密码");
// 创建获取视频地址request和response
GetPlayInfoRequest request = new GetPlayInfoRequest();
GetPlayInfoResponse response = new GetPlayInfoResponse();
// 向request对象里面设置视频id
request.setVideoId("7272bc8cc64344c2a3209c15881712fe");
// 调用初始化对象里面的方法,传递request,获取数据
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");
}
}
public class TestVod {
public static void main(String[] args) throws Exception{
// 2.根据视频id获取视频播放凭证
// 创建初始化对象
// 创建初始化对象
DefaultAcsClient client = InitObject.initVodClient("秘钥", "密码");
// 创建获取视频凭证request和response
GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
GetVideoPlayAuthResponse response = new GetVideoPlayAuthResponse();
// 向request对象里面设置视频id
request.setVideoId("7272bc8cc64344c2a3209c15881712fe");
// 调用初始化对象里面的方法,传递request,获取数据
response = client.getAcsResponse(request);
System.out.println("platauth: " + response.getPlayAuth());
}
}
public class TestVod {
public static void main(String[] args){
String accessKeyId = "秘钥";
String accessKeySecret = "密码";
String title = "3 - How Does Project Submission Work - upload by sdk"; // 上传之后文件的名称
String fileName = "D:/abc/3 - How Does Project Submission Work.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);
System.out.print("RequestId=" + response.getRequestId() + "\n"); //请求视频点播服务的请求ID
if (response.isSuccess()) {
System.out.print("VideoId=" + response.getVideoId() + "\n");
} 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");
}
}
}
创建微服务模块(同上)
# 服务端口
server.port=8003
# 服务名
spring.application.name=service-vod
# 环境设置:dev、test、prod
spring.profiles.active=dev
#阿里云 vod
#不同的服务器,地址不同
aliyun.vod.file.keyid=your accessKeyId
aliyun.vod.file.keysecret=your accessKeySecret
# 最大上传单个文件大小:默认1M
spring.servlet.multipart.max-file-size=1024MB
# 最大置总上传的数据大小 :默认10M
spring.servlet.multipart.max-request-size=1024MB
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = {"com.alex"})
public class VodApplication {
public static void main(String[] args) {
SpringApplication.run(VodApplication.class, args);
}
}
整合阿里云vod实现视频上传
// 创建常量类
@Component
public class ConstantVodUtils implements InitializingBean {
@Value("${aliyun.vod.file.keyid}")
private String keyid;
@Value("${aliyun.vod.file.keysecret}")
private String keysecret;
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;
}
}
@RestController
@RequestMapping("/eduvod/video")
@CrossOrigin
public class VodController {
@Autowired
private VodService vodService;
// 上传视频到阿里云
@PostMapping("uploadAlyVideo")
public R uploadAlyVideo(MultipartFile file) {
// 返回上传视频id
String videoId = vodService.uploadVideoAly(file);
return R.ok().data("videoId", videoId);
}
}
public interface VodService {
String uploadVideoAly(MultipartFile file);
}
@Service
public class VodServiceImpl implements VodService {
@Override
public String uploadVideoAly(MultipartFile file) {
try {
// accessKeyId,accessKeySecret
// fileName:上传文件原始名称
// 01.mp4
String fileName = file.getOriginalFilename();
// title:上传之后显示名称
String title = fileName.substring(0, fileName.lastIndexOf("."));
// inputStream:上传文件输入流
InputStream inputStream = file.getInputStream();
UploadStreamRequest request = new UploadStreamRequest(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET, title, fileName, inputStream);
UploadVideoImpl uploader = new UploadVideoImpl();
UploadStreamResponse response = uploader.uploadStream(request);
String videoId = null;
if (response.isSuccess()) {
videoId = response.getVideoId();
} else {
videoId = response.getVideoId();
}
return videoId;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = {"com.alex"})
public class VodApplication {
public static void main(String[] args) {
SpringApplication.run(VodApplication.class, args);
}
}
配置nginx反向代理
location ~ /vod/ {
proxy_pass http://localhost:8003;
}
client_max_body_size 1024m;
nginx -s reload
# PS:停止nginx命令
nginx -s stop
前端实现(src\views\edu\course\chapter.vue)
fileList: [],//上传文件列表
BASE_API: process.env.BASE_API // 接口API地址
<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/uploadAlyVideo'"
: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>
// 上传视频成功调用的方法
handleVodUploadSuccess(response, file, fileList) {
// 上传视频id赋值
this.video.videoSourceId = response.data.videoId
// 上传视频名称赋值
this.video.videoOriginalName = file.name
},
handleUploadExceed() {
this.$message.warning('想要重新上传视频,请先删除已上传的视频')
},