经历了几天的周折,近期才把项目完成,在这里与大家分享一下踩坑之路,也方便日后有类似项目,可以借阅一番

开发直播前先满足已下条件

1.开通视频直播功能

2.购买好了OSS存储

3.购买两个域名并且备案好,一个用来拉流,一个用来播流,

4.建议CNAM加速也设置好这样直播没那么卡

该项目是一个H5直播,采用m3u8格式完成直播的展示。通过推流地址,借助第三方推流工具实现直播效果,比如:OBS 或者一些微信小程序 小推流。。等等

项目介绍:根据域名生成推流、播流地址,推流回调,检查推流状态。直播视频存储至OSS,视频回调,统计当前在线人数等等

项目需要:需要现在阿里云上配置你的域名,推流域名,播流域名,推流回调地址,OSS存储,播流跨域问题等等

进入正题:
根据推拉域名生成推流地址与播流地址

配置pom文件

<!--阿里云直播--><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.4.6</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-live</artifactId><version>3.8.0</version></dependency><!-- Hutool工具包 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>4.0.12</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.48</version></dependency>
配置你的阿里云参数AliYunConfig  streamName这里是自定义的直播类型  根据你的需求而定,我的直播类型这里就没写
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
@Data
public class AliYunConfig {/*** 推流域名*/@Value("")private String aliyunLivePushDomain;/*** 拉流域名*/@Value("")private String aliyunLivePullDomain;/*** 直播测试appName*/@Value("")private String aliyunLiveAppName;/*** 直播测试streamName{直播类型}_{类型id}*/@Value("")private String aliyunLiveStreamName;/*** 推流鉴权url key*/@Value("")private String aliyunLivePushIdentKey;/*** 拉流鉴权url key*/@Value("")private String aliyunLivePullIdentKey;/*** 鉴权url的有效时间(秒),默认30分钟,1800秒 key*/@Value("1800")private Integer aliyunLiveIdentUrlValidTime;/*** OSS-区域代码*/@Value("cn-shanghai")private String regionId;/*** OSS-RAM 访问控制-人员管理-用户 AccessKey*/@Value("")private String accessKeyId;/*** OSS-RAM 访问控制-人员管理-用户 secret*/@Value("")private String secret;
}
配置阿里云AliYunUtil
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.gs.body.alilive.AliyunLiveUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class AliYunUtil {private static final Logger log = LoggerFactory.getLogger(AliyunLiveUtil.class);/*** 推拉流地址示例:* rtmp://www.ttest.ygdjonline.com/a/a?auth_key=1558065152-0-0-c3cb54d946c0590ca9aeee63573201ee* 播流地址* 原画* rtmp://www.btest.ygdjonline.com/a/a?auth_key=1558065152-0-0-fc711455c0815aeb581385f33451d5b4* http://www.btest.ygdjonline.com/a/a.flv?auth_key=1558065152-0-0-221abff1da1ee32151e365cf0dd42a53* http://www.btest.ygdjonline.com/a/a.m3u8?auth_key=1558065152-0-0-72124fcc3aee3404b0d65dcc114e207f*//*** 根据源id创建该id的推流url** @param sourceId* @param aliyunConfig* @return*/public static String createPushUrl(String sourceId, AliYunConfig aliyunConfig) {// 推流域名String pushDomain = aliyunConfig.getAliyunLivePushDomain();// 应用名称String appName = aliyunConfig.getAliyunLiveAppName();// 流名称String streamName = StrUtil.format(sourceId);// 推流签名keyString pushIdentKey = aliyunConfig.getAliyunLivePushIdentKey();// 签名url有效时间Integer identUrlValidTime = aliyunConfig.getAliyunLiveIdentUrlValidTime();//log.info("签名url有效时间" + identUrlValidTime);// 计算过期时间String timestamp = String.valueOf((System.currentTimeMillis() / 1000) + identUrlValidTime);// log.info("计算过期时间" + timestamp);// 组合推流域名前缀//rtmp://{pushDomain}/{appName}/{streamName}String rtmpUrl = StrUtil.format("rtmp://{}/{}/{}", pushDomain, appName, streamName);// 组合md5加密串///{appName}/{streamName}-{timestamp}-0-0-{pushIdentKey}String md5Url = StrUtil.format("/{}/{}-{}-0-0-{}", appName, streamName, timestamp, pushIdentKey);log.info("组合md5加密串"+md5Url);// md5加密String md5Str = DigestUtil.md5Hex(md5Url);// log.info("md5加密串,md5Url=" + md5Url + "------md5加密结果,md5Str=" + md5Str);// 组合最终鉴权过的推流域名
//      {rtmpUrl}?auth_key={timestamp}-0-0-{md5Str}String finallyPushUrl = StrUtil.format("{}?auth_key={}-0-0-{}", rtmpUrl, timestamp, md5Str);log.info("最终鉴权过的推流域名=" + finallyPushUrl);return finallyPushUrl;}/*** 创建拉流域名,key=rtmpUrl、flvUrl、m3u8Url,代表三种拉流类型域名** @param sourceId* @param aliyunConfig* @return*/public static String createPullUrl(String sourceId, AliYunConfig aliyunConfig) {// 拉流域名String pullDomain = aliyunConfig.getAliyunLivePullDomain();// 应用名称String appName = aliyunConfig.getAliyunLiveAppName();// 流名称String streamName = StrUtil.format(sourceId);// 拉流签名keyString pullIdentKey = aliyunConfig.getAliyunLivePullIdentKey();// 签名url有效时间Integer identUrlValidTime = aliyunConfig.getAliyunLiveIdentUrlValidTime();// 计算过期时间String timestamp = String.valueOf((System.currentTimeMillis() / 1000) + identUrlValidTime);// 组合通用域名
//      {pullDomain}/{appName}/{streamName}String pullUrl = StrUtil.format("{}/{}/{}", pullDomain, appName, streamName);//log.info("组合通用域名,pullUrl=" + pullUrl);// 组合md5加密串
//      /{appName}/{streamName}-{timestamp}-0-0-{pullIdentKey}String md5Url = StrUtil.format("/{}/{}-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);String md5FlvUrl = StrUtil.format("/{}/{}.flv-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);String md5M3u8Url = StrUtil.format("/{}/{}.m3u8-{}-0-0-{}", appName, streamName, timestamp, pullIdentKey);// md5加密String md5Str = DigestUtil.md5Hex(md5Url);String md5FlvStr = DigestUtil.md5Hex(md5FlvUrl);String md5M3u8Str = DigestUtil.md5Hex(md5M3u8Url);//log.info("md5加密串,md5Url    =" + md5Url + "       ------     md5加密结果,md5Str=" + md5Str);//log.info("md5加密串,md5FlvUrl =" + md5FlvUrl + "    ------    md5加密结果,md5FlvStr=" + md5FlvStr);//log.info("md5加密串,md5M3u8Url=" + md5M3u8Url + "   ------    md5加密结果,md5M3u8Str=" + md5M3u8Str);// 组合三种拉流域名前缀
//        rtmp://{pullUrl}?auth_key={timestamp}-0-0-{md5Str}String rtmpUrl = StrUtil.format("rtmp://{}?auth_key={}-0-0-{}", pullUrl, timestamp, md5Str);
//        http://{pullUrl}.flv?auth_key={timestamp}-0-0-{md5FlvStr}String flvUrl = StrUtil.format("http://{}.flv?auth_key={}-0-0-{}", pullUrl, timestamp, md5FlvStr);
//        http://{pullUrl}.m3u8?auth_key={timestamp}-0-0-{md5M3u8Str}String m3u8Url = StrUtil.format("http://{}.m3u8?auth_key={}-0-0-{}", pullUrl, timestamp, md5M3u8Str);log.info("最终鉴权过的拉流rtmp域名=" + rtmpUrl);log.info("最终鉴权过的拉流flv域名 =" + flvUrl);log.info("最终鉴权过的拉流m3u8域名=" + m3u8Url);return m3u8Url;}
}

通过GetMapping 生成推流 拉流地址

 @Resourceprivate AliYunConfig aliyunConfig;/*** 生成推流播流地址* sourceId  在这里我将它设置为房间号*/@GetMapping("/save_Live")public void save_Live(HttpServletRequest request, @RequestParam("sourceId") String sourceId){try {//生成推流地址String pushUrl = AliYunUtil.createPushUrl(sourceId, aliyunConfig);//生成播流地址String pullUrl = AliYunUtil.createPullUrl(sourceId, aliyunConfig);} catch (Exception e) {e.printStackTrace();}}

如果你的播流地址,存在跨域问题,请在阿里云上配置HTTP响应头,这里添加一个*号即可

现在开始走回调接口,这里需要你在阿里云上配置你的回调地址,是以http开头的

推流地址接口 同样也是GET形式的 阿里云返回的参数定义可以参考:https://help.aliyun.com/document_detail/84943.html?spm=a2c4g.11186623.2.27.44c63dd286Dtq1#concept-84943-zh

 /*** 推流地址回调接口 根据返回状态值进行业务处理*/@GetMapping("/callBackPath")public void test(HttpServletRequest request){/*** 返回参数* action:[publish].......*/try {Map<String, String[]> parameterMap = request.getParameterMap();ApiLiveModel model = JSONObject.parseObject(JSON.toJSONString(parameterMap),ApiLiveModel.class);// 实现效果   根据回调接口 publish_done:关闭直播 publish 开启直播if (model != null){String action = model.getAction().get(0); //获取直播状态值String houseId = model.getId().get(0); //获取直播房间号if (action.equals("publish")){log.info("开启直播状态");//业务处理}else if (action.equals("publish_done")){log.info("关闭直播状态");//业务处理}}}catch (Exception e){e.printStackTrace();}}

定义返回参数的model类

import java.util.List;public class ApiLiveModel {private List<String> action;private List<String> ip;private List<String> id;private List<String> app;private List<String> appname;private List<String> time;private List<String> usrargs;private List<String> node;public List<String> getAction() {return action;}public void setAction(List<String> action) {this.action = action;}public List<String> getIp() {return ip;}public void setIp(List<String> ip) {this.ip = ip;}public List<String> getId() {return id;}public void setId(List<String> id) {this.id = id;}public List<String> getApp() {return app;}public void setApp(List<String> app) {this.app = app;}public List<String> getAppname() {return appname;}public void setAppname(List<String> appname) {this.appname = appname;}public List<String> getTime() {return time;}public void setTime(List<String> time) {this.time = time;}public List<String> getUsrargs() {return usrargs;}public void setUsrargs(List<String> usrargs) {this.usrargs = usrargs;}public List<String> getNode() {return node;}public void setNode(List<String> node) {this.node = node;}
}

视频存储至阿里云OSS,需要配置Bucket,然后在域名管理,录制配置中添加配置

这样你的直播视频,就存放至阿里云上了,在这里有一个问题需要解决,m3u8格式的在线预览,需要配置一下跨域问题,不然无法播放。参考地址:https://help.aliyun.com/document_detail/31903.html?spm=a2c4g.11174283.6.1124.369f7da2kWLpA2

接下来就是视频回调了,同样也需要在阿里云配置你的视频回调接口,这里也是http开头的

接下来就是代码片段了,具体的返回参数,请参考:https://help.aliyun.com/document_detail/84935.html?spm=5176.13910061.0.0.6b2b7018cRAX1h&aly_as=qJRVAQTxQ

//录制视频存储到OSS 回调接口@PostMapping("/api_p/addLive")public void addLive(@RequestBody ApiSaveLiveModel model) throws IOException {try{/*** 返回参数* {*   "domain": "live.aliyunlive.com",*   "app": "live",*   "stream": "hello",*   "uri": "live/hello/0_2017-03-08-23:09:46_2017-03-08-23:10:40.flv",*   "duration": 69.403,*   "start_time": 1488985786,*   "stop_time": 1488985840* }* 具体参数详情请参考:https://help.aliyun.com/document_detail/84935.html?spm=5176.13910061.0.0.6b2b7018cRAX1h&aly_as=qJRVAQTxQ*/log.info("保存作品成功");}catch (Exception e){log.info("保存作品失败");e.printStackTrace();}}

回调参数model

public class ApiSaveLiveModel {/*** domain : live.aliyunlive.com* app : live* stream : hello* uri : live/hello/0_2017-03-08-23:09:46_2017-03-08-23:10:40.flv* duration : 69.403* start_time : 1488985786* stop_time : 1488985840*/private String domain;private String app;private String stream;private String uri;private double duration;private int start_time;private int stop_time;public String getDomain() {return domain;}public void setDomain(String domain) {this.domain = domain;}public String getApp() {return app;}public void setApp(String app) {this.app = app;}public String getStream() {return stream;}public void setStream(String stream) {this.stream = stream;}public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}public double getDuration() {return duration;}public void setDuration(double duration) {this.duration = duration;}public int getStart_time() {return start_time;}public void setStart_time(int start_time) {this.start_time = start_time;}public int getStop_time() {return stop_time;}public void setStop_time(int stop_time) {this.stop_time = stop_time;}@Overridepublic String toString() {return "ApiSaveLiveModel{" +"domain='" + domain + '\'' +", app='" + app + '\'' +", stream='" + stream + '\'' +", uri='" + uri + '\'' +", duration=" + duration +", start_time=" + start_time +", stop_time=" + stop_time +'}';}
}

接下来就是 根据当前播流地址,统计在线人数,统计HLS直播的在线人数, 我们需要客户端在请求的参数中带上唯一标识用户的uuid,在阿里云cdn使用的默认参数是aliyun_uuid,言下之意就是每当用户访问的时候,会携带这个uuid,通过这个uuid 来获取当前播流域名的在线人数

重要说明:统计m3u8格式的在线人数,需要通过阿里云工单申请

具体的参数可以找阿里云人工要一份,是PDF版,网上也有博客,但是我找不到了

//根据播流地址 查询当前在线人数public static Integer getPeopleSum() throws ClientException {/*** 返回参数**  time : 2020-04-20T03:40:00Z*  requestId : A76B853C-AB5A-4F02-96C5-BDAB1A485FAC*  usageData : [{"domainName":"boliu.comwinwin.com","streamInfos":[{"streamName":"/jingbei/82889.m3u8","infos":[{"downFlow":609.5467,"rate":"origin","online":1}]}]}]**  online:指的是当前的在线人数**/try{DescribeHlsLiveStreamRealTimeBpsDataRequest listRequest2 = new DescribeHlsLiveStreamRealTimeBpsDataRequest();listRequest2.setDomainName("boliu.comwinwin.com"); //播流域名listRequest2.setTime(getTime());  //UTC格式当前时间           归属地DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", "LTAI4G84ApyG4K1x4v9JHaXC", "d4iWslw08vidnqtYB8IpaHLLfsVp9e");IAcsClient iAcsClient = new DefaultAcsClient(profile);//配置的参数DescribeHlsLiveStreamRealTimeBpsDataResponse response = iAcsClient.getAcsResponse(listRequest2);//获取直播人数       List<DescribeHlsLiveStreamRealTimeBpsDataResponse.UsageDataPerDomain> usageDatas = usageDatasResponse.getUsageData();//获取直播状态        for (DescribeHlsLiveStreamRealTimeBpsDataResponse.UsageDataPerDomain usageData : usageDatas) {     if (usageData.getDomainName().equals("播流域名(补全)")) {//获取阿里云返回的结果,根据结果处理得到当前播放流下在线人数String str = new Gson().toJson(response);ApiPersonSumModel mode = JSON.parseObject(str, ApiPersonSumModel.class);return 0;}catch (Exception e){return 0;}}/*** 获取当前在线时间  UTC 格式时间* @return*/public static String getTime(){Date date = new Date();// 获取当前时间Calendar calendar = Calendar.getInstance();calendar.setTime(date);int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);int dstOffset = calendar.get(Calendar.DST_OFFSET);calendar.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));long timeInMillis = calendar.getTimeInMillis();SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");return df.format(timeInMillis);}

返回参数的model类

import java.util.List;public class ApiPersonSumModel {/*** time : 2020-04-20T03:40:00Z* requestId : A76B853C-AB5A-4F02-96C5-BDAB1A485FAC* usageData : [{"domainName":"boliu.comwinwin.com","streamInfos":[{"streamName":"/jingbei/82889.m3u8","infos":[{"downFlow":609.5467,"rate":"origin","online":1}]}]}]*/private String time;private String requestId;private List<UsageDataApiPersonSumModel> usageData;public String getTime() {return time;}public void setTime(String time) {this.time = time;}public String getRequestId() {return requestId;}public void setRequestId(String requestId) {this.requestId = requestId;}public List<UsageDataApiPersonSumModel> getUsageData() {return usageData;}public void setUsageData(List<UsageDataApiPersonSumModel> usageData) {this.usageData = usageData;}public static class UsageDataApiPersonSumModel {/*** domainName : boliu.comwinwin.com* streamInfos : [{"streamName":"/jingbei/82889.m3u8","infos":[{"downFlow":609.5467,"rate":"origin","online":1}]}]*/private String domainName;private List<StreamInfosApiPersonSumModel> streamInfos;public String getDomainName() {return domainName;}public void setDomainName(String domainName) {this.domainName = domainName;}public List<StreamInfosApiPersonSumModel> getStreamInfos() {return streamInfos;}public void setStreamInfos(List<StreamInfosApiPersonSumModel> streamInfos) {this.streamInfos = streamInfos;}public static class StreamInfosApiPersonSumModel {/*** streamName : /jingbei/82889.m3u8* infos : [{"downFlow":609.5467,"rate":"origin","online":1}]*/private String streamName;private List<InfosApiPersonSumModel> infos;public String getStreamName() {return streamName;}public void setStreamName(String streamName) {this.streamName = streamName;}public List<InfosApiPersonSumModel> getInfos() {return infos;}public void setInfos(List<InfosApiPersonSumModel> infos) {this.infos = infos;}public static class InfosApiPersonSumModel {/*** downFlow : 609.5467* rate : origin* online : 1*/private double downFlow;private String rate;private int online;public double getDownFlow() {return downFlow;}public void setDownFlow(double downFlow) {this.downFlow = downFlow;}public String getRate() {return rate;}public void setRate(String rate) {this.rate = rate;}public int getOnline() {return online;}public void setOnline(int online) {this.online = online;}}}}
}

定时器查询录制保存的视频

/*** 每隔30分钟执行一次 直播录制视频没有回调的* 要重新调用阿里云录制视频查询接口:* 参考地址 https://help.aliyun.com/document_detail/35421.html?spm=a2c4g.11186623.6.757.30f151e7YjXnFO*/@Scheduled(cron = "0 */30 * * * ?")public void updatePublisPushTime() {List<CourseItem> courseItemList = courseItemDao.getLiveList();if(courseItemList != null && !courseItemList.isEmpty()){for(CourseItem courseItem :courseItemList){//封装录制视频查询接口需要的参数DefaultProfile profile = DefaultProfile.getProfile(aliYunLiveConfig.getRegionId(), aliYunLiveConfig.getAccessKeyId(), aliYunLiveConfig.getSecret());IAcsClient client = new DefaultAcsClient(profile);DescribeLiveStreamRecordIndexFilesResponse response = null;List<RecordIndexInfo> recordIndexInfoList = null;DescribeLiveStreamRecordIndexFilesRequest request = new DescribeLiveStreamRecordIndexFilesRequest();request.setRegionId(aliYunLiveConfig.getRegionId());request.setAppName(aliYunLiveConfig.getAliyunLiveAppName()); //直播流所属应用名称。request.setStreamName(courseItem.getId().toString());    //直播流名称。 也是课节id/***  开始时间,格式:UTC时间。示例:2015-12-01T17:36:00Z*/request.setStartTime(DateUtil.utcDateStr(courseItem.getBeginDate()));/*** 结束时间。与StartTime的间隔时间不能超过4天。格式:UTC时间。示例:2015-12-01T17:36:00Z。*/request.setEndTime(DateUtil.utcDateStr(courseItem.getEndDate()));request.setDomainName(aliYunLiveConfig.getAliyunLivePullDomain()); //您的加速域名  try {//调用查询接口response = client.getAcsResponse(request);log.info("调用阿里云录制视频查询接口返回: " + new Gson().toJson(response));recordIndexInfoList = response.getRecordIndexInfoList();if(recordIndexInfoList != null && !recordIndexInfoList.isEmpty() ){courseItem.setItemUrl(recordIndexInfoList.get(0).getRecordUrl());courseItemDao.update(courseItem);}} catch (ClientException e) {log.error("调用阿里云录制视频查询接口错误ErrCode: " + e.getErrCode());log.error("调用阿里云录制视频查询接口错误ErrMsg: " + e.getErrMsg());log.error("调用阿里云录制视频查询接口错误RequestId: " + e.getRequestId());} catch (Exception e1){log.error("调用阿里云录制视频查询接口错误: " + e1.getMessage());}}}}
/*** * <p>Description: 北京时间转化为UTC时间</p>* @param date 指定时间* @return**/public static String utcDateStr(Date date) {try{SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");long localTimeInMillis=date.getTime();/** long时间转换成Calendar */Calendar calendar= Calendar.getInstance();calendar.setTimeInMillis(localTimeInMillis);/** 取得时间偏移量 */int zoneOffset = calendar.get(java.util.Calendar.ZONE_OFFSET);/** 取得夏令时差 */int dstOffset = calendar.get(java.util.Calendar.DST_OFFSET);/** 从本地时间里扣除这些差量,即可以取得UTC时间*/calendar.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));/** 取得的时间就是UTC标准时间 */Date utcDate=new Date(calendar.getTimeInMillis());String utcDateStr = format.format(utcDate);return utcDateStr;}catch(Exception e){e.printStackTrace();return null;}}
/*** 同一个推流 多个视频文件合并成一个 只支持m3u8录制格式* 创建某个时间范围的M3U8索引文件* 参考地址  https://help.aliyun.com/document_detail/35417.html*/public void createLiveStreamRecordIndexFiles(){DefaultProfile profile = DefaultProfile.getProfile(aliYunLiveConfig.getRegionId(), aliYunLiveConfig.getAccessKeyId(), aliYunLiveConfig.getSecret());IAcsClient client = new DefaultAcsClient(profile);CreateLiveStreamRecordIndexFilesRequest request = new CreateLiveStreamRecordIndexFilesRequest();request.setRegionId(aliYunLiveConfig.getRegionId());request.setAppName(aliYunLiveConfig.getAliyunLiveAppName());request.setStreamName("61");request.setOssEndpoint("oss-cn-shenzhen.aliyuncs.com");request.setOssBucket("fssh-video");request.setOssObject("course/live/record/live/record/61.m3u8");request.setStartTime("2020-07-12T17:36:00Z");request.setEndTime("2020-07-14T17:36:00Z");request.setDomainName(aliYunLiveConfig.getAliyunLivePullDomain());try {CreateLiveStreamRecordIndexFilesResponse response = client.getAcsResponse(request);log.info(new Gson().toJson(response));} catch (ServerException e) {e.printStackTrace();} catch (ClientException e) {log.info("ErrCode:" + e.getErrCode());log.info("ErrMsg:" + e.getErrMsg());log.info("RequestId:" + e.getRequestId());}}

至此阿里云视频直播,推拉流、推流回调、视频存储、存储回调、各项配置、统计在线人数,就搞定了!

经过跟阿里云工单讨教的答案,以及自己在博客上找的资源,最终整理了一篇关于阿里云开发直播的东西。

脱坑不易,与大家分享一下,如有错误的地方,请大佬指教。

java SpringBoot 集成 阿里云视频直播 完成直播功能相关推荐

  1. java SpringBoot 集成 阿里云视频直播 完成直播功能

    经历了几天的周折,近期才把项目完成,在这里与大家分享一下踩坑之路,也方便日后有类似项目,可以借阅一番 该项目是一个H5直播,采用m3u8格式完成直播的展示.通过推流地址,借助第三方推流工具实现直播效果 ...

  2. Java SpringBoot集成阿里云短信与邮件服务

    1.pom.xml导入jar包 <!--阿里云短信 --><dependency><groupId>com.aliyun</groupId><ar ...

  3. SpringBoot集成阿里云存储OSS服务

    前言 该文章会先简单的介绍一下阿里云的OSS存储,然后演示如何在SpringBoot项目中集成OSS,每一步都有记录,保证初学者也能看懂. 文章目录 前言 1.阿里云存储OSS是什么? 2.Sprin ...

  4. SpringBoot集成阿里云短信服务

    SpringBoot集成阿里云短信服务 1.准备工作 2.项目集成 2.1 添加依赖 2.2 配置文件 2.3 业务逻辑实现 在实际项目中经常有发送短信的功能,今天进说一下对接阿里云短信服务实现短信发 ...

  5. springboot集成阿里云短信服务,实现发送短信功能

    springboot集成阿里云短信服务,实现发送短信功能 准备工作: 1.登陆阿里云->进入控制台->开通短信服务(进入后根据提示开通) 2.充值(借人家平台发短信你以为不要钱的?我充了3 ...

  6. springBOOT集成阿里云MQ-AMQP

    序: MQ的优势就不做介绍了可以自行百度,前篇写了springboot集成本地搭建的rabbitmq组建,但是项目最后部署打算还是直接使用阿里云的AMQP,阿里云AMQP是直接可以兼容rabbitmq ...

  7. springBoot集成阿里云企业邮箱

    前言 springboot项目,集成阿里云企业邮箱,进行邮件发送,附带文件 代码 public class AliyunMail {public static final String ALIDM_S ...

  8. Java代码实现阿里云视频上传

    目录 视频上传 视频删除 视频上传 新建一个springboot项目,结构大概这样 添加依赖 <dependency><groupId>com.aliyun</group ...

  9. SpringBoot集成阿里云支付

    阿里云支付 支付宝官方文档说明 https://opendocs.alipay.com/open/203/107091 开发准备 1.登录支付宝开发平台(支付宝账号) 地址: https://open ...

最新文章

  1. 面试官:你说你精通Redis,你看过持久化的配置吗?
  2. SpringMVC 上传文件and过滤器
  3. Oracle Golden Gate 系列十六 -- 配置 GG 安全 说明 与 示例
  4. android 录音原始文件_Android 11可能最终会取消Android对视频录制的4GB文件大小限制...
  5. 实力分享,聚焦分布式高可用消息队列
  6. msclass 文字滚动_MSClass (通用不间断滚动JS封装类)
  7. 我是如何获取新知识的?
  8. IHS遥感图像融合算法及其相关的算法
  9. python随机数产生--random常用功能
  10. vs2017编译x265源码
  11. Linux修改Mysql默认端口3306
  12. ANdroid的QQ分享接入,android 集成QQ互联 (登录,分享)
  13. 容器化部署之看板工具: Wekan
  14. [莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II
  15. 网络存储专有名词介绍
  16. IE浏览器闪退、自动打开Edge浏览器
  17. FAQ:sorry,too many clients already
  18. 在代码里面如何使用workman
  19. Vue设置浏览器title-icon
  20. [渝粤教育] 山东大学 生物信息学 参考 资料

热门文章

  1. 通过HttpWebRequest实现模拟登陆
  2. 区块链信息安全(区块链信息安全关键技术研究)
  3. kaldi中的egs文件夹中的demo都是干什么的
  4. python樱花代码_武大学生用Python敲出樱花开放(附源码)
  5. C++的成员函数声明与定义 —— 类外定义成员函数以及inline函数
  6. 熊市中,值得关注的项目都有这三大特征
  7. Chromium源码目录结构简介
  8. FPA Function Point Analysis 功能点分析培训免费视频地址(by陈勇)
  9. html垂直居中vertical,利用vertical-align:middle垂直居中
  10. 【tools】Beyondcompared 3 试用过期 修改注册表