阿里云视频点播
视频点播(ApsaraVideo for VoD)是集音视频采集、编辑、上传、自动化转码处理、媒体资源管理、分发加速于一体的一站式音视频点播解决方案。
在service下面新建service_vod模块
依赖
<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>
application.properties
# 服务端口
server.port=8003
# 服务名
spring.application.name=service-vod
# 环境设置:dev、test、prod
spring.profiles.active=dev
#阿里云 vod
#不同的服务器,地址不同
aliyun.vod.file.keyid=
aliyun.vod.file.keysecret=
# 最大上传单个文件大小:默认1M
spring.servlet.multipart.max-file-size=1024MB
# 最大置总上传的数据大小 :默认10M
spring.servlet.multipart.max-request-size=1024MB
启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = {"com.atguigu"})
public class VodApplicaton {
public static void main(String[] args) {
SpringApplication.run(VodApplicaton.class,args);
}
}
阿里云视频点播测试
初始化
import com.aliyun.oss.ClientException;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
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 {
//根据视频id获取视频播放地址
//创建初始化对象
DefaultAcsClient client =InitObject.initVodClient("LTAI5tM89q3RBzKxsDh6b8", "rXd2Ze5DzS9C2izYF6ISoX9fI3I");
GetPlayInfoResponse response = new GetPlayInfoResponse();
GetPlayInfoRequest request=new GetPlayInfoRequest();
//向request对象里面设置视频id
request.setVideoId("e9aff412746a4868958bc4f5f4ba771e");
//调用初始化对象里面的方法,传递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 static void main(String[] args) throws ClientException {
//根据视频id获取视频播放地址
//创建初始化对象
DefaultAcsClient client =InitObject.initVodClient("LTAI5tM89q3RBzKxDh6b8", "rXd2Ze5DzS9C2izYF6ISoX9fI3I");
//创建获取视频凭证request和response对象
GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
GetVideoPlayAuthResponse response = new GetVideoPlayAuthResponse();
//向request对象里面设置视频id
request.setVideoId("e9aff412746a4868958bc4f5f4ba771e");
//调用初始化对象里面的方法,传递request,获取凭证
response = client.getAcsResponse(request);
//播放凭证
System.out.print("PlayAuth = " + response.getPlayAuth() + "\n");
//VideoMeta信息
System.out.print("VideoMeta.Title = " + response.getVideoMeta().getTitle() + "\n");
}
安装非开源jar包
在本地Maven仓库中安装jar包:
下载视频上传SDK,解压,命令行进入lib目录,执行以下代码
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包
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-sdk-vod-upload</artifactId>
<version>1.4.11</version>
</dependency>
测试本地文件上传
public static void main(String[] args) {
String accessKeyId = "LTAI4FvvVEWiTJ3GNJJqJnk7";
String accessKeySecret = "9st82dv7EvFk9mTjYO1XXbM632fRbG";
String title = "6 - What If I Want to Move Faster - upload by sdk"; //上传之后文件名称
String fileName = "F:/6 - What If I Want to Move Faster.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");
} 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");
}
}
整合阿里云vod实现视频上传
创建常量类
一定要注意注入容器不然后面返回的视频id一直会为空
@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;
}
}
创建service
public interface VodService {
String uploadVideoAly(MultipartFile file);
}
VideoServiceImpl
package com.atguigu.vod.service.Impl;
import com.aliyun.vod.upload.impl.UploadVideoImpl;
import com.aliyun.vod.upload.req.UploadStreamRequest;
import com.aliyun.vod.upload.resp.UploadStreamResponse;
import com.atguigu.vod.service.VodService;
import com.atguigu.vod.utils.ConstantVodUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
@Service
public class VodServiceImpl implements VodService {
@Override
public String uploadVideoAly(MultipartFile file) {
try {
//accessKeyId, accessKeySecret
//fileName:上传文件原始名称
// 01.03.09.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 { //如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因
videoId = response.getVideoId();
}
return videoId;
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
创建controller
@RestController
@RequestMapping("/eduvod/video")
@CrossOrigin
public class VodController {
@Autowired
private VodService vodService;
@PostMapping("uploadAlyiVideo")
public ResultVo uploadAlyiVideo(MultipartFile file){
// 返回上传视频id
String videoId= vodService.uploadVideoAly(file);
return ResultVo.ok().data("videoId",videoId);
}
//上传视频到阿里云
}
整合视频前端
配置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 -s reload
数据定义
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/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>
</el-form>
方法定义
//上传视频成功调用的方法
handleVodUploadSuccess(response, file, fileList) {
//上传视频id赋值
this.video.videoSourceId = response.data.videoId;
//上传视频名称赋值
this.video.videoOriginalName = file.name;
},
handleUploadExceed() {
this.$message.warning("想要重新上传视频,请先删除已上传的视频");
},
删除云端视频
后端
controller
@DeleteMapping("removeAlyVideo/{id}")
public ResultVo removeAlyVideo(@PathVariable String id){
try {
//初始化对象
DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);
//创建删除视频的request对象
DeleteVideoRequest request=new DeleteVideoRequest();
//向request设置删除的视频id
request.setVideoIds(id);
client.getAcsResponse(request);
return ResultVo.ok();
}catch (Exception e){
e.printStackTrace();
throw new GuliException(20001,"删除视频失败");
}
}
前端
定义api
//删除视频
deleteAliyunvod(id) {
return request({
url: '/eduvod/video/removeAlyVideo/' + id,
method: 'delete'
})
}
组件方法
//点击确定调用的方法
handleVodRemove() {
//调用接口的删除视频的方法
video.deleteAliyunvod(this.video.videoSourceId).then((response) => {
//提示信息
this.$message({
type: "success",
message: "删除视频成功!",
});
//把文件列表清空
this.fileList = [];
//把video视频id和视频名称值清空
//上传视频id赋值
this.video.videoSourceId = "";
//上传视频名称赋值
this.video.videoOriginalName = "";
});
},
//点击×调用这个方法
beforeVodRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}?`);
},
springcloud&&springcloudalibaba
springcloud笔记链接
springcloudalibaba笔记链接
服务注册
把service-edu微服务注册到注册中心中,service-vod步骤相同
在service模块配置pom
原先依赖是注释掉的打开即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
cloud:
nacos:
discovery:
server-addr: localhost:8848
添加服务配置信息
配置application.properties,在客户端微服务中添加注册Nacos服务的配置信息
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
添加Nacos客户端注解
在客户端微服务启动类中添加注解
@EnableDiscoveryClient
实现服务调用
删除课时的同时删除云端视频
在service模块添加pom依赖
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在调用端的启动类添加注解
@EnableFeignClients
@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"})
@EnableDiscoveryClient
@EnableFeignClients
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class,args);
}
}
创建包和接口
创建feignclient包
@FeignClient注解用于指定从哪个服务中调用功能 ,名称与被调用的服务名保持一致。
@GetMapping注解用于对被调用的微服务进行地址映射。
@PathVariable注解一定要指定参数名称,否则出错
@Component注解防止,在其他位置注入CodClient时idea报错
@FeignClient("service-vod")
@Component
public interface VodClient {
@DeleteMapping("/eduvod/video/removeAlyVideo/{id}")
public ResultVo removeAlyVideo(@PathVariable("id") String id);
}
注入
@Autowired
private VodClient vodClient;
调用微服务
@PostMapping("{id}")
@ApiOperation(value = "根据ID删除课时")
@ApiParam(name = "id", value = "课时ID", required = true)
public ResultVo deleteVideo(@PathVariable String id){
//根据小节id获取视频id,调用方法实现视频删除
EduVideo eduVideo = videoService.getById(id);
String videoSourceId = eduVideo.getVideoSourceId();
//判断小节里面是否有视频id
if(!StringUtils.isEmpty(videoSourceId)){
vodClient.removeAlyVideo(videoSourceId);
}
boolean b = videoService.removeById(id);
if(b){
return ResultVo.ok();
}
else{
return ResultVo.error();
}
}
完善删除课程业务
删除课程的同时删除云端视频
VideoService
void removeMoreAlyVideo(List videoIdList);
VideoServiceImpl
@Override
public void removeMoreAlyVideo(List videoIdList) {
try {
//初始化对象
DefaultAcsClient client = InitVodClient.initVodClient(ConstantVodUtils.ACCESS_KEY_ID, ConstantVodUtils.ACCESS_KEY_SECRET);
//创建删除视频的request对象
DeleteVideoRequest request=new DeleteVideoRequest();
//向request设置删除的视频id
String ids = StringUtils.join(videoIdList.toArray(), ",");
request.setVideoIds(ids);
client.getAcsResponse(request);
}catch (Exception e){
e.printStackTrace();
throw new GuliException(20001,"删除视频失败");
}
}
controller
//删除多个阿里云视频的方法
//参数多个视频id list
@DeleteMapping("delete-batch")
public ResultVo deleteBatch(@RequestParam("videoIdList") List<String> videoIdList){
vodService.removeMoreAlyVideo(videoIdList);
return ResultVo.ok();
}
VodClient.
@DeleteMapping("/eduvod/video/delete-batch")
public ResultVo deleteBatch(@RequestParam("videoIdList") List<String> videoIdList);
EduVideoServiceImpl
@Autowired
private VodClient vodClient;
@Override
public void removeVideoByCourseId(String courseId) {
//根据课程id查询所有视频id
QueryWrapper<EduVideo> Wrapper = new QueryWrapper<>();
Wrapper.eq("course_id",courseId);
Wrapper.select("video_source_id");
List<EduVideo> videoList = baseMapper.selectList(Wrapper);
//List<EduVideo>变成List<string>
List<String> videoIds=new ArrayList<>();
for (int i = 0; i < videoList.size(); i++) {
EduVideo eduVideo = videoList.get(i);
if(!StringUtils.isEmpty(eduVideo)){
String videoSourceId = eduVideo.getVideoSourceId();
videoIds.add(videoSourceId);
}
}
if(videoIds.size()>0){
vodClient.deleteBatch(videoIds);
}
QueryWrapper<EduVideo> QueryWrapper = new QueryWrapper<>();
QueryWrapper.eq("course_id",courseId);
baseMapper.delete(QueryWrapper);
}
EduCourseServiceImpl
@Override
public boolean removeCourse(String courseId) {
//根据课程id删除小节
eduVideoService.removeVideoByCourseId(courseId);
//根据课程id删除章节
chapterService.removeChapterByCourseId(courseId);
//根据课程id删除描述
courseDescriptionService.removeById(courseId);
//根据课程id删除课程本身
int i = baseMapper.deleteById(courseId);
if(i==0){
throw new GuliException(20001,"删除失败");
}
return true;
}
整合Hystrix
在service的pom中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!--hystrix依赖,主要是用 @HystrixCommand -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--服务注册-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在配置文件中添加hystrix配置
#开启熔断机制
feign.hystrix.enabled=true
# 设置hystrix超时时间,默认1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
feign:
hystrix:
enabled: true
设置超时时间yml好像没有提示
在service-edu的client包里面创建熔断器的实现类
@Component
public class VodFileDegradeFeignClient implements VodClient{
@Override
public ResultVo removeAlyVideo(String id) {
return ResultVo.error().message("删除视频出错了");
}
@Override
public ResultVo deleteBatch(List<String> videoIdList) {
return ResultVo.error().message("删除多个视频出错了");
}
}
修改VodClient接口的注解
@FeignClient(name="service-vod",fallback = VodFileDegradeFeignClient.class)
public interface VodClient {
@DeleteMapping("/eduvod/video/removeAlyVideo/{id}")
public ResultVo removeAlyVideo(@PathVariable("id") String id);
@DeleteMapping("/eduvod/video/delete-batch")
public ResultVo deleteBatch(@RequestParam("videoIdList") List<String> videoIdList);
}
测试熔断
//删除小节
@PostMapping("{id}")
@ApiOperation(value = "根据ID删除课时")
@ApiParam(name = "id", value = "课时ID", required = true)
public ResultVo deleteVideo(@PathVariable String id){
//根据小节id获取视频id,调用方法实现视频删除
EduVideo eduVideo = videoService.getById(id);
String videoSourceId = eduVideo.getVideoSourceId();
//判断小节里面是否有视频id
if(!StringUtils.isEmpty(videoSourceId)){
ResultVo result = vodClient.removeAlyVideo(videoSourceId);
if (result.getCode()==20001){
throw new GuliException(20001,"删除视频失败,熔断器...");
}
}
boolean b = videoService.removeById(id);
if(b){
return ResultVo.ok();
}
else{
return ResultVo.error();
}
}