springboot 整合 快手 移动应用 授权 发布视频 小黄车

 前言:

因快手文档混乱,官方社区技术交流仍有很多未解之谜,下面3种文档的定义先区分。

代码中的JSON相关工具均用hutool工具包

1.快手 移动双端 原生SDK 文档icon-default.png?t=O83Ahttps://mp.kuaishou.com/platformDocs/develop/mobile-app/ios.html

2.快手 Api 开放接口 文档icon-default.png?t=O83Ahttps://mp.kuaishou.com/platformDocs/openAbility/contentManagement/createAVideo.html

3.快手 Java 服务端SDK maven 依赖 文档icon-default.png?t=O83Ahttps://open.kuaishou.com/platform/openApi?menu=55

一、引入依赖

根据 3号 文档,虽然快手在JavaSDK中,封装了授权、用户信息、发布作品、直播等相关能力,但本次业务只涉及用户授权、发布视频,并且,SDK版的发布能力,不具备挂载小黄车的能力,所以只用到SDK中的授权能力。

            <dependency><groupId>com.github.kwaiopen</groupId><artifactId>kwai-open-sdk</artifactId><version>1.0.6</version></dependency>

二、信息配置

1.注册应用

快手有两个开放平台

①:快手开放平台——只涉及小程序

②:快手开放平台——5端统管

从 ② 进入创建开发者账户,并创建移动应用后提交审核。填写好ios和andriod信息,申请需要的权限

2.后端配置

yml中自定义参数

快手配置类
import com.github.kwai.open.api.KwaiOpenLiveApi;
import com.github.kwai.open.api.KwaiOpenOauthApi;
import com.github.kwai.open.api.KwaiOpenUserApi;
import com.github.kwai.open.api.KwaiOpenVideoApi;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;/*** 快手配置类*/
@Data
@Component
public class KuaishouConfig {/*** App*/@Value("${kuaishou.appId}")private String appId;@Value("${kuaishou.appSecret}")private String appSecret;/*** 小程序*/@Value("${kuaishou.appletId}")private String appletId;@Value("${kuaishou.appletSecret}")private String appletSecret;//快手服务端SDK接入- java版本//https://open.kuaishou.com/platform/openApi?menu=55//快手开放Api//https://mp.kuaishou.com/platformDocs/openAbility/contentManagement/createAVideo.html//发起上传Apiprivate final String startUploadApi = "https://open.kuaishou.com/openapi/photo/start_upload";//上传视频Apiprivate final String uploadApi = "http://{endpoint}/api/upload";public String getUploadApi(String endpoint) {return uploadApi.replace("{endpoint}", endpoint);}//发布视频Apiprivate final String publishApi = "https://open.kuaishou.com/openapi/photo/publish";/*** oauth2.0协议的接口封装*/private KwaiOpenOauthApi kwaiOpenOauthApi;/*** 获取用户信息的相关接口封装*/private KwaiOpenUserApi kwaiOpenUserApi;/*** 发布内容能力的相关接口封装*/private KwaiOpenVideoApi kwaiOpenVideoApi;/*** 直播能力的相关接口封装*/private KwaiOpenLiveApi kwaiOpenLiveApi;/*** 初始化API接口实例,只执行一次,保证单例*/@PostConstructpublic void init() {this.kwaiOpenOauthApi = KwaiOpenOauthApi.init(appId);this.kwaiOpenUserApi = KwaiOpenUserApi.init(appId);this.kwaiOpenVideoApi = KwaiOpenVideoApi.init(appId);this.kwaiOpenLiveApi = KwaiOpenLiveApi.init(appId);}
}

三、实现

1.授权

前端部分跳转快手,指定scope权限,获取授权码自行实现

绑定第三方Controller
/*** 绑定第三方*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/bound")
public class BoundThirdPartController extends BaseController {private final ISysUserService userService;/*** 绑定快手* @param bound* @return*/@PostMapping("/kuaishou")public R<Void> boundKuaishou(@Validated @RequestBody KuaishouBound bound){SysUser user = userService.selectUserById(getUserId());if (StringUtils.isNotEmpty(user.getKuaishouOpenId())) {return R.fail("您已绑定过快手账号");}return toAjax(userService.boundKuaishou(bound, getUserId()));}
}
import lombok.Data;
import javax.validation.constraints.NotBlank;@Data
public class KuaishouBound {/*** 快手授权码*/@NotBlank(message = "快手授权码不能为空")private String kuaishouCode;
}
用户Service
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl implements ISysUserService{private final SysUserMapper baseMapper;private final IKuaishouService kuaishouService;@Overridepublic boolean boundKuaishou(KuaishouBound bound, Long userId) {AccessTokenResponse response = kuaishouService.getKuaishouAccessToken(bound.getKuaishouCode());String openId = response.getOpenId();String accessToken = response.getAccessToken();Long expiresIn = response.getExpiresIn();//查看此openid是否有被绑定过SysUser old = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getKuaishouOpenId, openId));if (ObjectUtil.isNotNull(old)) {//自己绑定过if (old.getUserId().equals(userId)) {throw new ServiceException("您已绑定该快手账户,请勿重复绑定!");}//别人绑定过throw new ServiceException("该快手已绑定到其他用户!");}RedisUtils.setCacheObject(CacheConstants.KUAISHOU_ACCESS_TOKEN + userId, accessToken, Duration.ofSeconds(expiresIn));//更新用户数据SysUser user = new SysUser();user.setUserId(userId);user.setKuaishouOpenId(openId);return baseMapper.updateById(user) > 0;}
}
快手Service
@Slf4j
@RequiredArgsConstructor
@Service
public class IKuaishouServiceImpl implements IKuaishouService {private final KuaishouConfig kuaishouConfig;/*** 获取快手AccessToken** @param kuaishouCode 授权码*/@Overridepublic AccessTokenResponse getKuaishouAccessToken(String kuaishouCode) {try {AccessTokenRequest tokenRequest = new AccessTokenRequest(kuaishouCode, kuaishouConfig.getAppSecret());return kuaishouConfig.getKwaiOpenOauthApi().getAccessToken(tokenRequest);} catch (KwaiOpenException e) {throw new RuntimeException(e);}}}

2.发布视频

文章开头说到的三种文档,都有各自的发布视频实现,这里选择第2种,Api的文档,因为只有Api接口中,可以带上小黄车的商品id。

但是! 不要高兴的太早!

这里的商品id,只能是发布视频的账号下的橱窗自建商品。

附上我与快手社区官方的交流

接受了这点,就可以看接下来的代码了。或者你不需要挂载小黄车的功能,可以考虑更方便的3号文档中的实现方式

 业务Service
//快手创建一个视频需要执行 发起上传、上传视频、发布视频 三个步骤
//1.发起上传
JSONObject startResult = kuaishouService.startUpload(userId);
//2.上传视频
String endpoint = startResult.get("endpoint", String.class);
String uploadToken = startResult.get("upload_token", String.class);
Boolean uploadResult = kuaishouService.uploadMp4(endpoint,uploadToken,"mp4短视频 http url 地址");
//3.发布视频
JSONObject publishResult = kuaishouService.publishVideo(userId, "封面图 http url 地址", uploadToken, "短视频标题 (示例#话题)", "NOT_SPHERICAL_VIDEO", "快手账户 快手小店 中 商品id");
// 4.得到的publishResult 结果,进行业务处理
…………
…………
快手Service
    @Overridepublic JSONObject startUpload(Long userId) {//获取用户授权的快手tokenString accessToken = RedisUtils.getCacheObject(CacheConstants.KUAISHOU_ACCESS_TOKEN + userId);if (StringUtils.isEmpty(accessToken)) {throw new ServiceException("快手授权过期");}String result = HttpRequest.post(kuaishouConfig.getStartUploadApi() + "?access_token=" + accessToken + "&app_id=" + kuaishouConfig.getAppId()).execute().body();/*结果示例{"result": 1}*/JSONObject json = JSONUtil.parseObj(result);if (json.get("result", Integer.class) != 1) {throw new ServiceException("向快手发起上传请求失败,请稍后再试");}return json;}@Overridepublic Boolean uploadMp4(String endpoint, String uploadToken, String fileUrl) {//此接口的视频上传,只接受二进制,url转二进制byte[] bytes = FileUtils.urlToByteArray(fileUrl);String result = HttpRequest.post(kuaishouConfig.getUploadApi(endpoint) + "?upload_token=" + uploadToken).header("Content-Type", "video/mp4").body(bytes).execute().body();/*结果示例{"result": 1}*/if (!JSONUtil.isTypeJSON(result)) {log.error("快手上传视频失败,{}", result);throw new ServiceException("上传视频失败");}return JSONUtil.parseObj(result).get("result", Integer.class) == 1;}@Overridepublic JSONObject publishVideo(Long userId, String coverImg, String uploadToken, String skitsTitle, String panoramicParams, Integer productId) {//获取用户授权的快手tokenString accessToken = RedisUtils.getCacheObject(CacheConstants.KUAISHOU_ACCESS_TOKEN + userId);if (StringUtils.isEmpty(accessToken)) {throw new ServiceException("快手授权过期");}//上传封面又只接受File文件,主打一个混乱🤬🤬🤬File file = FileUtils.urlToFile(coverImg, "jpg");String body = HttpRequest.post(kuaishouConfig.getPublishApi() + "?access_token=" + accessToken + "&app_id=" + kuaishouConfig.getAppId() + "&upload_token=" + uploadToken).header("Content-Type", "multipart/form-data").form("cover", file)//封面图(10MB内).form("caption", skitsTitle)//标题//.form("stereo_type", panoramicParams)//全景视频参数//.form("merchant_product_id", productId)//需要挂载小黄车的商品ID.execute().body();/* 结果示例{"result": 1,"video_info": {//pending代表作品还在处理中,true时没有下面的play_url等参数"pending": true,"caption": "#测试1 #测试2 #测试3","view_count": 0,"comment_count": 0,"like_count": 0,"cover": "","play_url": "","photo_id": "3xf4z2c8d9awkgg","create_time": 1728634351884}}*/JSONObject result = JSONUtil.parseObj(body);if (result.get("result", Integer.class) != 1) {log.error("快手发布视频失败,{}", body);throw new ServiceException("视频分享失败,请稍后再试");}return JSONUtil.parseObj(result.get("video_info", JSONObject.class));}
FileUtils工具类
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;/*** 文件处理工具类*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FileUtils extends FileUtil {/*** url转二进制** @param url* @return*/public static byte[] urlToByteArray(String url) {//通过URL 流 下载 文件的二进制数据ByteArrayOutputStream outStream = new ByteArrayOutputStream();try {HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();urlConnection.setConnectTimeout(5000);urlConnection.setRequestMethod("GET");InputStream inputStream = urlConnection.getInputStream();byte[] buffer = new byte[1024];int len;while ((len = inputStream.read(buffer)) != -1) {outStream.write(buffer, 0, len);}//关闭输入流inputStream.close();} catch (Exception e) {log.error("短剧资源转二进制异常:{}", e.getMessage());}byte[] data = new byte[0];data = outStream.toByteArray();if (data.length == 0) {log.error("短剧资源二进制数据大小为0");throw new ServiceException("短剧资源异常");}return data;}/*** url转File** @param coverImg* @param fileType* @return*/public static File urlToFile(String coverImg, String fileType) {File file = new File("temp/" + IdUtil.fastSimpleUUID() + "." + fileType);try {URL url = new URL(coverImg);org.apache.commons.io.FileUtils.copyURLToFile(url, file);} catch (Exception e) {log.error("文件转换异常:{}", e.getMessage());throw new ServiceException("文件转换异常");}return file;}}

为了弄清混乱的快手开发,和根本没有官方技术回答,整理不易。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/447221.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch设置 X-Pack认证,设置账号和密码

前言 以下Elasticsearch版本&#xff1a;7.9.3 ES自带的X-Pack密码验证&#xff1a; X-Pack是elasticsearch的一个扩展包&#xff0c;将安全&#xff0c;警告&#xff0c;监视&#xff0c;图形和报告功能捆绑在一个易于安装的软件包中&#xff0c;所以我们想要开启账号密码验证…

网优学习干货:王者荣耀游戏用户体验洞察及质差识别(1)

一、课题背景 二、课题目的 针对热点游戏&#xff08;王者荣耀&#xff09;进行业务质量评估&#xff0c;并通过对端到端定界分析&#xff0c;从无线、核心网、互联网维度识别影响用户体验关键因素&#xff0c;为游戏用户的体验优化提供依据。 三、课题实施进度 王者荣耀卡顿特…

linux------缓冲区与C库的原理

前言 一、缓冲区 缓冲区的作用是提高效率&#xff0c;因为将数据写入到设备&#xff0c;是需要调用系统接口的&#xff0c;如果每次写入缓冲区的数据就调用一次系统调用&#xff0c;涉及到系统调用这时操作系统就会介入&#xff0c;用户态转为内核态&#xff0c;这个过程需要时…

linux 搭建sentinel

1.下载 linux执行下面的命令下载包 wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar2.启动 nohup java -Dserver.port9090 -Dcsp.sentinel.dashboard.serverlocalhost:9090 -Dproject.namesentinel-dashboard -jar sentin…

k8s中控制器的使用

一、replicaset控制器 ReplicaSet 是下一代的 Replication Controller&#xff0c;官方推荐使用ReplicaSet ReplicaSet和Replication Controller的唯一区别是选择器的支持&#xff0c;ReplicaSet支持新的基于集合的选择器需求 ReplicaSet 确保任何时间都有指定数量的 Pod 副…

Metasploit渗透测试之攻击终端设备和绕过安全软件

概述 在之前&#xff0c;重点讨论了针对服务器端的利用。但在当下&#xff0c;最成功的攻击都是针对终端的&#xff1b;原因是&#xff0c;随着大部分安全预算和关注都转向面向互联网的服务器和服务&#xff0c;越来越难找到可利用的服务&#xff0c;或者至少是那些还没有被破…

数据库设计与开发—初识SQLite与DbGate

一、SQLite与DbGate简介 &#xff08;一&#xff09;SQLite[1][3] SQLite 是一个部署最广泛、用 C 语言编写的数据库引擎&#xff0c;属于嵌入式数据库&#xff0c;其作为库被软件开发人员嵌入到应用程序中。 SQLite 的设计允许在不安装数据库管理系统或不需要数据库管理员的情…

一篇文章快速认识YOLO11 | 关键改进点 | 安装使用 | 模型训练和推理

前言 本文分享YOLO11的关键改进点、性能对比、安装使用、模型训练和推理等内容。 YOLO11 是 Ultralytics 最新的实时目标检测器&#xff0c;凭借更高的精度、速度和效率重新定义了可能性。 除了传统的目标检测外&#xff0c;YOLO11 还支持目标跟踪、实例分割、姿态估计、OBB…

深入理解 C/C++ 指针

深入理解 C 指针&#xff1a;指针、解引用与指针变量的详细解析 前言 在 C 编程语言中&#xff0c;指针 是一个非常强大且重要的概念。对于初学者来说&#xff0c;指针往往会让人感到困惑不解。本文将通过形象的比喻&#xff0c;帮助大家深入理解指针、解引用与指针变量的概念…

【算法】哈希表:49.字母异位词分组

目录 1、题目链接 2、题目介绍 3、解法 初始化设定--图解 步骤图解 4、代码 1、题目链接 49. 字母异位词分组 - 力扣&#xff08;LeetCode&#xff09; 2、题目介绍 3、解法 字母异位词的本质是字符相同但排列不同。因此&#xff0c;我们可以对字符串进行排序&#xf…

wordpress使用popup弹窗插件的对比

您在寻找最好的 WordPress 弹出插件吗&#xff1f;大多数网站利用某种形状或形式的弹出窗口来将访问者指向他们希望他们去的地方。例如&#xff0c;这可能用于结帐、电子邮件订阅或用于生成潜在客户。 表现 弹出插件会减慢您的网站速度。当插件使用 WordPress 跟踪弹出窗口的…

K8S配置MySQL主从自动水平扩展

前提环境 操作系统Ubuntu 22.04 K8S 1.28.2集群&#xff08;1个master2个node&#xff09; MySQL 5.7.44部署在K8S的主从集群 metrics-server v0.6.4 概念简介 在K8s中扩缩容分为两种 ●Node层面&#xff1a;对K8s物理节点扩容和缩容&#xff0c;根据业务规模实现物理节点自动扩…

《大规模语言模型从理论到实践》第一轮学习--强化学习(RLHF、PPO)

个人学习笔记,如有错误欢迎指出。 一、强化学习的意义 RLHF(Reinforcement Learning from Human Feedback):强化学习(Reinforcement Learning)结合人类反馈(Human Feedback)来微调大语言模型。 大语言模型的训练步骤包括:预训练、指令微调(SFT)、对齐。 对齐(a…

MWD天气图像多分类数据集,用于图像分类-共6个类别,共60000张图像数据 ,含有模型

MWD天气图像多分类数据集&#xff0c;用于图像分类- MWD天气图像多分类数据集&#xff0c;用于图像分类-共6个类别&#xff0c;共60000张图像数据 &#xff0c;含有模型 MWD天气图像多分类数据集及模型介绍 数据集概述 名称&#xff1a;MWD天气图像多分类数据集图像数量&…

使用node.js控制CMD命令——修改本机IP地址

设置每次打开cmd命令行窗口都是以管理员身份运行&#xff1a; 1. 按下Ctrl Shift Esc键组合&#xff0c;打开任务管理器。 2. 在任务管理器中&#xff0c;点击“文件”菜单&#xff0c;选择“运行新任务”。 3. 在“创建新任务”对话框中&#xff0c;输入cmd&#xff0c;勾…

基于知识图谱的宁夏非遗问答系统

八维视角探索宁夏非遗文化——基于知识图谱的非遗问答系统 作为一名程序员&#xff0c;能将大数据与文化传承结合&#xff0c;赋予历史新的生命&#xff0c;是件多么振奋的事&#xff01;今天给大家介绍的是一款基于知识图谱技术的宁夏非物质文化遗产问答系统。无论你是学术研…

Scrapy网络爬虫基础

使用Spider提取数据 Scarpy网络爬虫编程的核心就是爬虫Spider组件&#xff0c;它其实是一个继承与Spider的类&#xff0c;主要功能设计封装一个发送给网站服务器的HTTP请求&#xff0c;解析网站返回的网页及提取数据 执行步骤 1、Spider生成初始页面请求&#xff08;封装于R…

【未公开0day】9.9付费进群系统 wxselect SQL注入漏洞【附poc下载】

免责声明&#xff1a;本文仅用于技术学习和讨论。请勿使用本文所提供的内容及相关技术从事非法活动&#xff0c;若利用本文提供的内容或工具造成任何直接或间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果均与文章作者及本账号无关。 fofa语…

Java Maven day1014

ok了家人们&#xff0c;今天学习了如何安装和配置Maven项目&#xff0c;我们一起去看看吧 一.Maven概述 1.1 Maven作用 Maven 是专门用于管理和构建 Java 项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构 提供了一套标准化的构建流程&#x…

【2D/3D-Lidar-SLAM】 2D/3D激光SLAM以及GMapping 与 Cartographer

这里写自定义目录标题 1. 激光SLAM分类2. 2D Lidar SLAM3. 3D Lidar SLAM4. GMapping**1. GMapping 系统架构**1.1 **粒子滤波器Particle Filter**1.2 **运动模型Motion Model**1.3 **传感器模型Sensor Model**1.4 **地图更新Map Update**1.5 **重采样Resampling**1.6 **闭环检…