基于Springboot使用MongoDB进行简单Gis操作

  MongoDB使用json数据结构进行数据存储和组织,并提供了对gis的操作支持。mongoDB中基于GeoJson数据格式存储地理信息,并提供了一组函数对地理信息进行操作。因为项目需要,需要进行简单gis操作。在此就简单应用详述一二。

GeoJson数据格式

  GeoJson数据本质是一个json字符串,保存地理位置信息。
关于GeoJson数据的详细形式,及说明可参见官网。
下面列举项目中一个简单的geojson字符串,描述的是一个地理区域。

{
    "_id" : 1,
    "regionName" : "北京市",
    "regionCode" : "010",
    "regionType" : "province"
    "geometry" : {
        "type" : "Polygon", //geojson中地理类型,在此表示一个区域类型,其他类型可参考geojson官方文档。
        "coordinates" : [ //用于描述地理详细信息,一个[x,y]表示一个点的坐标[经度,纬度],在此区域信息,可以是一个包含多个点的闭环区域,首末坐标相同,形成闭环。 
            [ 
                [ 
                    117.209782, 
                    40.082243
                ],
                [ 
                    117.116937, 
                    40.071038
                ],
                 ... ,
                [ 
                    117.209782, 
                    40.082243
                ]
            ]
        ]
    }
}

  描述一个点的geojson字符串。

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [
          110.654296875,
          41.902277040963696
        ]
      }
    }
  ]
}

  可以在geojson.io得到在线生成的geojson数据。

基于Springboot的mongodb gis操作

  下面介绍一个地理围栏功能的功能实现,以此论述mongoDB对gis的操作过程。地理围栏功能,即给定一个点坐标,判断是否在一个指定区域内,超出就报警。
  新建Springboot项目,添加mongoDB的相关依赖jar包,并配置好数据库连接,使用mongo中数据库为gis,具体方式参见之前的文章。新建Collection,名称为geographicalRegion,保存地理信息对象。示例如下:

{
    "_id" : 1,
    "regionName" : "北京市",
    "regionCode" : "010",
    "regionType" : "province",
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [...]
    }
}

创建geoJson的domain对象。Spring-data-mongodb提供了对geoJson的抽象封装。提供了GeoJsonPolygon、Polygon、Line、GeoJsonPoint等类对geojson相关属性进行封装。
我们定义GisRegion对象,用来保存geojson地理信息,以及相关区域的名称和标识码code。如下所示:

@Document(collection = "geographicalRegion")  //spring.data为mongodb定义的注解,直接映射数据库的document名称
public class GisRegion {

    @Id  //指定字段的主键字段
    private int locationId;

    @Field("regionName")  //属性映射数据库document属性名称,若未指定,默认存储实体类属性名称
    private String regionName;
    private String regionCode;
    private String regionType;
    private GeoJsonPolygon geometry;

    public int getLocationId() {
        return locationId;
    }

    public void setLocationId(int locationId) {
        this.locationId = locationId;
    }

    public String getRegionName() {
        return regionName;
    }

    public void setRegionName(String regionName) {
        this.regionName = regionName;
    }

    public String getRegionCode() {
        return regionCode;
    }

    public void setRegionCode(String regionCode) {
        this.regionCode = regionCode;
    }

    public String getRegionType() {
        return regionType;
    }

    public void setRegionType(String regionType) {
        this.regionType = regionType;
    }

    public GeoJsonPolygon getGeometry() {
        return geometry;
    }

    public void setGeometry(GeoJsonPolygon geometry) {
        this.geometry = geometry;
    }
}

  自定义数据库dao并使用MongoTemplate。

@Component
public class GeoJsonDaoImpl {
    @Autowired
    private MongoTemplate mongoTemplate;

    public void savePolygon(Polygon polygon){
        mongoTemplate.save(polygon);
    }

    public void saveRegions(List gisRegionList){
        mongoTemplate.insert(gisRegionList,GisRegion.class);
    }

//使用mongoTemplate封装的intersects方法判断输入geojson信息是否在数据库保存的地理区域内。并返回相关区域信息列表
    public List findIntersective(GeoJson geoJson){
        Query query=new Query(Criteria.where("geometry").intersects(geoJson));
        List list=mongoTemplate.find(query,Polygon.class);
        return list;
    }
//查找目标区域是否在指定的几个区域内,locations的set中保存指定的区域id
//有时数据库中保存的geojson地理信息数据集比较大,整个对象返回往往会消耗很大的io和带宽,所以我们在这里指定仅返回区域的_id,并且只要判断目标geojson是指定的一个区域的子集就返回结果,降低数据库的处理开销
public boolean isInRegion(GeoJsonPoint point,Set locations){
        Criteria geoCriteria=Criteria.where("geometry").intersects(point);

        Criteria[] orArr=new Criteria[locations.size()];
        Iterator iterator=locations.iterator();
        int i=0;
        while(iterator.hasNext()){
            orArr[i]=new Criteria("_id").is(iterator.next());
            i++;
        }
        Criteria orCriteria=new Criteria().orOperator(orArr);
        Criteria andCriteria=new Criteria().andOperator(geoCriteria,orCriteria);

        DBObject field=new BasicDBObject();
        field.put("_id",true);

        Query query=new BasicQuery(new BasicDBObject(),field);
        query.addCriteria(andCriteria);

        GeographicalRegion region=mongoTemplate.findOne(query, GeographicalRegion.class);
        if(region==null){
            return false;
        }
        return true;
    }
}

测试方法:

public void findIntersectiveTest() throws IOException {
    GeoJsonDaoImpl geoJsonDaoImpl=new GeoJsonDaoImpl();
    GeoJson geoJson=new GeoJsonPoint(1,1);
    System.out.println(geoJsonDaoImpl.findIntersective(geoJson));
    Set locationIds=new HashSet();
    locationIds.add(1);
    locationIds.add(2);
    System.out.println(mongoDao.isInRegion(point, locationIds));
    }

关于mongoDB中对地理位置的其他操作,例如搜索指定范围内的指定目标,目标点附近的指定目标等功能都有支持,spring-data-mongodb中都提供了封装函数。可以在MongoTemplate中查看更多的gis操作方法。基于MongoDB更复杂的gis交互,有待进一步研究。

你可能感兴趣的:(基于Springboot使用MongoDB进行简单Gis操作)