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

在Java Spring Boot(Gradle)中用Mapbox获取指定坐标X公里内公共区域

问题:在Java/Spring Boot(Gradle)项目中获取指定坐标X公里内的公共区域POI列表

已尝试的两种实现及问题

方案1:使用Mapbox Geocoding SDK,结果范围偏差

public List<Point> getCoordinates2() { 
    List<Point> points=new ArrayList<>(); 
    MapboxGeocoding mapboxGeocoding = MapboxGeocoding.builder() 
            .accessToken(accessToken) 
            .query(GeocodingCriteria.TYPE_POI)            
            .country("IN") // ISO 3166 alpha 2 country code for India  
            .proximity(Point.fromLngLat(78.4983,  17.4399)) 
            .build(); 

    try { 
        GeocodingResponse response = mapboxGeocoding.executeCall().body(); 
        if (response != null && response.features().size() > 0) { 
            for (int i = 0; i < response.features().size(); i++) { 
                CarmenFeature feature = response.features().get(i); 
                String placeName = feature.placeName(); 
                Point point = (Point) feature.geometry(); 
                points.add(point); 
                String coordinates = String.format("%f,%f", point.longitude(), point.latitude()); 
                System.out.println(placeName + ": " + coordinates); 
            } 
        } 
    } catch (IOException  e) { 

    } 

    return points; 
} 

问题:仅设置proximity参数无法限制POI范围,返回结果分散到印度多个城市,不符合指定坐标附近的需求。

返回结果示例:

Point Pleasant Restaurant, Hyderabad, Telangana 500034, India: 78.444396,17.415243
PNT Colony, Vijayawada, NTR, Andhra Pradesh, India: 80.639416,16.538129
Poibeda, Machh Kund, Koraput, Odisha, India: 82.540986,18.584619
Poigai, Vellore, Vellore, Tamil Nadu, India: 79.053124,12.915003
Poigainallur, Arakonam, Ranipet, Tamil Nadu, India: 79.564364,12.903959

方案2:使用OkHttpClient调用Mapbox API,结果数量受限

public List<Point> getCoordinates() {
        List<Point> points = new ArrayList<>();

        OkHttpClient client = new OkHttpClient();
        String parksTemplesHotelsInJPnagar = "https://api.mapbox.com/geocoding/v5/mapbox.places/park%20and%20temple%20and%20hotels.json?bbox=77.449061%2C12.848347%2C77.695739%2C12.966143&limit=50&proximity=77.5724%2C12.907252&autocomplete=false&access_token="+accessToken;
        
        Request request = new Request.Builder()
                .url(parksTemplesHotelsInJPnagar)
                .build();

        try {
            Response response = client.newCall(request).execute();
            String responseBody = response.body().string();

            JSONArray features = new JSONObject(responseBody).getJSONArray("features");

            for (int i = 0; i < features.length(); i++) {
                JSONObject feature = features.getJSONObject(i);
                JSONArray coordinates = feature.getJSONArray("center");
                Point point = Point.fromLngLat(coordinates.getDouble(0), coordinates.getDouble(1));
                points.add(point);
                String placeName = feature.getString("text");
                System.out.println(placeName + ": " + point.longitude() + ", " + point.latitude());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return points;
    }

问题:设置bbox后返回的POI符合范围,但实际仅返回10条结果,即使指定了limit=50,无法获取区域内全部目标POI。

返回结果示例:

Banashankari Temple: 77.573312, 12.915979
Ragiguda Temple: 77.593409, 12.91467
Dharmagiri Manjunathaswamy Temple: 77.564309, 12.921
Venkateshwara Swamy Temple: 77.589474, 12.910329
Laxman Rao Park - Pride of JAYANAGAR: 77.580493, 12.918529
Lakshman Rao Park Jayanagar: 77.578719, 12.918843
Raagi Gudda Prasanna Anjaneya Temple: 77.593239, 12.915066
KS Layout Park 2: 77.559655, 12.906428
Devagiri Temple: 77.567178, 12.926082
ISKCON @ Vaikunta Hill: 77.549434, 12.89312

解决方案:修正范围偏差与结果数量限制

1. 解决范围偏差:用bbox严格限制区域

proximity仅用于提升结果排序优先级,无法限制POI范围。要获取X公里内的POI,需将半径转换为经纬度边界框(bbox):

  • 用Haversine公式计算中心坐标对应的西南、东北端点(小半径场景下足够准确,高精度场景可引入GeoTools等地理库)
  • 在API请求中添加bbox参数,确保返回POI严格落在目标区域内

2. 解决数量限制:合理设置limit与分页

  • Mapbox Geocoding API最大limit值为50,若设置后仍返回少量结果,可能是目标区域内匹配的POI数量本身较少,需优化查询关键词(如用bus station替代模糊的poi)
  • 若POI数量超过50,通过offset参数分页查询,循环获取全部结果

3. 优化后的Mapbox SDK实现示例

import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import com.mapbox.api.geocoding.v5.MapboxGeocoding;
import com.mapbox.api.geocoding.v5.models.GeocodingResponse;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.BoundingBox;
import com.mapbox.api.geocoding.v5.models.CarmenFeature;

public class MapboxPoiService {
    private String accessToken;

    public MapboxPoiService(String accessToken) {
        this.accessToken = accessToken;
    }

    public List<CarmenFeature> getNearbyPois(double centerLng, double centerLat, int radiusKm, List<String> poiTypes) {
        List<CarmenFeature> poiFeatures = new ArrayList<>();

        // 计算半径对应的bbox边界
        double earthRadius = 6371;
        double latRadian = Math.toRadians(centerLat);
        double lngDelta = Math.toDegrees(radiusKm / (earthRadius * Math.cos(latRadian)));
        double latDelta = Math.toDegrees(radiusKm / earthRadius);

        double minLng = centerLng - lngDelta;
        double minLat = centerLat - latDelta;
        double maxLng = centerLng + lngDelta;
        double maxLat = centerLat + latDelta;

        // 构建多类型POI查询
        String query = String.join(",", poiTypes);

        // 首次请求
        MapboxGeocoding geocoding = buildGeocodingRequest(query, minLng, minLat, maxLng, maxLat, 0);
        try {
            GeocodingResponse response = geocoding.executeCall().body();
            if (response != null && !response.features().isEmpty()) {
                poiFeatures.addAll(response.features());
                // 分页获取剩余结果
                int total = response.features().size();
                int offset = 50;
                while (total == 50) {
                    geocoding = buildGeocodingRequest(query, minLng, minLat, maxLng, maxLat, offset);
                    response = geocoding.executeCall().body();
                    if (response == null || response.features().isEmpty()) break;
                    poiFeatures.addAll(response.features());
                    total = response.features().size();
                    offset += 50;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return poiFeatures;
    }

    private MapboxGeocoding buildGeocodingRequest(String query, double minLng, double minLat, double maxLng, double maxLat, int offset) {
        return MapboxGeocoding.builder()
                .accessToken(accessToken)
                .query(query)
                .country("IN")
                .bbox(BoundingBox.fromLngLat(minLng, minLat, maxLng, maxLat))
                .limit(50)
                .offset(offset)
                .autocomplete(false)
                .build();
    }

    // 调用示例
    public static void main(String[] args) {
        MapboxPoiService service = new MapboxPoiService("YOUR_MAPBOX_ACCESS_TOKEN");
        List<String> targetTypes = List.of("park", "theater", "bus station", "railway station", "temple");
        List<CarmenFeature> pois = service.getNearbyPois(78.4983, 17.4399, 10, targetTypes);
        for (CarmenFeature poi : pois) {
            Point point = (Point) poi.geometry();
            System.out.printf("%s: %.6f, %.6f%n", poi.placeName(), point.longitude(), point.latitude());
        }
    }
}

关键说明

  • bbox计算:手动实现为近似值,适合小半径场景;若需高精度,可引入GeoTools等专业地理库
  • POI筛选:使用具体关键词(如railway station)而非TYPE_POI,能精准匹配目标公共区域
  • 分页逻辑:通过offset参数循环请求,确保获取区域内全部符合条件的POI

内容的提问来源于stack exchange,提问作者Balu Mahendra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:57:05