抖音 - 抖店开放平台 SDK
抖音 - 抖店开放平台:https://op.jinritemai.com/
该 SDK 已实现 API 接口调用和消息推送验证解析
项目地址
项目结构
- common-rocketmq: 根据 阿里 com.aliyun.openservices 的 ons-client 第三方依赖,自定义实现的 rocketmq 基础工程
- doudian-open-sdk: 对接 抖音 - 抖店开放平台接口 的 SDK 工程
- doudian-open-test: 结合 common-rocketmq 与 doudian-open-sdk ,测试 SpringBoot 项目中 抖音 - 抖店开放平台接口 SDK 的使用
API 接口
API 文档:https://op.jinritemai.com/docs/guide-docs/10/814
注: 该 SDK 目前只适用于自用型应用,实现了自用型应用 client;后续补充工具型应用;两者的差别仅存在于获取授权的方式不一样
获取可用的 client
- 自用型应用 client
建议使用配置文件配置参数 + Bean 注入方式,来构建自用型应用 client
在配置文件中配置
doudian:serverUrl: https://openapi-fxg.jinritemai.comappKey: appSecret:signMethod: md5readTimeout: 30000version: 2
Bean 注入 DoudianClient
@Value("${spring.profiles.active}")
private String env;@Autowired
private DoudianProperties doudianProperties;/*** 描述:默认的抖店开放平台 client(默认为自用型应用)** @methodName defaultDoudianClient* @param* @return {@link DoudianClient}* @date 2021/8/20 10:42* @author chengqb*/
@Bean
public DoudianClient defaultDoudianClient() {DefaultDoudianClient defaultDoudianClient = new DefaultDoudianClient();defaultDoudianClient.setServerUrl(doudianProperties.getServerUrl());defaultDoudianClient.setAppKey(doudianProperties.getAppKey());defaultDoudianClient.setAppSecret(doudianProperties.getAppSecret());defaultDoudianClient.setSignMethod(doudianProperties.getSignMethod());defaultDoudianClient.setReadTimeout(doudianProperties.getReadTimeout());defaultDoudianClient.setVersion(doudianProperties.getVersion());defaultDoudianClient.setEnv(env);return defaultDoudianClient;
}
- 工具型应用 client
Client 方法
- 创建并获取 access_token
- 刷新并获取 access_token
- API 接口调用(通用)
具体代码如下:
/*** 描述:抖店平台 api 调用工具** @author chengqb* @className DoudianClient* @date 2021/8/19 10:30*/
public interface DoudianClient extends Cloneable {/*** 描述:创建并获取授权** @methodName getAccessToken* @param* @return {@link DoudianAccessToken}* @date 2021/8/19 10:38* @author chengqb*/DoudianAccessToken getAccessToken();/*** 描述:刷新并获取授权** @methodName getAccessToken* @param refreshToken* @return {@link DoudianAccessToken}* @date 2021/8/19 10:38* @author chengqb*/DoudianAccessToken getAccessToken(String refreshToken);/*** 描述:抖店接口调用** @methodName execute* @param request* @param accessToken* @return {@link T}* @date 2021/8/19 10:38* @author chengqb*/<T extends DoudianResponse> T execute(DoudianRequest<T> request, String accessToken);
}
SDK 调用类名规则
-
请求类(Request)
-
基类(DoudianRequest)
该基类为一个接口,含有两个方法:
getMethod():用于请求时,构建请求路径,从而指定请求接口
getResponseClass():用于请求结果返回时,构建对应的 Response;必须被实现 -
分页基类(BasePage)
主要有两个参数:page(当前页码,从 0 开始)、size(每页条数) -
具体接口请求类(Request)
必须实现 DoudianRequest 接口
需要分页请求的接口,具体接口请求类需继承 BasePage 类
必须定义private final String method = "";
具体值,根据抖店开放平台 API 文档中的接口而定
注: method 由 “.” 分隔,具体可查看抖店开放平台 API 文档
如:
必须实现 getResponseClass() ,并指定具体的返回基类(Response)
再补充定义具体接口所需请求参数,如:shopOrderId(店铺订单号)如:
/*** 描述:获取抖店订单详情请求类** @author chengqb* @className DoudianOrderDetailRequest* @date 2021/8/25 17:59*/ @Data public class DoudianOrderDetailRequest implements DoudianRequest<DoudianOrderDetailResponse> {private final String method = "order.orderDetail";/*** 店铺订单号*/private String shopOrderId;@Overridepublic Class<DoudianOrderDetailResponse> getResponseClass() {return DoudianOrderDetailResponse.class;} }
-
-
返回基类(Response)
-
基类(DoudianResponse)
该基类后跟上一个泛型,标识具体返回参数类
返回基础结构如下:{"err_no": 0,"message": "success","logId": "20210831199610203011""data": {} }
-
分页基类(DoudianPage)
该基类后跟上一个泛型,标识具体返回参数类,指明具体分页数据类型 -
具体接口返回类(Response)
必须继承 DoudianResponse 类,并指定泛型
若为分页请求,DoudianResponse 的泛型指定为 DoudianPage ;而 DoudianPage 的泛型再指定为具体参数类;
如:public class DoudianSettleBillResponse extends DoudianResponse<DoudianPage<DoudianSettleBill>>
如:
/*** 描述:获取抖店订单详情返回类** @author chengqb* @className DoudianOrderDetailResponse* @date 2021/8/25 18:00*/ @Data public class DoudianOrderDetailResponse extends DoudianResponse<DoudianOrderDetail> { }
-
-
返回参数类(Entity)
-
普通返回参数类
根据抖店开放平台接口具体返回参数进行定义如:
/*** 描述:获取抖店订单详情返回参数** @author chengqb* @className DoudianOrderDetail* @date 2021/8/25 18:01*/ @Data public class DoudianOrderDetail {/*** 抖店订单详情信息*/private ShopOrderDetail shopOrderDetail; }
-
订阅消息接收
抖店订阅消息推送:https://op.jinritemai.com/docs/guide-docs/10/99
注: 需定义个接口,专门接收抖店各类订阅消息;再将该接口路径拼接上请求协议及请求域名,再填写至抖店开放平台配置中
此处,要求在 5 s 内必须返回 {"code":0,"msg":"success"}
;故而,建议在接收到消息内容并解析完成后,立即返回指定格式数据给抖店,再通过 异步来处理业务 ;doudian-open-test 使用了 mq 消息 的方式来实现了异步处理
-
基础返回类(BaseResponse)
只含有 code、msg 两个参数字段 -
基础数据类(DoudianMessageData )
含有 tag、msgId、data 三个参数字段;其中 data 为字符串类型,存放具体数据;
含有 toObject(Class tClass) 方法,可将 data 字符串数据转换为具体的订阅消息数据如: DoudianOrderPaySuccess 为抖店订单支付成功订阅消息数据类
DoudianMessage pushMessage = DoudianMessageUtil.getDoudianMessage(request); List<DoudianMessageData> pushDataList = pushMessage.getData(); for (DoudianMessageData messageData : messageDataList) {DoudianOrderPaySuccess orderPaySuccess = messageData.toObject(DoudianOrderPaySuccess.class); }
-
基础消息类(DoudianMessage)
含有 appId、eventSign、body 三个参数字段;其中 body 为字符串类型,存放具体数据;
含有 getData() 方法,可将 body 字符串数据转换为 DoudianMessageData 列表 -
消息获取
该 SDK 定义了 DoudianMessageUtil 工具类
其中的public static DoudianMessage getDoudianMessage(HttpServletRequest request)
方法,可解析获取抖店开放平台订阅消息
具体代码可参考:
/*** 描述:抖店开放平台订阅消息推送接收** @author chengqb* @className DoudianMessageController* @date 2021/8/20 17:05*/
@Slf4j
@RestController
@Api(tags = "抖店消息")
@RequestMapping("/doudian/message")
public class DoudianMessageController {@Autowiredprivate DoudianMessageDataHandler doudianMessageDataHandler;/*** 描述:抖店订阅消息接收** @methodName receiveMessage* @param request* @return {@link BaseResponse}* @date 2021/8/12 14:42* @author chengqb*/@ApiOperation(value = "抖店订阅消息接收", notes = "接收")@PostMapping("/receiveMessage")public BaseResponse receiveMessage(HttpServletRequest request) {// return BaseResponse.failed(1, "测试中");DoudianMessage pushMessage = DoudianMessageUtil.getDoudianMessage(request);if (CollectionUtil.isEmpty(pushMessage.getData())) {log.info("接收到抖店平台订阅消息,但消息解析失败");return BaseResponse.failed(ReponseEnum.DATA_BLANK.getCode(), ReponseEnum.DATA_BLANK.getMsg());} else {// 推送地址添加后,平台会立即 Post 一条 "[{"tag":"0","msg_id":"0","data":"2020-09-10T16:27:56.52842897+08:00"}]" 的测试消息,// 必须返回 {"code":0,"msg":"success"} ,否则平台判定推送地址异常,将无法启用消息推送服务// (注意:超时也会被认为是推送失败,超时时间是5s)List<DoudianMessageData> pushDataList = pushMessage.getData();// 接收到抖店平台推送消息后,必须返回{"code":0,"msg":"success"}if (pushDataList.size() == 1 && "0".equals(pushDataList.get(0).getTag())) {log.info("接收到抖店平台订阅消息,消息 tag 为:{}", pushDataList.get(0).getTag());return BaseResponse.ok();} else {log.info("接收到抖店平台订阅消息,并解析成功");// 处理抖店订阅消息数据doudianMessageDataHandler.proccessPushData(pushDataList);// return BaseResponse.failed(1, "测试中");return BaseResponse.ok();}}}
}
access_token 获取
店铺授权:https://op.jinritemai.com/docs/guide-docs/9/20
access_token 获取后,有效期为 7 天,而 refresh_token 有效期为 14 天
- 建议将 access_token 和 refresh_token 都存放至 redis
- 在 7 天内,直接从 redis 中获取 access_token
- 在 7 ~ 14 天内,通过 refresh_token 去抖店开放平台刷新并获取 access_token
- 在 14 天后,直接去抖店开放平台重新创建获取 access_token
可参考如下代码:
DoudianOauthHandler
/*** 描述:抖店平台 access_token 相关业务处理** @author chengqb* @className DoudianOauthHandler* @date 2021/8/20 10:13*/
@Slf4j
@Service
public class DoudianOauthHandler {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate DoudianOpenOauthHandler doudianOpenOauthHandler;private static final String DOUDIAN_ACCESS_TOKEN_KEY = "doudian:access_token";private static final String DOUDIAN_REFRESH_TOKEN_KEY = "doudian:refresh_token";/*** 描述:获取抖店授权* 文档地址:https://op.jinritemai.com/docs/guide-docs/9/21** @methodName getOauthToken* @param* @return {@link String}* @date 2021/8/16 16:08* @author chengqb*/public String getOauthToken() {Object accessTokenObject = redisTemplate.opsForValue().get(DOUDIAN_ACCESS_TOKEN_KEY);if (ObjectUtil.isNull(accessTokenObject)) {String refreshToken = (String) redisTemplate.opsForValue().get(DOUDIAN_REFRESH_TOKEN_KEY);// 获取 access_tokenDoudianAccessToken accessToken = doudianOpenOauthHandler.getAccessToken(refreshToken);redisTemplate.opsForValue().set(DOUDIAN_ACCESS_TOKEN_KEY, accessToken, accessToken.getExpiresIn(), TimeUnit.SECONDS);redisTemplate.opsForValue().set(DOUDIAN_REFRESH_TOKEN_KEY, accessToken.getRefreshToken(), 14, TimeUnit.DAYS);return accessToken.getAccessToken();}DoudianAccessToken accessToken = JSONUtil.toBean(JSONUtil.toJsonStr(accessTokenObject), DoudianAccessToken.class);return accessToken.getAccessToken();}
}
DoudianOpenOauthHandler
/*** 描述:抖店平台对接 access_token 相关业务处理** @author chengqb* @className DoudianOpenOauthHandler* @date 2021/8/20 10:15*/
@Slf4j
@Service
public class DoudianOpenOauthHandler {@Autowiredprivate DoudianClient defaultDoudianClient;/*** 描述:获取 access_token** @methodName getAccessToken* @param refreshToken* @return {@link DoudianAccessToken}* @date 2021/8/20 10:39* @author chengqb*/public DoudianAccessToken getAccessToken(String refreshToken) {DoudianAccessToken accessToken = null;if (StrUtil.isBlank(refreshToken)) {// 如果刷新令牌也过期了,则调用获取 access_token 接口accessToken = defaultDoudianClient.getAccessToken();} else {// 如果刷新令牌还未过期了,则调用刷新 access_token 接口accessToken = defaultDoudianClient.getAccessToken(refreshToken);}return accessToken;}
}
参考资料: https://github.com/cnJun/sdk4-jinritemai