当前位置: 首页 > article >正文

基于 Java 和高德开放平台的 WebAPI 集成实践——以“搜索 POI 2.0”为例

在位置服务类应用里“找点”Point of InterestPOI几乎是最常见能力输入“咖啡”“地铁站”“医院”返回可用地点列表。高德开放平台的 WebAPI 在这类场景中非常成熟而POI 2.0相比早期版本在字段丰富度、检索能力和结果可用性上更适合企业级业务集成。本文将从 Java 工程落地视角完整讲解如何从 0 到 1 接入高德 POI 2.0 搜索包含配置、安全、代码实现、异常治理、性能优化与上线建议。一、业务目标与技术选型我们先定义一个最小可用目标输入关键词如“星巴克”、城市如“北京”、分页参数输出标准化 POI 列表名称、地址、坐标、距离、类型等要求可扩展、可观测、可限流、可容错技术栈建议Java 17Spring Boot 3.xWebClient或 RestTemplateCaffeine本地缓存可选Micrometer Prometheus监控可选二、开通高德开放平台能力注册高德开放平台账号创建应用选择Web 服务 API获取key必要开启安全校验可选生产建议开启sig签名阅读 POI 2.0 文档确认接口地址与参数规则例如文本搜索接口常见调用方式是 GET 请求核心参数一般包含key、keywords、region/city、page_num、page_size等。三、Spring Boot 项目配置1application.ymlyamlamap: webapi: key: your_amap_key secret: your_amap_secret # 可选启用签名时使用 base-url: https://restapi.amap.com timeout-ms: 30002配置类javaConfigurationProperties(prefix amap.webapi) Data public class AmapProperties { private String key; private String secret; private String baseUrl; private int timeoutMs 3000; }javaConfiguration EnableConfigurationProperties(AmapProperties.class) public class HttpClientConfig { Bean public WebClient amapWebClient(AmapProperties p) { HttpClient httpClient HttpClient.create() .responseTimeout(Duration.ofMillis(p.getTimeoutMs())); return WebClient.builder() .baseUrl(p.getBaseUrl()) .clientConnector(new ReactorClientHttpConnector(httpClient)) .build(); } }四、定义请求与响应模型先做“防腐层”不要把高德原始 JSON 直接暴露给业务层建议建一层 DTO 转换。javaData public class PoiSearchRequest { private String keywords; private String city; // 或 region private Integer pageNum 1; private Integer pageSize 10; }javaData public class PoiItem { private String id; private String name; private String address; private String location; // lng,lat private String type; private String distance; }javaData public class PoiSearchResult { private Long total; private ListPoiItem pois; }五、核心调用实现POI 2.0下面以“文本搜索”思路示例具体路径以官方文档为准javaService RequiredArgsConstructor public class AmapPoiService { private final WebClient amapWebClient; private final AmapProperties props; private final ObjectMapper objectMapper; public PoiSearchResult search(PoiSearchRequest req) { MapString, String params new TreeMap(); params.put(key, props.getKey()); params.put(keywords, req.getKeywords()); params.put(region, req.getCity()); params.put(page_num, String.valueOf(req.getPageNum())); params.put(page_size, String.valueOf(req.getPageSize())); params.put(show_fields, business,indoor,navi,photos); // 如开启签名按官方规则计算 sig if (StringUtils.hasText(props.getSecret())) { params.put(sig, buildSig(params, props.getSecret())); } String body amapWebClient.get() .uri(uriBuilder - { UriBuilder b uriBuilder.path(/v5/place/text); params.forEach(b::queryParam); return b.build(); }) .retrieve() .onStatus(HttpStatusCode::isError, resp - Mono.error(new RuntimeException(Amap http error: resp.statusCode()))) .bodyToMono(String.class) .block(); return parseResult(body); } private PoiSearchResult parseResult(String body) { try { JsonNode root objectMapper.readTree(body); String status root.path(status).asText(); if (!1.equals(status)) { String info root.path(info).asText(unknown); String infocode root.path(infocode).asText(unknown); throw new RuntimeException(Amap biz error, info info , infocode infocode); } PoiSearchResult result new PoiSearchResult(); result.setTotal(root.path(count).asLong(0L)); ListPoiItem list new ArrayList(); for (JsonNode n : root.path(pois)) { PoiItem item new PoiItem(); item.setId(n.path(id).asText()); item.setName(n.path(name).asText()); item.setAddress(n.path(address).asText()); item.setLocation(n.path(location).asText()); item.setType(n.path(type).asText()); item.setDistance(n.path(distance).asText()); list.add(item); } result.setPois(list); return result; } catch (Exception e) { throw new RuntimeException(Parse amap response failed, e); } } private String buildSig(MapString, String params, String secret) { // 示例按官方签名规则拼接后 MD5请严格对照官方文档实现 StringBuilder sb new StringBuilder(); params.forEach((k, v) - sb.append(k).append().append(v).append()); sb.setLength(sb.length() - 1); sb.append(secret); return DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8)); } }六、Controller 暴露内部统一接口javaRestController RequestMapping(/api/poi) RequiredArgsConstructor public class PoiController { private final AmapPoiService poiService; GetMapping(/search) public PoiSearchResult search(RequestParam String keywords, RequestParam(required false) String city, RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize) { PoiSearchRequest req new PoiSearchRequest(); req.setKeywords(keywords); req.setCity(city); req.setPageNum(pageNum); req.setPageSize(pageSize); return poiService.search(req); } }调用示例bashcurl http://localhost:8080/api/poi/search?keywords咖啡city北京pageNum1pageSize10七、工程化关键点不仅“能调通”还要“可上线”1超时与重试连接超时、读取超时必须配置仅对幂等请求做有限重试如最多 2 次使用指数退避避免雪崩2限流与熔断对外部 API 调用做 QPS 限制Bucket4j / Sentinel异常率过高时熔断降级返回兜底结果或友好提示3缓存策略对热门关键词 城市组合做短 TTL 缓存如 30~120 秒避免每次都打外部 API降低成本与延迟4日志与追踪记录requestId、关键词、城市、耗时、返回码不打印敏感信息key、secret统一错误码映射便于排查八、常见问题与排查思路问题 1返回INVALID_USER_KEYkey 未开通 Web 服务权限key 与调用域/环境不匹配key 输入错误或被禁用问题 2签名错误参数排序规则不一致拼接字符串包含多余字符URL 编码前后顺序不符合规范问题 3结果为空关键词过窄或城市限制过严分页超范围行政区参数与关键词冲突问题 4偶发超时网络抖动或对端限流未设置连接池、超时、重试突发高峰未做缓存与削峰九、性能与体验优化建议前端联动建议输入框做防抖300ms分页策略首屏只拉 10~20 条减少响应体字段裁剪只请求业务必要字段控制带宽地理偏置结合用户定位提升相关性多源兜底关键业务可设计降级数据源本地库/历史缓存十、测试策略建议最少三层单元测试签名生成、参数校验、响应解析集成测试Mock 外部 API验证超时/重试/异常分支联调测试使用真实 key 在测试环境压测 QPS 与延迟示例断言重点status1 时解析是否完整status!1 时是否正确抛业务异常缓存命中时是否减少外部调用次数十一、安全与合规建议key/secret 放配置中心或密钥管理系统禁止硬编码生产环境按最小权限开通能力对调用频率、来源 IP 做安全策略日志脱敏遵守数据合规要求尤其位置相关数据结语基于 Java 集成高德开放平台 POI 2.0本质不是“写一个 HTTP 请求”那么简单而是要把外部能力变成你系统里稳定、可控、可演进的基础服务。最佳实践可以总结为一句话先建立统一 API 防腐层再用超时/重试/限流/缓存把稳定性补齐最后用监控与日志保证可运营。当你按这条路径建设POI 搜索不仅能“跑起来”更能支撑真实业务长期迭代。如果你愿意我可以下一步给你一份可直接运行的 Spring Boot Demo含完整 Maven 依赖、测试样例与 Docker 部署文件。

相关文章:

基于 Java 和高德开放平台的 WebAPI 集成实践——以“搜索 POI 2.0”为例

在位置服务类应用里,“找点”(Point of Interest,POI)几乎是最常见能力:输入“咖啡”“地铁站”“医院”,返回可用地点列表。 高德开放平台的 WebAPI 在这类场景中非常成熟,而 POI 2.0 相比早期…...

Redis数据库基础

NoSQL(内存/缓存型数据库): 相比于其他的内存/缓存数据库,redis可以方便的实现持久化的功能(保存至磁盘中)一、关系数据库与非关系数据库概述1、关系型数据库关系型数据库是一个结构化的数据库,…...

人工智能之知识蒸馏 第一章 绪论:知识蒸馏的基础认知

人工智能之知识蒸馏 第一章 绪论:知识蒸馏的基础认知 文章目录人工智能之知识蒸馏前言1.1 知识蒸馏的背景与意义1.2 知识蒸馏的核心定义与核心目标1.3 核心框架与学习目标核心流程图解配套代码实现(PyTorch示例)资料前言 1.1 知识蒸馏的背景…...

Java 大厂一面模拟:从活动发奖到消息幂等的分布式一致性拷问

开场说明 这是一场面向 1-3 年 Java 后端候选人或校招高阶候选人的模拟大厂一面,时长约 30 分钟。面试围绕一个典型的电商活动发奖业务场景展开,串联缓存设计、消息可靠性、事务一致性及分布式协调等核心模块。问题设计兼顾广度与深度,重点考…...

机器学习概念及学习目标

机器学习是计算机科学和人工智能的一个子领域,它通过对大量数据进行 分析,自动构建数学模型,从而能够在未见过的数据上进行预测、分类、 决策或生成内容。该算法通过训练数据优化模型参数,使模型能够根据输 入数据生成合理的输出。…...

Jetson orin nano 中安装docker

检查当前系统是否已经安装了 Docker,以及当前安装的版本号。通常在安装前运行它是为了确认是否需要安装: docker --version使用 curl 工具从 Docker 官方网站下载“一键安装脚本”,-fsSL 是一些静默下载和处理重定向的参数,-o ge…...

微型循环氩气金属气雾化制粉设备性价比高服务商

在材料科学的星辰大海中,金属粉末制备是通往3D打印、粉末冶金等前沿领域的基石。然而,对于无数高校课题组和中小型研发企业而言,这块“基石”却重若千钧——动辄三层楼高、耗气如流水、价格动辄百万的传统高压气雾化设备,如同一道…...

新手必读:计算机视觉需要哪些数学基础?如何高效学习线性代数和概率论?

新手必读:计算机视觉需要哪些数学基础?如何高效学习线性代数和概率论? 标签:#计算机视觉、#线性代数、#人工智能、#深度学习、#自然语言处理、#神经网络、#机器学习### 一、痛点引入:为什么很多人怕CV数学?…...

续讲wireshark——ECU测试实践记录

作为高效的以太网报文捕捉,也是测试手里的几件神器之一,wireshark的主要功用就是捕获报文。但也不仅仅只是开始捕获,结束捕获,保存文件,上传钉钉。wireshark入门首先的就是熟悉它的语法。捕获那么多东西,你…...

React 19新特性实战:3种方案实现组件自动刷新优化

在前端应用迭代中,组件不必要的重复渲染一直是性能优化的核心痛点,尤其在数据密集型场景中,频繁刷新不仅会拖慢页面响应速度,还会增加用户设备的资源消耗。React 19针对这一问题推出了多项底层优化,同时提供了更精细化…...

从零构建pix2pix训练集:数据准备与预处理实战

1. 理解pix2pix的数据需求 pix2pix作为经典的图像到图像转换模型,对训练数据有着特殊的要求。我第一次接触这个模型时,最头疼的就是数据准备环节。与普通分类任务不同,pix2pix需要的是成对的图像数据——简单说就是每张输入图片都要有对应的目…...

Kuikly框架性能深度解析:原生级跨端体验如何实现?

Kuikly 是腾讯大前端Oteam基于 Kotlin Multiplatform 开发的跨端框架。其技术设计使其在包体积、渲染效率等核心性能指标上,展现出特定优势。 1. 包体积极致轻量Android平台:AOT模式下仅约300KB iOS平台:约1.2MB Web版本:仅463K…...

手眼标定实战:从千米误差到毫米精度的关键技巧

1. 手眼标定为什么会出现"千米误差"? 第一次做手眼标定的同学,看到结果时可能会吓一跳——明明相机就装在机械臂末端,计算结果却显示两者相距上千米。这种情况我遇到过不止一次,记得有次在汽车装配线上调试,…...

ConvNeXt 系列改进:ConvNeXt 用于视频行为识别:3D ConvNeXt 改进与 Kinetics 实验

引言:当 ConvNeXt 遇上视频 2022年,Facebook AI Research提出的ConvNeXt在计算机视觉领域投下了一颗重磅炸弹。它以纯卷积结构达到了87.8%的ImageNet Top-1精度,在COCO检测和ADE20K分割任务上甚至超越了当时风头正劲的Swin Transformer,证明了“卷积并未死去,只是需要被现…...

[具身智能-364]:LeRobot 不是通用机器人控制系统(如 ROS2 导航/规划栈),而是专注于“感知-决策-动作”端到端学习的 AI 框架。他们共同成为具身智能时代最重要的开源基础设施之一

LeRobot 与 ROS2 并非替代关系,而是“智能生成”与“可靠执行”的双轨架构。二者共同构成了下一代机器人从“实验室原型”走向“物理世界部署”的基石。以下从定位差异、架构协同、融合挑战、演进趋势四个维度进行系统阐述。🔍 一、核心定位与设计哲学&a…...

从SDR#到MATLAB:用RTL-SDR玩转无线信号分析,一份完整的软硬件环境搭建清单

从零构建无线信号分析实验室:RTL-SDR与MATLAB的深度整合指南 无线电波如同城市中看不见的暗流,承载着从广播到卫星通信的各种信息。RTL-SDR这款售价仅20美元左右的USB接收器,配合MATLAB强大的信号处理能力,可以成为探索这片无形领…...

ConvNeXt 系列改进:ConvNeXt 添加 MetaFormer 风格池化层,简化 Block 并保持性能

2026 年的计算机视觉领域呈现出一种有趣的“返璞归真”趋势——在 Vision Transformer 狂飙数年之后,卷积神经网络正以全新的姿态强势回归。根据 Meta AI 近年来发布的官方论文数据,ConvNeXt 已经证明了一个关键事实:不需要 Attention 机制,纯 CNN 依然可以达到甚至超越同级…...

OpenPose Unity插件:5分钟实现实时多人姿态估计

OpenPose Unity插件:5分钟实现实时多人姿态估计 【免费下载链接】openpose_unity_plugin OpenPoses Unity Plugin for Unity users 项目地址: https://gitcode.com/gh_mirrors/op/openpose_unity_plugin 你想为Unity项目添加智能动作识别功能吗?O…...

怎样排查Laravel中Scout全文搜索导致的数据同步报错_队列与底层状态

Scout同步失败主因是底层驱动非2xx响应被静默忽略:启用SCOUT_DEBUGtrue查日志,检查failed_jobs中Guzzle/MeiliSearch异常,精简toSearchableArray字段,避免413/409错误,并手动补同步批量操作数据。Scout 同步失败时队列…...

从LLM到可执行Agent:2026奇点大会指定框架的Tool Calling Pipeline全链路拆解,含4类超时熔断实战配置

第一章:2026奇点智能技术大会:AIAgent工具调用框架 2026奇点智能技术大会(https://ml-summit.org) AIAgent工具调用框架是本届大会发布的开源核心基础设施,旨在统一异构工具接入、语义化意图解析与可验证执行链路。该框架不依赖特定LLM后端&…...

终极Windows内存管理指南:Mem Reduct完整教程与实战配置

终极Windows内存管理指南:Mem Reduct完整教程与实战配置 【免费下载链接】memreduct Lightweight real-time memory management application to monitor and clean system memory on your computer. 项目地址: https://gitcode.com/gh_mirrors/me/memreduct …...

[具身智能-363]:Hugging Face LeRobot 详解:像训练语言模型一样训练机器人

LeRobot 是 Hugging Face 于 2024 年 5 月 正式开源的机器人学习框架,专注于模仿学习(Imitation Learning)与视觉-语言-动作基础模型(VLA)。它的核心目标是:降低机器人 AI 的开发门槛,提供从数据…...

如何配置用户的资源使用上限_MAX_QUERIES_PER_HOUR查询频率限制

MySQL 8.0 仅支持通过 CREATE/ALTER USER ... WITH MAX_QUERIES_PER_HOUR 设置频率限流,按自然小时统计语句总数,不区分类型、不看耗时,不可自定义窗口;GRANT ... WITH 已废弃且逻辑危险,应禁用。MySQL 8.0 怎么给用户…...

【我的Android进阶之旅】Android 7.0报异常:java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated;

之前开发的一个和第三方合作的apk,在之前公司的 Android 5.1 系统的手表上运行正常,今天在公司新开发的 Android 7.1系统的手表上运行的时候,使用 DownloadManager 下载之后,查询下载状态的时候,报了异常 java.lang.SecurityException: COLUMN_LOCAL_FILENAME is depreca…...

【我的Android进阶之旅】快速创建和根据不同的版本类型(Dev、Beta、Release)发布Android 开发库到Maven私服

文章目录 前言 一、准备好要上传的Android 开发库 二、编写上传Maven私服的脚本 2.1 maven_upload.gradle文件 2.2 maven_user.properties配置文件 2.3 maven_pom.properties配置文件 三、执行上传maven的gradle脚本文件 3.1 上传成功 3.2 上传失败 四、使用maven私服中的库文件…...

【我的Android进阶之旅】解决MediaPlayer播放音乐的时候报错: Should have subtitle controller already set

文章目录 一、错误描述 二、错误解决 解决方法一 解决方法二 一、错误描述 刚用MediaPlayer播放Music的时候,看到Log打印台总是会打印一条错误日志,MediaPlayer: Should have subtitle controller already set,虽然程序运行不会出问题,但是看起来红色的日志很显眼,因此决…...

【词汇专栏】 预训练 vs 微调:AI 界最常被混淆的一对概念

预训练 vs 微调:AI 界最常被混淆的一对概念 “我们对模型进行了微调” “这是基于预训练模型的” “我要训练一个专属 AI”……这几句话你一定经常听到,但它们到底有什么区别?谁更厉害?什么时候该用哪个? 一句话定义 …...

【我的Android进阶之旅】 解决bug: Expected file scheme in URI: content://downloads/my_downloads/12

文章目录 一、错误描述 二、错误分析 三、错误解决 四、参考文章 一、错误描述 今天测试MM用HTC手机测试某个模块的时候crash了,抓log后发现是使用DownloadManager下载apk安装包然后自动安装的时候,抛了异常:java.lang.IllegalArgumentException: Expected file scheme in …...

【具身智能新范式】NaVid:纯视觉VLM如何重塑机器人导航的“大脑”与“眼睛”

1. 当机器人学会"看视频":NaVid如何用纯视觉颠覆导航逻辑 记得小时候玩捉迷藏吗?蒙着眼睛数到十,然后靠着对房间布局的记忆和声音线索找人。传统机器人导航就像这个游戏的"青铜玩家"——必须依赖精确的地图(相…...

银行数据中心基础设施建设与运维管理【1.6】

3. 5 常见问题 1. 数据中心采用吊顶还是不吊顶方案的问题 数据中心装饰装修, 可以采用无吊顶板和安装吊顶板两种方案。 数据中心建筑内房间是否吊顶, 主要取决于该房间的应用功能或空调形式, 除 IT 机房、 ECC 及人员区域, 其他房间可不设置吊顶, 走廊区域是否吊顶取决…...