当前位置: 代码网 > it编程>编程语言>Java > 使用Spring Data MongoDB进行地理位置相关查询的步骤和示例

使用Spring Data MongoDB进行地理位置相关查询的步骤和示例

2025年05月27日 Java 我要评论
以下是如何使用 spring data mongodb 进行地理位置相关查询的步骤和示例:核心概念:geojson 对象: mongodb 推荐使用 geojson 格式来存储地理位置数据。sprin

以下是如何使用 spring data mongodb 进行地理位置相关查询的步骤和示例:

核心概念:

  1. geojson 对象: mongodb 推荐使用 geojson 格式来存储地理位置数据。spring data mongodb 提供了相应的 geojson 类型,如 geojsonpointgeojsonpolygongeojsonlinestring 等。
    • geojsonpoint: 表示一个点,例如 [longitude, latitude]
  2. 地理空间索引 (geospatial index): 为了高效地执行地理位置查询,必须在存储位置数据的字段上创建地理空间索引。
    • 2dsphere: 支持球面几何计算,适用于地球表面的经纬度数据(推荐)。
    • 2d: 支持平面几何计算,适用于二维平面上的点。
  3. 查询操作符: mongodb 提供了多种地理位置查询操作符:
    • $near / $nearsphere: 查找靠近某个点的文档,并按距离排序。
    • $geowithin: 查找几何形状(如多边形、圆形)内的文档。
    • $geointersects: 查找与指定 geojson 对象相交的文档。
    • $centersphere (与 $geowithin 结合使用): 定义一个球心和半径的圆形区域进行查询。

步骤详解:

步骤 1: 添加依赖

确保你的 pom.xml (maven) 或 build.gradle (gradle) 文件中包含 spring data mongodb 的依赖:

<!-- pom.xml (maven) -->
<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-data-mongodb</artifactid>
</dependency>

步骤 2: 定义实体 (entity)

在你的实体类中,使用 org.springframework.data.mongodb.core.geo.geojsonpoint (或其他 geojson 类型) 来存储位置信息。

import org.springframework.data.annotation.id;
import org.springframework.data.mongodb.core.geo.geojsonpoint;
import org.springframework.data.mongodb.core.index.geospatialindextype;
import org.springframework.data.mongodb.core.index.geospatialindexed;
import org.springframework.data.mongodb.core.mapping.document;

@document(collection = "locations")
public class locationentity {

    @id
    private string id;
    private string name;

    // 存储经纬度信息,并创建 2dsphere 索引
    @geospatialindexed(type = geospatialindextype.geo_2dsphere)
    private geojsonpoint location; // [longitude, latitude]

    public locationentity() {}

    public locationentity(string name, geojsonpoint location) {
        this.name = name;
        this.location = location;
    }

    // getters and setters
    public string getid() {
        return id;
    }

    public void setid(string id) {
        this.id = id;
    }

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }

    public geojsonpoint getlocation() {
        return location;
    }

    public void setlocation(geojsonpoint location) {
        this.location = location;
    }

    @override
    public string tostring() {
        return "locationentity{" +
               "id='" + id + '\'' +
               ", name='" + name + '\'' +
               ", location=" + (location != null ? location.getcoordinates() : null) +
               '}';
    }
}

注意:

  • @geospatialindexed(type = geospatialindextype.geo_2dsphere) 注解会自动在 location 字段上创建 2dsphere 索引。这是进行地理位置查询的关键。
  • geojson 点的坐标顺序是 [longitude, latitude] (经度在前,纬度在后)。

步骤 3: 创建 repository 接口

spring data mongodb 可以通过方法名派生查询,或者使用 @query 注解自定义查询。

import org.springframework.data.geo.distance;
import org.springframework.data.geo.point;
import org.springframework.data.geo.polygon;
import org.springframework.data.mongodb.repository.mongorepository;
import java.util.list;

public interface locationrepository extends mongorepository<locationentity, string> {

    // 1. 查找靠近某个点的文档 (使用 $nearsphere)
    // spring data 会自动使用 $nearsphere 因为索引是 2dsphere
    // point 来自 org.springframework.data.geo.point (x=longitude, y=latitude)
    // distance 来自 org.springframework.data.geo.distance
    list<locationentity> findbylocationnear(point point, distance distance);

    // 也可以只按点查找,不限制距离 (结果按距离排序)
    list<locationentity> findbylocationnear(point point);

    // 2. 查找在指定多边形内的文档 (使用 $geowithin)
    // polygon 来自 org.springframework.data.geo.polygon
    list<locationentity> findbylocationwithin(polygon polygon);

    // 3. 查找在指定圆形区域内的文档 (使用 $geowithin 和 $centersphere)
    // circle 来自 org.springframework.data.geo.circle
    // spring data 会将其转换为 $geowithin 与 $centersphere
    list<locationentity> findbylocationwithin(org.springframework.data.geo.circle circle);

    // 4. 查找与指定 geojson 几何图形相交的文档 (使用 $geointersects)
    // 需要使用 mongotemplate 或 @query 来实现更复杂的 geojson 相交查询,
    // 因为派生查询对 $geointersects 的支持有限,尤其是对于复杂的 geojson 输入。
    // 但简单的 point 相交可以。
    // 对于更复杂的 geojson (如 polygon),通常使用 mongotemplate 或 @query
    // list<locationentity> findbylocationintersects(geojson geometry); // 示例,可能需要自定义实现

}

使用的 spring data geo 类型:

  • org.springframework.data.geo.point: 用于查询参数,表示一个点 (x 对应经度, y 对应纬度)。
  • org.springframework.data.geo.distance: 用于指定距离,可以包含单位 (如 metrics.kilometers)。
  • org.springframework.data.geo.polygon: 用于查询参数,表示一个多边形。
  • org.springframework.data.geo.circle: 用于查询参数,表示一个圆形。
  • org.springframework.data.geo.box: 用于查询参数,表示一个矩形。

步骤 4: 使用 repository 或 mongotemplate 进行查询

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.geo.*;
import org.springframework.data.mongodb.core.mongotemplate;
import org.springframework.data.mongodb.core.geo.geojsonpoint;
import org.springframework.data.mongodb.core.geo.geojsonpolygon;
import org.springframework.data.mongodb.core.query.criteria;
import org.springframework.data.mongodb.core.query.query;
import org.springframework.stereotype.service;

import jakarta.annotation.postconstruct;
import java.util.arrays;
import java.util.list;

@service
public class locationservice {

    @autowired
    private locationrepository locationrepository;

    @autowired
    private mongotemplate mongotemplate;

    @postconstruct
    public void init() {
        locationrepository.deleteall(); // 清理旧数据

        // 插入一些示例数据
        // 故宫 (116.403963, 39.915119)
        locationrepository.save(new locationentity("forbidden city", new geojsonpoint(116.403963, 39.915119)));
        // 天安门广场 (116.3912757, 39.9037078)
        locationrepository.save(new locationentity("tiananmen square", new geojsonpoint(116.3912757, 39.9037078)));
        // 颐和园 (116.275136, 39.999077)
        locationrepository.save(new locationentity("summer palace", new geojsonpoint(116.275136, 39.999077)));
        // 东方明珠 (121.499718, 31.239703)
        locationrepository.save(new locationentity("oriental pearl tower", new geojsonpoint(121.499718, 31.239703)));
    }

    public void performgeoqueries() {
        system.out.println("--- performing geo queries ---");

        // 中心点: 北京市中心附近 (例如王府井 116.417427, 39.913904)
        point centerpoint = new point(116.417427, 39.913904); // longitude, latitude

        // 1. 查找王府井附近 5 公里内的地点
        distance fivekilometers = new distance(5, metrics.kilometers);
        list<locationentity> nearwangfujing = locationrepository.findbylocationnear(centerpoint, fivekilometers);
        system.out.println("\nlocations near wangfujing (5km):");
        nearwangfujing.foreach(system.out::println); // 应该包含故宫和天安门

        // 2. 查找在指定多边形内的地点 (大致覆盖北京二环内)
        // 注意:多边形的点必须形成闭合环路,且第一个点和最后一个点相同
        polygon beijingring2 = new polygon(
                new point(116.30, 39.85), //西南
                new point(116.50, 39.85), //东南
                new point(116.50, 39.95), //东北
                new point(116.30, 39.95), //西北
                new point(116.30, 39.85)  //闭合
        );
        list<locationentity> withinbeijingring2 = locationrepository.findbylocationwithin(beijingring2);
        system.out.println("\nlocations within beijing ring 2 (approx):");
        withinbeijingring2.foreach(system.out::println); // 应该包含故宫和天安门

        // 3. 查找在指定圆形区域内的地点 (以故宫为圆心,2公里为半径)
        point forbiddencitycoords = new point(116.403963, 39.915119);
        distance twokilometers = new distance(2, metrics.kilometers);
        // 对于2dsphere索引, circle的距离单位会被正确处理 (例如转换为弧度)
        circle aroundforbiddencity = new circle(forbiddencitycoords, twokilometers);
        list<locationentity> withincircle = locationrepository.findbylocationwithin(aroundforbiddencity);
        system.out.println("\nlocations within 2km of forbidden city:");
        withincircle.foreach(system.out::println); // 应该包含故宫和天安门

        // 4. 使用 mongotemplate 进行 $geointersects 查询
        // 定义一个 geojsonpolygon (注意点顺序,逆时针为外部,顺时针为内部,但通常简单多边形即可)
        // 这里用和上面一样的多边形,但用 geojsonpolygon
        geojsonpolygon querypolygon = new geojsonpolygon(
                new point(116.30, 39.85),
                new point(116.50, 39.85),
                new point(116.50, 39.95),
                new point(116.30, 39.95),
                new point(116.30, 39.85)
        );
        query intersectsquery = new query(criteria.where("location").intersects(querypolygon));
        list<locationentity> intersectinglocations = mongotemplate.find(intersectsquery, locationentity.class);
        system.out.println("\nlocations intersecting with query polygon (mongotemplate):");
        intersectinglocations.foreach(system.out::println);


        // 5. 使用 mongotemplate 进行 $nearsphere 查询,并指定最小和最大距离
        query nearquerywithminmax = new query(
            criteria.where("location")
                    .nearsphere(centerpoint) // 使用 spring data point
                    .mindistance(1000 / 6378137.0) // 最小距离1公里 (转换为弧度,mongodb $nearsphere 需要弧度或米)
                                                   // 或者直接用米: .mindistance(1000) 如果mongodb版本支持
                    .maxdistance(5000 / 6378137.0) // 最大距离5公里
                                                   // 或者直接用米: .maxdistance(5000)
        );
        // 如果mongodb 4.0+ 且 spring data mongodb 2.2+, 可以直接用米
        // query nearquerywithminmaxmeters = new query(
        // criteria.where("location")
        // .nearsphere(centerpoint)
        // .mindistance(1000.0) // 1000 meters
        // .maxdistance(5000.0) // 5000 meters
        // );
        // list<locationentity> nearwithminmax = mongotemplate.find(nearquerywithminmaxmeters, locationentity.class);
        // system.out.println("\nlocations near wangfujing (1km-5km, mongotemplate):");
        // nearwithminmax.foreach(system.out::println);

        // 对于 $nearsphere,spring data 的 repository 方法中的 distance 对象会自动处理单位转换。
        // 使用 mongotemplate 时,对于 $mindistance / $maxdistance:
        // - 如果是 `2dsphere` 索引,mongodb 期望距离单位是米。
        // - 如果是 `2d` 索引,mongodb 期望距离单位是索引坐标系的单位。
        // spring data mongodb 3.0+ 配合 mongodb 4.0+,`nearsphere` 可以直接接受米为单位的 `mindistance`/`maxdistance`。
        // 如果使用较旧版本,可能需要将距离转换为弧度(如示例中除以地球半径)。
        // 简单的 findbylocationnear(point, distance) 通常是更方便的选择。
    }
}

运行示例 (在一个 spring boot 应用中):

import org.springframework.boot.commandlinerunner;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.context.annotation.bean;

@springbootapplication
public class mongogeoapplication {

    public static void main(string[] args) {
        springapplication.run(mongogeoapplication.class, args);
    }

    @bean
    commandlinerunner runner(locationservice locationservice) {
        return args -> {
            locationservice.performgeoqueries();
        };
    }
}

总结与要点:

  1. 实体定义: 使用 geojsonpoint (或其他 geojson* 类型) 存储位置,并用 @geospatialindexed 创建 2dsphere 索引。
  2. 坐标顺序: 始终记住 geojson 使用 [longitude, latitude]。spring data 的 point 对象构造函数 new point(x, y) 中 x 是经度,y 是纬度。
  3. repository 查询: spring data repositories 为常见的地理位置查询(如 nearwithin)提供了便捷的方法名派生。
  4. mongotemplate: 对于更复杂或自定义的地理位置查询(如 $geointersects 配合复杂 geojson 对象,或需要更精细控制 $nearsphere 的 $mindistance/$maxdistance),可以使用 mongotemplate
  5. 单位:
    • org.springframework.data.geo.distance: 允许你指定单位 (如 metrics.kilometersmetrics.miles)。spring data 会在与 mongodb 交互时处理转换。
    • mongodb 的 $nearsphere 和 $centersphere (用于 2dsphere 索引) 默认使用作为距离单位。
    • 当使用 mongotemplate 时,需要注意 mindistance/maxdistance 的单位,较新版本的 mongodb (4.0+) 和 spring data mongodb (2.2+/3.0+) 可以直接使用米。
  6. 性能: 地理空间索引对于查询性能至关重要。确保索引已正确创建。

以上就是使用spring data mongodb进行地理位置相关查询的步骤和示例的详细内容,更多关于spring data mongodb地理位置查询的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com