目录

一.前言

二.账号

三.数据源

四.涉及接口以及大致流程

1.广告主账号授权. (授权给开发者账号)

2.获取access_token

3.上传用户行为

五.代码


一.前言

不知道有没有跟我一样的同学, 每次新对接的一个腾讯产品的时候看着它的api就感觉头疼哈哈
官方文档链接 :https://developers.e.qq.com/docs/start

二.账号

关于client_id和client_secret, 这个是要在开发者账号中新建应用, 进而获取到client_id和client_secret, 在我向运营小姐姐要这个参数的时候, 她以为这个是广告主账号里面应用的appid就给我了, 所以在进行访问授权链接的时候就会提示"加载应用信息失败,您授权的应用id不存在,请联系您授权应用的开发者确认该授权链接是否有误" . .

三.数据源

数据源广告主账号可以在页面上直接创建暂且不谈

四.涉及接口以及大致流程

1.广告主账号授权. (授权给开发者账号)

http://developers.e.qq.com/oauth/authorize?client_id=(开发者账号创建出的应用的id)&redirect_uri=自己的服务器接口地址md5(用来接收回调,可获得authorization_code)

仅仅需要把链接在浏览器上访问一下, 然后用广告主账号登录后同意授权给开发者账号的应用对应的权限. 介时, 腾讯会回调配置好的链接, 并带参数回去, 具体参数参考api, 其中最主要的就是带有authorization_code, 这是获取access_token与refresh_token的必要参数

2.获取access_token

获取access_token总共有两种方式, 一个是通过authorization_code, 另一个是通过refresh_token. 这两种都是要被使用的. 下面将介绍其中的区别与使用

在第一次授权回调时, 就会获得authorization_code(有效时长很短), 这时候就要用到第一种方式(通过authorization_code)来获取access_token. 而且refresh_token也是在第一种获取access_token的方式中一起返回的参数. 这个时候记录下refresh_token, 以后在access_token过期时(24小时过期), 就可以通过refresh_token(30天过期)来获取了
第一种和第二种获取access_token方式的接口地址是一样的: https://api.e.qq.com/oauth/token, 但是不同类型的话grant_type参数的传递值要有所不同

3.上传用户行为

在上传用户行为时, 调用的接口:

https://api.e.qq.com/v1.1/user_actions/add?access_token=之前获取的access_token&timestamp=当前时间戳(单位秒)&nonce=随机32为字符串

请求参数(Post Content-Type: application/json):

{"account_id": "广告主账号","user_action_set_id": "数据源id(广告主那边可以获得)","actions": [{"action_time": 当前时间戳(秒),"user_id": {"hash_imei": "设备号"},"action_type": "枚举类型"}]
}

五.代码

    //回调@ResponseBody@RequestMapping(value = "/callback/Tencent/promotion")public BizResult setAccessToken(HttpServletRequest request) {String domain = "http://api.xxxx.cn/callback/Tencent/promotion";String url = domain + "?" + request.getQueryString();ttLog.info("获取 authorization_code 的url: " + url);//缓存tokenString authorization_code = request.getParameter(AUTHORIZATION_CODE);//刷新access_token 与 refresh_tokenString access_token = callBackTencentService.refreshToken(CallBackTencentService.GRANT_TYPE_VALUE_AUTHORIZATION, authorization_code);redisUtils.setString(RedisConstant.ACCESS_TOKEN, refresh_token, RedisConstant.REFRESH_TOKEN_exp)if (StringUtils.isEmpty(access_token)) {redisUtils.delString(RedisConstant.ACCESS_TOKEN);return BizResult.create("token更新失败");} else {return BizResult.create("token更新成功");}}

/*** 腾讯广点通*/
@Slf4j
@Service
public class CallBackTencentService {private static Logger ttLog = LoggerFactory.getLogger("ttPromotionCallback");private static Logger ttexLog = LoggerFactory.getLogger("ttPromotionCallbackException");//刷新类型public static final String GRANT_TYPE_VALUE_AUTHORIZATION = "authorization_code";//授权码方式获取 token, 这个时候必填redirect_uripublic static final String GRANT_TYPE_VALUE_REFRESH = "refresh_token";//刷新 token// 请求token需要的几个字段private static final String CLIENT_ID = "client_id";private static final String CLIENT_SECRET = "client_secret";private static final String CLIENT_ID_VALUE = "1321321321";private static final String CLIENT_SECRET_VALUE = "fdgsgsdgdsg";private static final String GRANT_TYPE = "grant_type";private static final String REDIRECT_URI = "redirect_uri";private static final String REDIRECT_URI_VALUE = "http://api.qtread.cn/callback/Tencent/promotion";// 直接获取private static String getAccessTokenUrl;// 通过 refresh_token u获取private static String getAccessTokenFromRefreshTokenUrl;static {StringBuilder sb = new StringBuilder("https://api.e.qq.com/oauth/token");sb.append("?");sb.append(CLIENT_ID);sb.append("=");sb.append(CLIENT_ID_VALUE);sb.append("&");sb.append(CLIENT_SECRET);sb.append("=");sb.append(CLIENT_SECRET_VALUE);sb.append("&");sb.append(GRANT_TYPE);sb.append("=");sb.append("grant_type_value");getAccessTokenFromRefreshTokenUrl = sb.toString();sb.append("&");sb.append(REDIRECT_URI);sb.append("=");sb.append(REDIRECT_URI_VALUE);getAccessTokenUrl = sb.toString();}@Autowiredprivate RedisGetCacheByDb redisGetCacheByDb;@Autowiredprivate RedisUtils redisUtils;/*** 刷新access_token 与 refresh_token*/public String refreshToken(String grantTypeValue, String authorization_code) {if (GRANT_TYPE_VALUE_AUTHORIZATION.equals(grantTypeValue) && StringUtils.isEmpty(authorization_code)) {ttexLog.error("authorization_code更新token失败!authorization_code为空");return "";}String requestUrl = "";String refresh_token = "";String access_token = "";if (GRANT_TYPE_VALUE_AUTHORIZATION.equals(grantTypeValue)) {requestUrl = getAccessTokenUrl.replace("grant_type_value", GRANT_TYPE_VALUE_AUTHORIZATION);requestUrl += "&" + GRANT_TYPE_VALUE_AUTHORIZATION + "=" + authorization_code;} else {refresh_token = redisUtils.getString(RedisConstant.REFRESH_TOKEN);if (StringUtils.isEmpty(refresh_token)) {//万一refresh_token过期了, 需要运营重新请求调用授权获取ttexLog.error("refresh_token更新token失败! refresh_token已经失效!");try {SmsSendUtil.send(refresh_token失效了, 请重新授权, "13600000000");//发送短信告诉运营需要重新认证} catch (Exception e) {ttexLog.error("发送短信失败");}return "";}requestUrl = getAccessTokenFromRefreshTokenUrl.replace("grant_type_value", GRANT_TYPE_VALUE_REFRESH);requestUrl += "&" + GRANT_TYPE_VALUE_REFRESH + "=" + refresh_token;}String returnMsg = HttpUtils.httpGet(requestUrl, "");ttLog.info(returnMsg);Map map = JSONObject.parseObject(returnMsg, Map.class);if (map.get("code") == null || !"0".equals(map.get("code").toString())) {ttexLog.error(grantTypeValue + "更新token失败!" + GRANT_TYPE_VALUE_AUTHORIZATION + "=" + authorization_code + "," + GRANT_TYPE_VALUE_REFRESH + "=" + refresh_token + "错误码=" + map.get("code").toString() + "错误原因=" + map.get("message").toString());return "";}Map data = (Map) map.get("data");access_token = data.get("access_token").toString();refresh_token = data.get("refresh_token").toString();redisUtils.setString(RedisConstant.REFRESH_TOKEN, refresh_token, RedisConstant.REFRESH_TOKEN_exp);ttLog.info("更新token成功!");return access_token;}/*** 普通获取access_token*/public String getAccessToken() throws Exception {String access_token = redisGetCacheByDb.getCache(RedisConstant.ACCESS_TOKEN, RedisConstant.ACCESS_TOKEN_exp, new TypeReference<String>() {}, () -> {return this.refreshToken(GRANT_TYPE_VALUE_REFRESH, "");});if (StringUtils.isEmpty(access_token)) {//请求失败 空串不存redisUtils.delString(RedisConstant.ACCESS_TOKEN);}return access_token;}//用户行为上传需要的几个字段private static final String ACCOUNT_ID = "1234567";//推广帐号 id,有操作权限的帐号 id,包括代理商和广告主帐号 idprivate static final String USER_ACTION_SET_ID = "98767777";//用户行为源 id,通过 [user_action_sets 接口] 创建用户行为源时分配的唯一 idpublic static final String ACTION_TYPE = "REGISTER";//注册类型/*** 上传用户行为*/public boolean userActionAdd(String deviceId, String oaid, String actionType, String channelId) throws Exception {ttLog.info(channelId + "开始进行回调, imei:" + deviceId + ", oaid:" + oaid);Long timeStamp = System.currentTimeMillis() / 1000;String accessToken = getAccessToken();String uuid = UUID.randomUUID().toString().trim().replace("-", "");String imei = StringUtils.isEmpty(deviceId) ? (StringUtils.isEmpty(oaid) ? "" : oaid) : getMd5(deviceId).toLowerCase();String baseUrl = String.format("https://api.e.qq.com/v1.1/user_actions/add?access_token=%s&timestamp=%s&nonce=%s", accessToken, timeStamp, uuid);Map<Object, Object> userId = new HashMap<>();if (!StringUtils.isEmpty(deviceId)) {userId.put("hash_imei", imei);} else {userId.put("oaid", imei);}ArrayList<Map> actions = new ArrayList<>();Map<String, Object> actionsMap = CollectionUtil.createMap("action_time,user_id,action_type", timeStamp, userId, actionType);actions.add(actionsMap);Map<String, Object> param = CollectionUtil.createMap("account_id,user_action_set_id,actions", ACCOUNT_ID, USER_ACTION_SET_ID, actions);Map<String, String> headers = new HashMap<>();headers.put("content-type", "application/json");String result = HttpUtils.httpPost(baseUrl, JSONObject.toJSONString(param), headers);Map map = JSONObject.parseObject(result, Map.class);if (!"0".equals(map.get("code").toString())) {ttexLog.error("上传用户行为失败:" + "deviceId=" + deviceId + "&oaid=" + oaid + "错误码=" + map.get("code").toString() + "错误原因=" + map.get("message").toString());return false;}return true;}/*** 异步调用行为*/@Asyncpublic void userActionAddAsync(String deviceId, String oaid, String actionType, String channelId) throws Exception {if (!"XXX".equals(channelId)) {//XXX渠道用户进行上传用户行为return;}this.userActionAdd(deviceId, oaid, actionType ,channelId);}

对接腾讯广告(广点通) 上传用户行为相关推荐

  1. 腾讯广告 广点通 数据上报 上传用户行为数据

    腾讯广告文档地址:https://developers.e.qq.com/docs/start 第一步 准备账户信息 const APP_URl = 'https://api.e.qq.com'; c ...

  2. 腾讯广告广点通API接入文档(Android)

    官方文档地址 如果能够看懂文档的也没有必要再往下面看了.本篇文章就到此结束. 下面记录的是本人在上面锁踩过的坑,因为我发现Mac电脑上面的联系客服不是我想要的. 本来只是内部使用的文档,后来想想还是公 ...

  3. 腾讯云 视频 点播 视频上传接口

    申请腾讯云  获取id  及  key [腾讯云视频]Web上传 地址 https://cloud.tencent.com/document/product/266/9239 Java 签名示例 ht ...

  4. 腾讯云COS服务器文件上传与生命周期的设置,以及Opencv nparry数组格式图片非文件流方式上传

    目录 Opencv numpy arry图片非文件流直接上传 腾讯云COS服务器的文件上传和生命周期的设置 1.申请服务器 2.创建桶 3.官方文档以及安装SDK 4.开始使用(官方示例代码) 5.必 ...

  5. Typora+PicGo+腾讯云COS实现图片上传功能

    文章目录 * * 一.前言 * 二.安装Typora和PicGo * 三.[腾讯云](https://l.gushuji.site/tencent)COS创建对象存储 * 四.配置Typora和Pic ...

  6. 腾讯云cos预签名上传文件

    腾讯云cos预签名上传文件 链接: 文档地址 下面展示一些 内联代码片. 后端要个 scene的值 这个是你上传什么类型的文件传不同的值 然后成功之后调一个原生的put请求 最后会得到一个 retur ...

  7. java窗体广告墙(图片上传)java广告系统

    java窗体广告墙(图片上传)java广告系统 public Swingtest002() {// 设置标题setTitle("请登陆");// 绝对布局setLayout(nul ...

  8. SSM上传用户头像。解决HTTP 400,保存到本地以及数据库保存路径,在页面显示的问题

    第一次用SSM上传用户图片,遇到很多问题,这里逐一记录: 1.保存到本地某个文件夹 2.在页面显示图片 3.报错HTTP 400 bad request 用maven搭建的项目,结构如图: 主要是实体 ...

  9. 【探花交友】保存用户信息、上传用户头像、用户信息管理

    文章目录 1.3.保存用户信息 1.4.上传用户头像 2.用户信息管理 2.1.查询用户资料 2.2.更新用户资料 1.3.保存用户信息 1.3.1.接口文档 YAPI接口地址:http://192. ...

最新文章

  1. C++ 中NULL 和 nullptr 的区别
  2. js事件循环 microtask macrotask
  3. 大叔手记(16):分析URL Routing和URL Rewriting两者之间的不同
  4. linux 串口编程_ARM-Linux开发与MCU开发有何不同?上篇
  5. 获取图片中感兴趣区域的信息(Matlab实现)
  6. java反射成员变量_java反射之成员变量的反射
  7. 用回溯法找出n个自然数中取r个数的全排列
  8. 抽取类的#技巧#成员变量最可能
  9. [Effective C++ --032]确定你的public继承塑模出is-a
  10. JQuery的$.extend()的源码
  11. c# 获取docx中的内容
  12. 开启本地git权限_git的使用,有这篇文章就够了
  13. 自己给打印机怎么加粉墨,联想兄弟打印机加粉步骤
  14. 3dmax如何建模(二)
  15. 站长开源工具箱V2.0网站源码
  16. 未来智能营销时代到来,人工智能营销系统方兴未艾
  17. android mediastore指定前置摄像头,Intent方式打开前置摄像头
  18. 请用一句话证明你是程序员
  19. ABAP BDC个人使用见解
  20. ☀️光天化日学C语言☀️(31)- break 关键字 | 当断则断!

热门文章

  1. Activity 使用方法详解
  2. AD52095 大功率Class-D音频功放,立体声功率50W*2,单通道功率100W
  3. php基础(09):php模板引擎Smarty
  4. 2018 AI Challenger全球AI挑战赛‘眼底水肿病变区域自动分割’赛道比赛总结
  5. Unity特效学习笔记——受击爆点
  6. 《预训练周刊》第41期: 知识型对话生成、语境学习、通用控制器学习
  7. Maven Repository官网
  8. maven官网如何下载
  9. vue下的audio标签播放、暂停、完成事件
  10. 图形数据库总结之NoSQL