SpringBoot+阿里云OSS實(shí)現(xiàn)在線視頻播放的示例
阿里云 OSS 是一種云存儲(chǔ)技術(shù),你可以理解為云盤(pán),我們的目標(biāo)是將視頻存儲(chǔ)到云端,然后在前端讀取并播放視頻。
OSS
首先登陸首頁(yè),創(chuàng)建一個(gè)存儲(chǔ)桶:https://oss.console.aliyun.com

然后找到讀寫(xiě)權(quán)限:

將讀寫(xiě)權(quán)限設(shè)置為公共讀即可:

在 RAM 中新建一個(gè)用戶:

為其添加權(quán)限,選擇 OSS 的權(quán)限:

然后點(diǎn)進(jìn)去這個(gè)用戶,找到 AccessKey:

創(chuàng)建之后記下來(lái) secret ,因?yàn)樗怀霈F(xiàn)一次,如果沒(méi)記住也沒(méi)事,可以重新創(chuàng)建新的 key。
下面開(kāi)始編寫(xiě)服務(wù)端代碼:
POM
<!-- 阿里云oss --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency>
package com.lsu.file.controller.admin;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.AppendObjectRequest;
import com.aliyun.oss.model.AppendObjectResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.lsu.server.dto.FileDto;
import com.lsu.server.dto.ResponseDto;
import com.lsu.server.enums.FileUseEnum;
import com.lsu.server.service.FileService;
import com.lsu.server.util.Base64ToMultipartFile;
import com.lsu.server.util.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
/**
* @author wsuo
*/
@RestController
@RequestMapping("/admin")
public class OssController {
private static final Logger LOG = LoggerFactory.getLogger(FileController.class);
@Value("${oss.accessKeyId}")
private String accessKeyId;
@Value("${oss.accessKeySecret}")
private String accessKeySecret;
@Value("${oss.endpoint}")
private String endpoint;
@Value("${oss.bucket}")
private String bucket;
@Value("${oss.domain}")
private String ossDomain;
public static final String BUSINESS_NAME = "OSS文件上傳";
@Resource
private FileService fileService;
@PostMapping("/oss-append")
public ResponseDto<FileDto> fileUpload(@RequestBody FileDto fileDto) throws Exception {
LOG.info("上傳文件開(kāi)始");
String use = fileDto.getUse();
String key = fileDto.getKey();
String suffix = fileDto.getSuffix();
Integer shardIndex = fileDto.getShardIndex();
Integer shardSize = fileDto.getShardSize();
String shardBase64 = fileDto.getShard();
MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);
FileUseEnum useEnum = FileUseEnum.getByCode(use);
String dir = useEnum.name().toLowerCase();
String path = dir +
"/" +
key +
"." +
suffix;
// 創(chuàng)建OSSClient實(shí)例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ObjectMetadata meta = new ObjectMetadata();
// 指定上傳的內(nèi)容類型。
meta.setContentType("text/plain");
// 通過(guò)AppendObjectRequest設(shè)置多個(gè)參數(shù)。
AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucket, path, new ByteArrayInputStream(shard.getBytes()), meta);
appendObjectRequest.setPosition((long) ((shardIndex - 1) * shardSize));
AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
// 文件的64位CRC值。此值根據(jù)ECMA-182標(biāo)準(zhǔn)計(jì)算得出。
System.out.println(appendObjectResult.getObjectCRC());
System.out.println(JSONObject.toJSONString(appendObjectResult));
ossClient.shutdown();
LOG.info("保存文件記錄開(kāi)始");
fileDto.setPath(path);
fileService.save(fileDto);
ResponseDto<FileDto> responseDto = new ResponseDto<>();
fileDto.setPath(ossDomain + path);
responseDto.setContent(fileDto);
return responseDto;
}
@PostMapping("/oss-simple")
public ResponseDto<FileDto> fileUpload(@RequestParam MultipartFile file, String use) throws Exception {
LOG.info("上傳文件開(kāi)始");
FileUseEnum useEnum = FileUseEnum.getByCode(use);
String key = UuidUtil.getShortUuid();
String fileName = file.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
String dir = useEnum.name().toLowerCase();
String path = dir + "/" + key + "." + suffix;
// 創(chuàng)建OSSClient實(shí)例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, path, new ByteArrayInputStream(file.getBytes()));
ossClient.putObject(putObjectRequest);
ResponseDto<FileDto> responseDto = new ResponseDto<>();
FileDto fileDto = new FileDto();
fileDto.setPath(ossDomain + path);
responseDto.setContent(fileDto);
return responseDto;
}
}
這部分內(nèi)容可以參考阿里云的幫助手冊(cè):https://help.aliyun.com/document_detail/32011.html?spm=a2c4g.11174283.6.915.443b7da2mfhbKq
上面寫(xiě)的是兩個(gè)接口:
- 追加上傳:
/oss-append - 簡(jiǎn)單上傳:
/oss-simple
注意這里的參數(shù)都已經(jīng)在 yml 文件中定義了:

上面的 KeyId 和 KeySecret 就是之前在創(chuàng)建用戶時(shí)給的那兩個(gè),填上就行了。
在前端我們就可以發(fā)送請(qǐng)求獲取數(shù)據(jù),注意這里的對(duì)象是我自定義的,大家可以根據(jù)項(xiàng)目需求自行設(shè)置。
_this.$ajax.post(process.env.VUE_APP_SERVER + '/file/admin/oss-simple', formData).then(response => {
Loading.hide();
let resp = response.data;
_this.afterUpload(resp);
// 清空原來(lái)控件中的值
$("#" + _this.inputId + "-input").val("");
})
視頻點(diǎn)播
VOD 是另一種視頻存儲(chǔ)的形式,它的功能更豐。阿里云視頻點(diǎn)播(VOD)是集音視頻上傳、自動(dòng)化轉(zhuǎn)碼處理、媒體資源管理、分發(fā)加速于一體的全鏈路音視頻點(diǎn)播服務(wù)。
我們同樣需要一個(gè) VOD 的用戶,給它賦予 VOD 的權(quán)限:

SDK 的使用可以參考文檔:https://help.aliyun.com/document_detail/61063.html?spm=a2c4g.11186623.6.921.418f192bTDCIJN
我們可以在轉(zhuǎn)碼組設(shè)置自己的模板,然后通過(guò) ID 在代碼中使用:

上傳視頻比較簡(jiǎn)單,和 OSS 很像,但是播放視頻要多一個(gè)條件,在獲取播放鏈接之前要先取得權(quán)限認(rèn)證,所以下面單獨(dú)寫(xiě)了一個(gè) /get-auth/{vod} 接口,其中的參數(shù)就是 vod 的 ID,這個(gè) ID 在我們上傳視頻之后會(huì)作為返回值返回的。
package com.lsu.file.controller.admin;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.CreateUploadVideoResponse;
import com.aliyuncs.vod.model.v20170321.GetMezzanineInfoResponse;
import com.aliyuncs.vod.model.v20170321.GetVideoPlayAuthResponse;
import com.lsu.server.dto.FileDto;
import com.lsu.server.dto.ResponseDto;
import com.lsu.server.enums.FileUseEnum;
import com.lsu.server.service.FileService;
import com.lsu.server.util.Base64ToMultipartFile;
import com.lsu.server.util.VodUtil;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
/**
* @author wsuo
*/
@RestController
@RequestMapping("/admin")
public class VodController {
private static final Logger LOG = LoggerFactory.getLogger(FileController.class);
@Value("${vod.accessKeyId}")
private String accessKeyId;
@Value("${vod.accessKeySecret}")
private String accessKeySecret;
public static final String BUSINESS_NAME = "VOD視頻上傳";
@Resource
private FileService fileService;
@PostMapping("/vod")
public ResponseDto<FileDto> fileUpload(@RequestBody FileDto fileDto) throws Exception {
String use = fileDto.getUse();
String key = fileDto.getKey();
String suffix = fileDto.getSuffix();
Integer shardIndex = fileDto.getShardIndex();
Integer shardSize = fileDto.getShardSize();
String shardBase64 = fileDto.getShard();
MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);
FileUseEnum useEnum = FileUseEnum.getByCode(use);
String dir = useEnum.name().toLowerCase();
String path = dir +
"/" +
key +
"." +
suffix;
//需要上傳到VOD的本地視頻文件的完整路徑,需要包含文件擴(kuò)展名
String vod = "";
String fileUrl = "";
try {
// 初始化VOD客戶端并獲取上傳地址和憑證
DefaultAcsClient vodClient = VodUtil.initVodClient(accessKeyId, accessKeySecret);
CreateUploadVideoResponse createUploadVideoResponse = VodUtil.createUploadVideo(vodClient, path);
// 執(zhí)行成功會(huì)返回VideoId、UploadAddress和UploadAuth
vod = createUploadVideoResponse.getVideoId();
JSONObject uploadAuth = JSONObject.parseObject(
Base64.decodeBase64(createUploadVideoResponse.getUploadAuth()), JSONObject.class);
JSONObject uploadAddress = JSONObject.parseObject(
Base64.decodeBase64(createUploadVideoResponse.getUploadAddress()), JSONObject.class);
// 使用UploadAuth和UploadAddress初始化OSS客戶端
OSSClient ossClient = VodUtil.initOssClient(uploadAuth, uploadAddress);
// 上傳文件,注意是同步上傳會(huì)阻塞等待,耗時(shí)與文件大小和網(wǎng)絡(luò)上行帶寬有關(guān)
if (shard != null) {
VodUtil.uploadLocalFile(ossClient, uploadAddress, shard.getInputStream());
}
System.out.println("上傳視頻成功, vod : " + vod);
GetMezzanineInfoResponse response = VodUtil.getMezzanineInfoResponse(vodClient, vod);
System.out.println("獲取視頻信息 response = " + JSON.toJSONString(response));
fileUrl = response.getMezzanine().getFileURL();
ossClient.shutdown();
} catch (Exception e) {
System.out.println("上傳視頻失敗, ErrorMessage : " + e.getLocalizedMessage());
}
fileDto.setPath(path);
fileDto.setVod(vod);
fileService.save(fileDto);
ResponseDto<FileDto> responseDto = new ResponseDto<>();
fileDto.setPath(fileUrl);
responseDto.setContent(fileDto);
return responseDto;
}
@RequestMapping(value = "/get-auth/{vod}", method = RequestMethod.GET)
public ResponseDto<String> getAuth(@PathVariable String vod) {
LOG.info("獲取播放授權(quán)開(kāi)始");
ResponseDto<String> responseDto = new ResponseDto<>();
DefaultAcsClient client = VodUtil.initVodClient(accessKeyId, accessKeySecret);
GetVideoPlayAuthResponse response;
try {
response = VodUtil.getVideoPlayAuthResponse(client, vod);
String playAuth = response.getPlayAuth();
//播放憑證
LOG.info("授權(quán)碼 = {}", playAuth);
responseDto.setContent(playAuth);
//VideoMeta信息
LOG.info("VideoMeta信息 = {}", response.getVideoMeta().getTitle());
} catch (Exception e) {
System.out.print("ErrorMessage = " + e.getLocalizedMessage());
}
LOG.info("獲取播放授權(quán)結(jié)束");
return responseDto;
}
}
methods: {
playUrl(url) {
let _this = this;
console.log("開(kāi)始播放:", url);
// 如果已經(jīng)有播放器了 就將播放器刪除
if (_this.aliPlayer) {
_this.aliPlayer = null;
$("#" + _this.playerId + '-player').remove();
}
// 初始化播放器
$("#" + _this.playerId).append("<div class=\"prism-player\" id=\"" + _this.playerId + "-player\"></div>");
_this.aliPlayer = new Aliplayer({
id: _this.playerId + '-player',
width: '100%',
autoplay: true,
//支持播放地址播放,此播放優(yōu)先級(jí)最高
source: url,
cover: 'http://liveroom-img.oss-cn-qingdao.aliyuncs.com/logo.png'
}, function (player) {
console.log("播放器創(chuàng)建好了")
})
},
playVod(vod) {
let _this = this;
Loading.show();
_this.$ajax.get(process.env.VUE_APP_SERVER + '/file/admin/get-auth/' + vod).then((response) => {
Loading.hide();
let resp = response.data;
if (resp.success) {
//如果已經(jīng)有播放器了,則將播放器div刪除
if (_this.aliPlayer) {
_this.aliPlayer = null;
$("#" + _this.playerId + '-player').remove();
}
// 初始化播放器
$("#" + _this.playerId).append("<div class=\"prism-player\" id=\"" + _this.playerId + "-player\"></div>");
_this.aliPlayer = new Aliplayer({
id: _this.playerId + '-player',
width: '100%',
autoplay: false,
vid: vod,
playauth: resp.content,
cover: 'http://liveroom-img.oss-cn-qingdao.aliyuncs.com/logo.png',
encryptType: 1, //當(dāng)播放私有加密流時(shí)需要設(shè)置。
}, function (player) {
console.log('播放器創(chuàng)建好了。')
});
} else {
Toast.warning('播放錯(cuò)誤。')
}
});
}
},
上述的前端代碼只是一個(gè)例子,playVod 調(diào)用的是阿里的播放器。
到此這篇關(guān)于SpringBoot+阿里云OSS實(shí)現(xiàn)在線視頻播放的示例的文章就介紹到這了,更多相關(guān)SpringBoot阿里云OSS在線視頻內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA:Git stash 暫存分支修改的實(shí)現(xiàn)代碼
這篇文章主要介紹了IDEA:Git stash 暫存分支修改的實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
簡(jiǎn)單介紹區(qū)分applet和application的方法
applet和application都是Java語(yǔ)言編寫(xiě)出來(lái)的應(yīng)用程序,本文簡(jiǎn)單介紹了二者的不同之處,需要的朋友可以參考下2017-09-09
SpringBoot開(kāi)發(fā)實(shí)戰(zhàn)之自動(dòng)配置
SpringBoot的核心就是自動(dòng)配置,自動(dòng)配置又是基于條件判斷來(lái)配置Bean,下面這篇文章主要給大家介紹了關(guān)于SpringBoot開(kāi)發(fā)實(shí)戰(zhàn)之自動(dòng)配置的相關(guān)資料,需要的朋友可以參考下2021-08-08
java struts2學(xué)習(xí)筆記之線程安全
這篇文章主要為大家詳細(xì)介紹了java struts2學(xué)習(xí)筆記之線程安全,感興趣的朋友可以參考一下2016-04-04
關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問(wèn)題
這篇文章主要介紹了關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

