最近整理项目代码,偶然间看到了以前写的空间查询代码,顿时回想起来那些试图解决空间与条件复合查询分页问题的夜晚。于是想借着这个机会记录一下到底应该如何进行空间信息的管理呢。
后台向通过arcgis发布的arcgis服务发送restful请求,通过调整请求参数来获取查询结果,arcgis再去数据库检索数据,并把结果返回请求方,请求方按照规范解析json数据,再组装其他属性。
其中:
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);
}
比较直观,没有开发经验的话很容易就走上这条路,毕竟如果你手里只有锤子那么看什么都是钉子,当时我们什么也不会只能照葫芦画瓢。
但对于复杂场景处理较为困难,包括但不限于下面两个问题
这种解决方案有点像靠着金山要饭吃,postgrelsql是以全能而见长的,自身就有较强的空间信息处理能力,所以恐怕只适合没有后端情况。
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可以实现许多以前想不到的功能,比如缓冲区分析,路径规划等。
技术栈也比较通用。
暂时没有想到、
较为复杂,需要一定的开发经验,但更高的可控程度和更强的能力。这个后续再跟大家介绍。
redis,mongodb,es都提供了一定的空间查询和处理的能力,有兴趣的同学可以去尝试一下。
强烈推荐mybatis+postgrelsql+postgis的解决方案,有必要的再配合geoserver完全可以实现图层的发布显示。