java服务端几种常见的空间信息处理方式

前言

最近整理项目代码,偶然间看到了以前写的空间查询代码,顿时回想起来那些试图解决空间与条件复合查询分页问题的夜晚。于是想借着这个机会记录一下到底应该如何进行空间信息的管理呢。

常见方式梳理

基于Arcgis Restful API的方式

技术框架

后台向通过arcgis发布的arcgis服务发送restful请求,通过调整请求参数来获取查询结果,arcgis再去数据库检索数据,并把结果返回请求方,请求方按照规范解析json数据,再组装其他属性。
其中:

  • arcgis负责发布图层服务,访问postgrelsql查询数据
  • postgresl单独保存数据,并单独再管理业务数据,两者通过gid关联
  • 后台服务,请求arcgis并将空间数据和关系数据组装

示例代码

	public String queryByWhere(String tableUrl, String queryWhere, List<Point> pointList, boolean returnIdsOnly){
     
		
		if(queryWhere == null || queryWhere.isEmpty()) {
     
			queryWhere = new String("1=1");
		}

		Map<String, String> params = new HashMap<>();
		
		JSONArray geoJsonArray = new JSONArray();
		JSONArray ringsJsonArray = new JSONArray();
		JSONObject geoJson = new JSONObject();
		
		//geometry
		if(pointList != null && pointList.size() > 4) {
     
			for(Point p : pointList){
     
				geoJsonArray.add(JSONArray.fromObject(p.toString()));
			}
			ringsJsonArray.add(geoJsonArray);
			geoJson.accumulate(RINGS, ringsJsonArray);
			params.put("geometry", geoJson.toString());
			params.put("geometryType", "esriGeometryPolygon");
		}
		
		params.put("where", queryWhere);
		//其他参数
		if(returnIdsOnly) {
     
			params.put("returnIdsOnly", "true");
		}	
		params.put("outfields", "*");
		params.put("f", "json");

		String jsonResult = GisRestService.post(tableUrl, params);
		return jsonResult;
	}
	
	public String queryByObjectIds(String tableUrl, int[] objectIdsArray){
     
		
		if(objectIdsArray == null || objectIdsArray.length == 0) {
     
			return null;
		}
		Map<String, String> params = new HashMap<>();

		StringBuilder objectIdsStrBuf = new StringBuilder();
		for(int i=0; i<objectIdsArray.length; i++) {
     
			if(i != 0) {
     
				objectIdsStrBuf.append(",");
			}
			objectIdsStrBuf.append(objectIdsArray[i]);
		}
		String objectIdsStr = objectIdsStrBuf.toString();
		params.put("objectIds", objectIdsStr);
		params.put("outfields", "*");
		params.put("f", "json");

		return GisRestService.post(tableUrl, params);
	}

优点

比较直观,没有开发经验的话很容易就走上这条路,毕竟如果你手里只有锤子那么看什么都是钉子,当时我们什么也不会只能照葫芦画瓢。

缺点

但对于复杂场景处理较为困难,包括但不限于下面两个问题

  • 大量数据的分页问题,由于业务数据与空间数据分开管理,仅通过gid关联,空间表中没有大部分关系字段,业务数据无法通过空间检索。所以只能先通过空间检索获取gids,再通过in和条件查询的方式实现复合查询,但分页有大问题,而且数据量打了in的效率很低。。。
  • 空间库和关系库的同步问题,由于关系库中存放的是业务数据,增删改都是家常便饭,同步修改当然是好的,但异常情况会使空间和关系库不统一,需要单独开发同步模块保证两者的数据一致。

适合场景

这种解决方案有点像靠着金山要饭吃,postgrelsql是以全能而见长的,自身就有较强的空间信息处理能力,所以恐怕只适合没有后端情况。

基于mybatis+postgis+postgresql的方式

技术框架

  • mybatis,负责数据库访问,xml中直接编写sql可以直接调用postgis的各种辅助方法
  • postgis,负责复杂空间信息的处理和辅助
  • postgresql,负责空间信息保存,这次业务数据和空间数据统一为一张表,对于空间数据会有空间字段

示例

Mapper

@Mapper
@Component
public interface MapEelementMapper {
     
  
    /**
     * 条件查询
     * @param mapElement 查询条件
     * @return 符合条件的数据
     */
    List<MapElement> findByCondition(MapElement mapElement);

    /**
     * @param geometry 对变形地理信息
     * @param type     元素大类
     * @param subType  元素细分类
     * @return 给定多边形区域中满足条件的元素的集合
     */
    List<MapElement> findMapElementByPolygon(@Param("geometry") String geometry,
                                             @Param("type") String type,
                                             @Param("subType") String subType);


}

xml

<select id="findMapElementByPolygon" resultMap="MapElementMap">
        SELECT id, name,       
        ST_AsGeoJson(element_location) as element_location
        from map_elements
        where ST_Contains( ST_MakePolygon(ST_GeomFromText('LINESTRING' || #{geometry}, 4326)) , element_location) = 't'
    select>

    <select id="findByCondition" resultMap="MapElementMap">
        SELECT id,
        name,
        ST_AsGeoJson(element_location) as element_location
        FROM map_elements where deleted = false

        <if test="name!=null">
            and name like concat('%', #{name}, '%')
        if>
        <if test="spatialPointsStr!=null">
            and ST_Contains( ST_MakePolygon(ST_GeomFromText('LINESTRING' || #{spatialPointsStr}, 4326)) ,
            element_location) = 't'
        if>

        ORDER BY update_time DESC

    select>

优点

比较灵活,直接操作数据库,效率也相较于之前的方案要高得多,借助postgis可以实现许多以前想不到的功能,比如缓冲区分析,路径规划等。
技术栈也比较通用。

缺点

暂时没有想到、

基于geotools的方式

较为复杂,需要一定的开发经验,但更高的可控程度和更强的能力。这个后续再跟大家介绍。

其他方式

redis,mongodb,es都提供了一定的空间查询和处理的能力,有兴趣的同学可以去尝试一下。

总结

强烈推荐mybatis+postgrelsql+postgis的解决方案,有必要的再配合geoserver完全可以实现图层的发布显示。

你可能感兴趣的:(java服务端几种常见的空间信息处理方式)