com.hn.map.qq.LocationUtil Maven / Gradle / Ivy
package com.hn.map.qq;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.hn.config.HnConfigUtils;
import com.hn.config.exception.ConfigException;
import com.hn.map.MapException;
import com.hn.map.qq.domain.AddressComponent;
import com.hn.map.qq.domain.Location;
import com.hn.utils.AssertUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 描述:
* 位置工具类 腾讯地图
*
* 域名白名单:
* 适用于浏览器端JSONP方式调用Webservice服务
* 1.仅白名单中的域名才可使用此key调用WebService服务,留空则不限制
* 2.每行填写一个域名,填写的域名及其子域名都会同时得到授权,如:qq.com,则qq.com下的子域名map.qq.com也可以使用此key
*
* 授权ip:
* 授权指定IP来源的请求才可使用,每行填写一条,留空则不限制
* 1.填写单一授权IP,例:202.106.0.99
* 2.填写授权地址段,起始IP-结束IP。例:202.106.0.20-202.106.0.26
*
* 签名计算:
* 通过签名校验的方式,可有效解决请求伪造,稍有开发量,但与授权IP方式比较,不必担心服务器换IP的问题。
*
* @author fei
* 2019-12-30 18:31
*/
public class LocationUtil {
private static final Log log = LogFactory.get();
/**
* 开发密钥
*/
private static String key;
private static final String GEN_URL = "https://apis.map.qq.com";
/**
* 请求地址
*/
private static final String REQ_URL = "/ws/geocoder/v1/";
static {
// 初始化key
key = getKey("");
}
/**
* 读取对应场景的key
*
* @param scene 场景
*/
public static void scene(String scene) {
// 这样会存在线程安全问题
key = getKey(scene);
}
/**
* 逆地址解析(坐标位置描述)
*
* @param lat 纬度
* @param lng 经度
* @return addressComponent {@link AddressComponent}
*/
public static AddressComponent locationToAddress(double lat, double lng) {
Map param = new HashMap<>(3);
param.put("key", key);
// 是否返回周边POI列表: 1.返回;0不返回(默认)
// param.put("get_poi", 1);
// param.put("poi_options","address_format=short");
// 返回格式:支持JSON/JSONP,默认JSON
// param.put("output", "JSON");
param.put("location", lat + "," + lng);
// 加密
String secretKey = getSecretKey("");
if (StrUtil.isNotBlank(secretKey)) {
param.put("sig", sign(lat, lng));
}
String resultStr = HttpUtil.get(GEN_URL + REQ_URL, param);
log.debug("[腾讯地图]逆地址解析(坐标位置描述) 返回结果:{}", resultStr);
JSONObject resultObject = JSONUtil.parseObj(resultStr);
if (resultObject.getInt("status") == 0) {
JSONObject result = resultObject.getJSONObject("result");
return JSONUtil.toBean(result.getStr("address_component"), AddressComponent.class);
}
throw new MapException("[腾讯地图]逆地址解析失败:" + resultObject.getStr("message"));
}
/**
* 地址解析(地址转坐标)
*
* @param address 地址 (注:地址中请包含城市名称,否则会影响解析效果)
* @return 坐标信息 {@link Location}
*/
public static Location addressToLocation(String address) {
Map param = new HashMap<>();
param.put("key", key);
// 返回格式:支持JSON/JSONP,默认JSON
// param.put("output", "JSON");
param.put("address", address);
// 加密
String secretKey = getSecretKey("");
if (StrUtil.isNotBlank(secretKey)) {
param.put("sig", sign(address));
}
String resultStr = HttpUtil.get(GEN_URL + REQ_URL, param);
log.debug("[腾讯地图]地址解析(地址转坐标) 返回结果:{}", resultStr);
JSONObject resultObject = JSONUtil.parseObj(resultStr);
if (resultObject.getInt("status") == 0) {
JSONObject result = resultObject.getJSONObject("result");
JSONObject location = result.getJSONObject("location");
return new Location(location.getDouble("lat"), location.getDouble("lng"));
}
throw new MapException("【腾讯地图】地址解析(地址转坐标)失败:" + resultObject.getStr("message"));
}
/**
* 签名计算
*
* 1. 首先对参数进行排序:按参数名升序(本例结果为key在前,location在后):
* 2. 签名计算(sig):请求路径+”?”+请求参数+SK进行拼接,并计算拼接后字符串md5值,即为签名(sig):
* md5("/ws/geocoder/v1?key=5Q5BZ-5EVWJ-SN5F3-*****&location=28.7033487,115.8660847SWvT26ypwq5Nwb5RvS8cLi6NSoH8HlJX")
* 3. 生成最终请求:将计算得到的签名sig,放到请求中(参数名即为:sig):
*
* @param lat 纬度
* @param lng 经度
* @return 签名计算后的结果
*/
private static String sign(double lat, double lng) {
String secretKey = getSecretKey("");
String location = lat + "," + lng;
return SecureUtil.md5(REQ_URL + "?key=" + key + "&location=" + location + secretKey);
}
/**
* 签名计算
*
* @param address 地址
* @return 签名计算后的结果
*/
private static String sign(String address) {
String secretKey = getSecretKey("");
return SecureUtil.md5(REQ_URL + "?address=" + address + "&key=" + key + secretKey);
}
/**
* 配置前缀名
*/
private static final String CONFIG_KEY = "map.qq";
private static String getKey(String scene) {
if (StrUtil.isNotBlank(scene)) {
scene = "-".concat(scene);
}
String key = HnConfigUtils.getConfig(CONFIG_KEY.concat(scene).concat(".key"));
AssertUtils.notNull(key, ConfigException.exception("腾讯地图key未配置"));
return key;
}
private static String getSecretKey(String scene) {
if (StrUtil.isNotBlank(scene)) {
scene = "-".concat(scene);
}
return HnConfigUtils.getConfig(CONFIG_KEY.concat(scene).concat(".secretKey"));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy