一.前言
不知道有没有跟我一样的同学, 每次新对接的一个腾讯产品的时候看着它的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×tamp=当前时间戳(单位秒)&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);
//缓存token
String authorization_code = request.getParameter(AUTHORIZATION_CODE);
//刷新access_token 与 refresh_token
String 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_uri
public 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();
}
@Autowired
private RedisGetCacheByDb redisGetCacheByDb;
@Autowired
private 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,包括代理商和广告主帐号 id
private static final String USER_ACTION_SET_ID = “98767777”;//用户行为源 id,通过 [user_action_sets 接口] 创建用户行为源时分配的唯一 id
public 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×tamp=%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;
}
/**
* 异步调用行为
*/
@Async
public void userActionAddAsync(String deviceId, String oaid, String actionType, String channelId) throws Exception {
if (!”XXX”.equals(channelId)) {//XXX渠道用户进行上传用户行为
return;
}
this.userActionAdd(deviceId, oaid, actionType ,channelId);
}
————————————————
版权声明:本文为CSDN博主「uknowzxt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/uknowzxt/article/details/106255418