package com.stylefeng.guns.modular.system.util;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.MediaType;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
import org.springframework.web.client.RestTemplate;
|
|
|
/**
|
* 高德猎鹰服务
|
* key次数用完时自动切换可用key(切换后自动重建serverId)
|
*/
|
@Component
|
public class GDFalconUtil implements ApplicationRunner {
|
|
@Autowired
|
private RestTemplate restTemplate;
|
|
@Autowired
|
private GDKeyManager gdKeyManager;
|
|
private static String serverId = null;
|
|
/**
|
* 当前serverId对应的key(key切换后需重建serverId)
|
*/
|
private static volatile String currentKey = null;
|
|
|
public String getServerId() {
|
return serverId;
|
}
|
|
/**
|
* 服务启动后执行的代码
|
* @param args
|
* @throws Exception
|
*/
|
@Override
|
public void run(ApplicationArguments args) throws Exception {
|
this.init();
|
}
|
|
|
/**
|
* 初始化创建服务
|
*/
|
public void init(){
|
if(serverId == null){
|
if (gdKeyManager == null || restTemplate == null) {
|
// 非容器实例(如 GunsApplication.main 中 new 出来的对象),由容器内bean完成初始化
|
return;
|
}
|
ensureServerId();
|
}
|
}
|
|
/**
|
* 参数构造器:key与sid切换后需按最新值重新构造
|
*/
|
private interface ParamsBuilder {
|
MultiValueMap<String, Object> build(String key, String sid);
|
}
|
|
/**
|
* 确保serverId与当前使用的key对应:
|
* key切换后自动查询/重建serverId;key用完自动切换可用key重试
|
*/
|
private synchronized String ensureServerId(){
|
int maxAttempts = 5;
|
String lastKey = gdKeyManager.getKey();
|
for (int i = 0; i < maxAttempts; i++) {
|
String gdKey = gdKeyManager.getKey();
|
lastKey = gdKey;
|
if (serverId != null && gdKey.equals(currentKey)) {
|
return gdKey;
|
}
|
// 1. 查询该key下的服务列表
|
JSONArray jsonArray = null;
|
try {
|
String url = "https://tsapi.amap.com/v1/track/service/list?key=" + gdKey;
|
String forObject = restTemplate.getForObject(url, String.class);
|
JSONObject jsonObject = JSON.parseObject(forObject);
|
if (GDKeyManager.isFalconExhausted(jsonObject)) {
|
gdKeyManager.reportExhausted(gdKey);
|
serverId = null;
|
continue;
|
}
|
if (jsonObject.getIntValue("errcode") == 10000) {
|
JSONObject data = jsonObject.getJSONObject("data");
|
if (null != data) {
|
jsonArray = data.getJSONArray("results");
|
}
|
}
|
} catch (Exception e) {
|
loggerWarn("查询猎鹰服务列表异常", e);
|
}
|
if (jsonArray != null && jsonArray.size() > 0) {
|
serverId = jsonArray.getJSONObject(0).getString("sid");
|
currentKey = gdKey;
|
return gdKey;
|
}
|
// 2. 无服务:创建新服务
|
String sid = createServerInternal("server", gdKey);
|
if (sid != null) {
|
serverId = sid;
|
currentKey = gdKey;
|
return gdKey;
|
}
|
// 3. 创建失败(可能key用完):切换key重试
|
gdKeyManager.reportExhausted(gdKey);
|
serverId = null;
|
}
|
return lastKey;
|
}
|
|
private void loggerWarn(String msg, Exception e) {
|
System.err.println("[GDFalconUtil] " + msg + ":" + e.getMessage());
|
}
|
|
/**
|
* 执行猎鹰POST表单请求:key次数用完时自动切换key并重建serverId重试
|
*/
|
private String doFalconPost(String url, ParamsBuilder builder) {
|
String lastResp = null;
|
int maxAttempts = 5;
|
for (int i = 0; i < maxAttempts; i++) {
|
String gdKey = ensureServerId();
|
String sid = serverId;
|
MultiValueMap<String, Object> params = builder.build(gdKey, sid);
|
HttpHeaders headers = new HttpHeaders();
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
|
String resp = restTemplate.postForObject(url, requestEntity, String.class);
|
lastResp = resp;
|
JSONObject jsonObject;
|
try {
|
jsonObject = JSON.parseObject(resp);
|
} catch (Exception e) {
|
return resp;
|
}
|
if (GDKeyManager.isFalconExhausted(jsonObject)) {
|
gdKeyManager.reportExhausted(gdKey);
|
serverId = null;
|
continue;
|
}
|
return resp;
|
}
|
return lastResp;
|
}
|
|
/**
|
* 执行猎鹰GET请求:key次数用完时自动切换可用key重试
|
*/
|
private String doFalconGet(String baseUrl) {
|
String lastResp = null;
|
int maxAttempts = 5;
|
for (int i = 0; i < maxAttempts; i++) {
|
String gdKey = gdKeyManager.getKey();
|
String url = baseUrl + (baseUrl.contains("?") ? "&" : "?") + "key=" + gdKey;
|
String resp = restTemplate.getForObject(url, String.class);
|
lastResp = resp;
|
JSONObject jsonObject;
|
try {
|
jsonObject = JSON.parseObject(resp);
|
} catch (Exception e) {
|
return resp;
|
}
|
if (GDKeyManager.isFalconExhausted(jsonObject)) {
|
gdKeyManager.reportExhausted(gdKey);
|
continue;
|
}
|
return resp;
|
}
|
return lastResp;
|
}
|
|
|
/**
|
* 创建新的服务
|
* @return
|
*/
|
public String createServer(String name){
|
return createServerInternal(name, gdKeyManager.getKey());
|
}
|
|
/**
|
* 创建新的服务(内部直连,供ensureServerId使用)
|
*/
|
private String createServerInternal(String name, String key){
|
String url = "https://tsapi.amap.com/v1/track/service/add";
|
//调用推送
|
HttpHeaders headers = new HttpHeaders();
|
// 以表单的方式提交
|
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
//将请求头部和参数合成一个请求
|
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
params.add("key", key);
|
params.add("name", name);
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
|
String s = restTemplate.postForObject(url, requestEntity , String.class);
|
JSONObject jsonObject = JSON.parseObject(s);
|
if(jsonObject.getIntValue("errcode") == 10000){
|
JSONObject data = jsonObject.getJSONObject("data");
|
if(null != data){
|
return data.getString("sid");
|
}
|
}
|
return null;
|
}
|
|
|
/**
|
* 创建终端数据
|
* @param name
|
* @return
|
*/
|
public String createTerminal(String name){
|
String tid = this.selectTerminal(name);
|
if(tid != null){
|
return tid;
|
}
|
String s = doFalconPost("https://tsapi.amap.com/v1/track/terminal/add", (key, sid) -> {
|
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
params.add("key", key);
|
params.add("sid", sid);
|
params.add("name", name);
|
return params;
|
});
|
JSONObject jsonObject = JSON.parseObject(s);
|
if(jsonObject.getIntValue("errcode") == 10000){
|
JSONObject data = jsonObject.getJSONObject("data");
|
return data.getString("tid");
|
}
|
System.err.println(jsonObject.getString("errmsg"));
|
return null;
|
}
|
|
|
/**
|
* 查询终端
|
* @param name
|
* @return
|
*/
|
public String selectTerminal(String name){
|
String forObject = doFalconGet("https://tsapi.amap.com/v1/track/terminal/list?name=" + name);
|
JSONObject jsonObject = JSON.parseObject(forObject);
|
if(jsonObject.getIntValue("errcode") == 10000){
|
JSONObject data = jsonObject.getJSONObject("data");
|
int count = 0;
|
if(null != data){
|
count = data.getIntValue("count");
|
}
|
if(count > 0){
|
JSONObject results = data.getJSONArray("results").getJSONObject(0);
|
return results.getString("tid");
|
}else{
|
return this.createTerminal(name);
|
}
|
}
|
return null;
|
}
|
|
|
/**
|
* 创建轨迹
|
* @param tid 终端id
|
* @return
|
*/
|
public String createTrack(String tid){
|
String s = doFalconPost("https://tsapi.amap.com/v1/track/trace/add", (key, sid) -> {
|
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
params.add("key", key);
|
params.add("sid", sid);
|
params.add("tid", tid);
|
return params;
|
});
|
JSONObject jsonObject = JSON.parseObject(s);
|
if(jsonObject.getIntValue("errcode") == 10000){
|
return jsonObject.getString("data");
|
}
|
System.err.println(jsonObject.getString("errmsg"));
|
return null;
|
}
|
|
|
/**
|
* 删除轨迹
|
* @param tid 终端id
|
* @param trid 轨迹id
|
*/
|
public void deleteTrack(String tid, String trid){
|
String s = doFalconPost("https://tsapi.amap.com/v1/track/trace/delete", (key, sid) -> {
|
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
|
params.add("key", key);
|
params.add("sid", sid);
|
params.add("tid", tid);
|
params.add("trid", trid);
|
return params;
|
});
|
JSONObject jsonObject = JSON.parseObject(s);
|
if(jsonObject.getIntValue("errcode") != 10000){
|
System.err.println(jsonObject.getString("errmsg"));
|
}
|
}
|
|
}
|