You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Telegram Bot:无需Google Maps API,如何从经纬度获取城市国家名?

无需依赖Google Maps API的经纬度转城市国家方案

方案一:使用OpenStreetMap Nominatim API

这是完全免费的反向地理编码服务,不需要API密钥,只需遵守基础使用规范(比如避免高频调用、设置明确的User-Agent标识)。

实现步骤(Spring Boot)

  1. 引入WebClient依赖(Spring WebFlux,也可替换为RestTemplate):
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
  1. 编写地理编码服务类,调用接口并解析返回结果:
@Service
public class ReverseGeocodingService {
    private final WebClient webClient;

    public ReverseGeocodingService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
                .baseUrl("https://nominatim.openstreetmap.org")
                .defaultHeader("User-Agent", "YourSpringBootTelegramBot/1.0") // 替换为你的应用标识
                .build();
    }

    public Optional<LocationDetails> getCityAndCountry(double latitude, double longitude) {
        try {
            String responseBody = webClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/reverse")
                            .queryParam("lat", latitude)
                            .queryParam("lon", longitude)
                            .queryParam("format", "json")
                            .queryParam("addressdetails", 1) // 要求返回详细地址信息
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            if (responseBody == null) {
                return Optional.empty();
            }

            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode root = objectMapper.readTree(responseBody);
            JsonNode addressNode = root.get("address");

            if (addressNode == null) {
                return Optional.empty();
            }

            // 优先取city,无则降级取town/village
            String city = addressNode.has("city") ? addressNode.get("city").asText() :
                    addressNode.has("town") ? addressNode.get("town").asText() :
                    addressNode.has("village") ? addressNode.get("village").asText() : null;
            String country = addressNode.has("country") ? addressNode.get("country").asText() : null;

            if (city != null && country != null) {
                return Optional.of(new LocationDetails(city, country));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Optional.empty();
    }

    // 结果封装类
    public static class LocationDetails {
        private final String city;
        private final String country;

        public LocationDetails(String city, String country) {
            this.city = city;
            this.country = country;
        }

        // Getters
        public String getCity() { return city; }
        public String getCountry() { return country; }
    }
}
  1. 在Telegram Bot逻辑中注入服务并调用:
@Autowired
private ReverseGeocodingService geocodingService;

// 处理用户发送的位置信息
public void handleUserLocation(double lat, double lon) {
    geocodingService.getCityAndCountry(lat, lon)
            .ifPresent(location -> {
                String replyMsg = String.format("当前所在城市:%s,国家:%s", location.getCity(), location.getCountry());
                // 发送消息给用户的逻辑
            });
}

注意事项

  • 控制请求频率,Nominatim默认限制每秒1次请求,超出可能被临时封禁;
  • 必须设置User-Agent头,明确标识你的应用信息,否则请求可能被拒绝。

方案二:离线反向地理编码(无网络场景适用)

如果Bot需要在无网络环境下运行,可考虑搭建本地Nominatim实例或使用带空间索引的本地数据库(如PostGIS)。但这种方式配置维护成本较高,仅推荐对离线访问有硬性要求的场景。

内容的提问来源于stack exchange,提问作者Yuliia Liapkalo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 02:20:59