抖音 - 抖店开放平台 SDK

抖音 - 抖店开放平台:https://op.jinritemai.com/
该 SDK 已实现 API 接口调用和消息推送验证解析

项目地址

github:
gitee:

项目结构

  • 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.com
  appKey: 
  appSecret:
  signMethod: md5
  readTimeout: 30000
  version: 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)

    1. 基类(DoudianRequest)
      该基类为一个接口,含有两个方法:
          getMethod():用于请求时,构建请求路径,从而指定请求接口
          getResponseClass():用于请求结果返回时,构建对应的 Response;必须被实现

    2. 分页基类(BasePage)
      主要有两个参数:page(当前页码,从 0 开始)、size(每页条数)

    3. 具体接口请求类(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;
      
         @Override
         public Class<DoudianOrderDetailResponse> getResponseClass() {
             return DoudianOrderDetailResponse.class;
         }
      }
      
  • 返回基类(Response)

    1. 基类(DoudianResponse)
      该基类后跟上一个泛型,标识具体返回参数类
      返回基础结构如下:

      {
        "err_no": 0,
        "message": "success",
        "logId": "20210831199610203011"
        "data": {}
      }
      
    2. 分页基类(DoudianPage)
      该基类后跟上一个泛型,标识具体返回参数类,指明具体分页数据类型

    3. 具体接口返回类(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)

    1. 普通返回参数类
      根据抖店开放平台接口具体返回参数进行定义

      如:

      /**
       * 描述:获取抖店订单详情返回参数
       *
       * @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 {
    @Autowired
    private 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 天

  1. 建议将 access_token 和 refresh_token 都存放至 redis
  2. 在 7 天内,直接从 redis 中获取 access_token
  3. 在 7 ~ 14 天内,通过 refresh_token 去抖店开放平台刷新并获取 access_token
  4. 在 14 天后,直接去抖店开放平台重新创建获取 access_token

可参考如下代码:

DoudianOauthHandler

/**
 * 描述:抖店平台 access_token 相关业务处理
 *
 * @author chengqb
 * @className DoudianOauthHandler
 * @date 2021/8/20 10:13
 */
@Slf4j
@Service
public class DoudianOauthHandler {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private 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_token
            DoudianAccessToken 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 {
    @Autowired
    private 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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐