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.mzph.cn/web/55090.shtml

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

相关文章

物联网智能项目(含案例说明)

物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;智能项目是指利用物联网技术将各种物理设备、传感器、软件、网络等连接起来&#xff0c;实现设备之间的互联互通&#xff0c;并通过数据采集、传输、处理和分析&#xff0c;实现智能化管理和控制的项目。以…

Qt入门教程:创建我的第一个小程序

本章教程&#xff0c;主要介绍如何编写一个简单的QT小程序。主要是介绍创建项目的过程。 一、打开QT软件编辑器 这里使用的是QT5.14.2版本的&#xff0c;安装教程参考以往教程&#xff1a;https://blog.csdn.net/qq_19309473/article/details/142907096 二、创建项目 到这里&am…

【Docker】03-自制镜像

1. 自制镜像 2. Dockerfile # 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["ja…

Flutter应用解析(一)

1、创建项目 1.1 新建 1.2 选择Flutter SDK的位置 1.3 项目名称 英文单词加下划线起名规范&#xff0c;其他默认即可。 1.4 点击运行 发生报错显示我们的JAVA版本不符合 1.5 更改版本设置 1.6 再次启动项目 2、分析页面代码 以下是lib/main.dart的源代码&#xff08;为了阅…

【机器学习】朴素贝叶斯算法|商品评论情感分析案例介绍及代码实现

文章目录 朴素贝叶斯算法朴素贝叶斯算法介绍概率数学基础复习朴素贝叶斯算法-利用概率值进行分类的一种机器学习算法贝叶斯公式朴素贝叶斯算法拉普拉斯平滑系数 朴素贝叶斯API案例分析流程数据集代码实现运行结果 朴素贝叶斯算法 朴素贝叶斯算法介绍 概率数学基础复习 条件概…

架构设计笔记-11-未来信息综合技术

知识要点 云原生架构原则包括&#xff1a;服务化原则、弹性原则、可观测原则、韧性原则、所有过程自动化原则、零信任原则和架构持续演进原则。 区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学方式保证的不可篡改和不可…

CVE-2022-26965靶机渗透

​ 开启环境 ​ ​ 进入环境 ​ ​ 使用弱口令admin登录 ​ ​ 利用cms主题构造木马 ​ 需要将主题中的info.php文件修改&#xff0c;再打包成zip再上传&#xff0c;通过网络搜索找到Github中的Pluck CMS&#xff0c;进入后随便下载任一主题 https://github.com/sear…

服务性能优化之mybatis-plus 开启与关闭 SQL 日志打印

Hello&#xff01;欢迎各位新老朋友来看小弟博客&#xff0c;祝大家事业顺利&#xff0c;财源广进&#xff01;&#xff01; 主题&#xff1a;mybatis-plus 开启与关闭 SQL 日志打印 第一&#xff1a;开启打印 Mybatis-plus 需要通过下面的方式开启控制台 SQL 日志打印 myba…

和鲸科技创始人范向伟:拐点即将来临,AI产业当前的三个瓶颈

在科技迅猛发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑已经成为引领新一轮产业革命的核心动力之一。全球企业纷纷拥抱AI技术&#xff0c;试图借助其变革力量在竞争中突围&#xff0c;然而业界对AI产业化的拐点何时来临却众说纷纭。毕竟AI技术从实验室到商业…

4K变倍镜头特点

1、高分辨率成像&#xff1a; ① 能够呈现清晰、细腻的图像&#xff0c;可清晰快速地识别出被测物体的微小细节、特征以及潜在的缺陷等。例如在芯片外观瑕疵检测中&#xff0c;能清晰地分辨出芯片上的刮痕、污渍、破损、引脚缺失等问题。 ② 相比传统的变倍镜头&#xff0c;在…

LabVIEW提高开发效率技巧----队列使用

在LabVIEW开发中&#xff0c;队列是实现并行处理、数据传递和任务调度的关键机制之一&#xff0c;合理使用队列可以有效提高程序性能并避免内存问题。结合队列长度限制和其他队列相关技巧&#xff0c;以下是队列使用的详细说明&#xff1a; 1. 队列长度限制 限制队列的长度可以…

全面讲解C++

数据类型 1.1 基本数据类型 1.1.1 整型&#xff08;Integer Types&#xff09; 整型用于表示整数值&#xff0c;分为以下几种类型&#xff1a; int&#xff1a;标准整数类型&#xff0c;通常为4字节&#xff08;32位&#xff09;。short&#xff1a;短整型&#xff0c;通常…

量子数字签名概述

我们都知道&#xff0c;基于量子力学原理研究密钥生成和使用的学科称为量子密码学。其内容包括了量子密钥分发、量子秘密共享、量子指纹识别、量子比特承诺、量子货币、秘密通信扩展量子密钥、量子安全计算、量子数字签名、量子隐性传态等。虽然各种技术发展的状态不同&#xf…

FreeRTOS学习总结

背景&#xff1a;在裸机开发上&#xff0c;有时候我们需要等待某个信号或者需要延迟时&#xff0c;CPU的运算是白白浪费掉了的&#xff0c;CPU的利用率并不高&#xff0c;我们希望当一个函数在等待的时候&#xff0c;可以去执行其他内容&#xff0c;提高CPU的效率&#xff0c;同…

windows修改文件最后修改时间

一、需要修改日期的文件 背景:有时候我们需要做一些文件定期删除的操作,但是测试时候并不一定有符合测试的文件,这时候就需要可以方便的修改文件的最后修改时间。 系统环境:windows 测试文件:如上 修改时间方式:windows 脚本。 二、测试脚本 (1) 脚本 # 指定文件路径 …

自然语言处理:第五十三章 Ollama

代码&#xff1a; ollama/ollama: Get up and running with Llama 3.1, Mistral, Gemma 2, and other large language models. (github.com) 官网&#xff1a; Ollama 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易…

Android Framework默认授予app通知使用权限

安卓通知使用权限 在安卓系统中&#xff0c;应用程序需要获取通知使用权限才能向用户发送通知。以下是关于安卓通知使用权限的一些信息&#xff1a; 权限获取方式 当用户安装应用时&#xff0c;系统可能会在安装过程中提示用户授予应用通知权限。用户可以选择允许或拒绝。 应…

架构设计笔记-18-安全架构设计理论与实践

知识要点 常见的安全威胁&#xff1a; 信息泄露&#xff1a;信息被泄露或透露给某个非授权的实体。破坏信息的完整性&#xff1a;数据被非授权地进行增删、修改或破坏而受到损失。拒绝服务&#xff1a;对信息或其他资源的合法访问被无条件地阻止。攻击者向服务器发送大量垃圾…

OCM认证考试须知:掌握这些关键点,轻松应对考试

在Oracle认证体系中&#xff0c;OCM&#xff08;OracleCertifiedMaster&#xff09;是最高级别的认证。它代表了在Oracle数据库技术领域的顶尖水平。 OCM认证不仅要求你具备深厚的理论知识&#xff0c;还要求你能够解决复杂的数据库问题&#xff0c;并具备高级的项目管理能力。…

数据结构期中代码注意事项(二叉树及之前)1-11

注意&#xff1a;链表为空。是否越界访问。每写一步都要思考该步是否会有越界&#xff08;多/少&#xff09;等问题。这一步是否有不能走的条件&#xff08;删除的时候不为空&#xff09;。只有该节点开辟了空间&#xff0c;该节点才能被指向。能用c就用c。#include <iostre…