? 嗨,您好 ? 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者
? 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代
?文章所在专栏:业务设计
? 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识
? 向我询问任何您想要的东西,ID:vnjohn
?觉得博主文章写的还 OK,能够帮助到您的,感谢三连支持博客?
? 代词: vnjohn
⚡ 有趣的事实:音乐、跑步、电影、游戏
目录
简介 配置管理 配额 申请步骤 地理位置解析 基础代码配置 腾讯 API 配置信息 基础地图结构定义 公用数据结构抽象 请求工具类 IP 定位接口 地址解析接口 逆地址解析接口 关键字输入提示接口 总结
简介
在工作中,一旦涉及到地理位置经纬度的解析,通过经纬度解析所在的详细地址,通过 IP 解析所在的经纬度再解析所在的详细地址,常用的地图 API 有百度、腾讯等第三方可以用于集成在项目中使用,本文我们会以腾讯地图 API 实现地理位置信息解析,提供源码以及应用的场景
腾讯地图 API 官方文档:WebService API|腾讯位置服务
腾讯地图 WebService API 是基于 HTTPS/HTTP 协议的数据接口
开发者可以使用任何客户端、服务器和开发语言,按照腾讯地图 WebService API 规范,按需构建 HTTPS 请求,并获取结果数据(目前支持JSON/JSONP方式返回)
配置管理
配额
针对个人开发者和企业开发者,提供的服务 API 调用量有明显的差别,以下图来自官方文档
从上图可知,普通的接口 API 能够让我们自由的调用,根据不同的身份来区分对应的可用额度,个人开发者 -> 企业开发者 -> 商业授权开发者
除了:路线规划|距离矩阵:货车|智能地址解析这些复杂的地理位置信息采集,其他啊的接口都有可限的使用额度
申请步骤
前往腾讯位置服务注册页,通过手机号+邮箱认证号个人开发者身份,随即登录至控制台
1、创建应用
应用是最大的承载能力,一个应用下可以添加多个对应的 Key,而应用下所属的 Key 才是我们服务端调用 API 必须要的能力
2、创建 Key
启用产品:WebServiceAPI、SDK、微信小程序
WebServiceAPI 产品是用于服务端调用的能力,有三种可配置能力:域名白名单、授权 IP、签名检验
1、域名白名单:当在调用腾讯地图 API 时传入当前所要服务的域名,请求的域名在域名白名单内,才能完成服务的请求
2、授权 IP:当在调用腾讯地图 API 时传入当前所要请求的 IP 地址,请求的 IP 在「授权IP」内,才能完成服务的请求
3、签名校验:当采用这种方式时,腾讯地图 API 会为我们分配一个 Secret key 值,同时会为我们提供具体的签名校验方式,让我们能够快速接入
一般在工作中较多采用的是第一种、第二种方式,第一种、第二种没有那么大的复杂性不需要额外的技术成本去接入但安全性不高,第三种方式会增加接入的复杂性要额外的技术知识去实现但安全性较高
WebServiceAPI 如何使用的官方文档:WebServiceAPI 配置
「SDK」产品是用于安卓端、IOS 端使用的能力,当 App 应用需要使用到腾讯地图的地图、导航服务时,需要配置好该产品的能力,它的配置方式则与 WebServiceAPI 不同,它要配置的是安卓应用或 IOS 应用打包以后生成的包名称,可支持配置多个,每行配一个,多个进行隔行分开
「微信小程序」产品是用于在微信小程序端使用的能力,当小程序内需要用到腾讯地图的某些功能时,例如:路线规划,那么使用它是非常好的选择
3、当创建 Key 完成以后,会生成一个随机的密钥字符
4、点击详情,可查看具体分配的接口 API 调用额度信息
当您是个人开发者时,默认只会给你一个 Key 的可用额度,再申请其他的 Key 是无法获取额度的
地理位置解析
当应用和 Key 配置好以后,下面我们就通过官方文档 API 来进行以下几种 API 具体的实现
基础代码配置
腾讯 API 配置信息
/** * 腾讯地图 API 配置信息 * * @author vnjohn * @since 2023/10/25 */@Componentpublic class TencentMapConfig { @Value("${tencent.map.key}") private String tencentMapKey; protected static String PARSE_IP = "https://apis.map.qq.com/ws/location/v1/ip?key=%s&ip=%s"; protected static String PARSE_ADDRESS = "https://apis.map.qq.com/ws/geocoder/v1/?key=%s&address=%s"; protected static String PARSE_INVERSE_ADDRESS = "https://apis.map.qq.com/ws/geocoder/v1/?key=%s&location=%s,%s&get_poi=0"; protected static String PLACE_TIPS = "https://apis.map.qq.com/ws/place/v1/suggestion?key=%s&keyword=%s&page_index=%s&page_size=%s&location=%s,%s";// .......}
调用 API 接口所需的 Key 信息以及其他 API 完整的 URL 地址,单独放在一个类进行存储
一般我们会放在 Nacos 中进行存储,当发生 URL 参数变更时,可以结合 Nacos 动态刷新机制一起使用
基础地图结构定义
/** * @author vnjohn * @since 2023/7/23 */@Datapublic class TencentMapResult<T> { /** * 状态码,0为正常,其它为异常 */ private Integer status; /** * 状态说明 */ private String message; /** * 查询结果总数量 */ private Integer count; /** * 返回数据 > 数组 */ private T data; /** * 返回数据 > 对象 */ private T result;}
因为在腾讯位置服务提供的 API 接口中,不同的接口可能它返回的结构不一样,有的返回是数组,有的返回是对象,所以在我们对接使用这一侧,就必须对不同的数据结构做一层适配,故而之采用泛型的结构来接收处理
公用数据结构抽象
/** * 腾讯地图「经纬度」 * * @author vnjohn * @since 2023/7/23 */@Datapublic class TencentLocation { /** * 经度 */ private Double lng; /** * 纬度 */ private Double lat;}
在接收 API 接口返回的结果时,这一块的结构可以在多个地方同时运用到,故将它抽象出来作为一个单独的类
请求工具类
在简介中介绍到了「腾讯地图 WebService API 是基于 HTTPS/HTTP 协议的数据接口」那么我们就调用这部分数据接口时,就需要一个 HTTPS、HTTP 工具来进行调用,从而拿到具体的返回结果,在这里我们采用了 Spring 提供的客户端请求类:org.springframework.web.client.RestTemplate,如下的源码就是基于它进行再次封装,我们只需要关心具体的结果即可,在再次封装中我会适配好 HTTP、HTTPS 协议实现,如下:
/** * 远程调用 URL 工具类 * * @author vnjohn * @date 2022/1/7 */@Slf4j@Configurationpublic class RestTemplateUtils { private static final RestTemplate restTemplate = new RestTemplate(); @PostConstruct public void initial() { restTemplate.getMessageConverters().add(new WxHttpMessageConverter()); restTemplate.setRequestFactory(clientHttpRequestFactory()); restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); } /** * 添加对 HTTPS 的支持. * * @return */ @Bean public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() { try { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build(); httpClientBuilder.setSSLContext(sslContext); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslConnectionSocketFactory).build(); PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager( socketFactoryRegistry); poolingHttpClientConnectionManager.setMaxTotal(2700); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); httpClientBuilder<