• 【转】ArcGIS Server如何动态添加图层并进行查询


    摘要:在ArcGIS Server 9.2的应用程序中,如果使用的资源类型是com.esri.adf.web.ags.data.AGSLocalMapResource,就可以在该资源上动态添加新的图层,图层数据可以来自不同的地方,比如本地的shapefile、file geodatabase或者SDE,也可以来自WMS等web服务。本文以本地的file geodatabase为例,为AGSLocalMapResource动态添加一个新的图层。

    软件:ArcGIS Server for Java platform

    版本:9.2

    平台:Solaris 9.0, 10; Linux Red Hat AS/ES 3.0, AS/ES 4.0; Linux-SUSE Server 9

      在ArcGIS Server 9.2的应用程序中,如果使用的资源类型是com.esri.adf.web.ags.data.AGSLocalMapResource,就可以在该资源上动态添加新的图层,图层数据可以来自不同的地方,比如本地的shapefile、file geodatabase或者SDE,也可以来自WMS等web服务。本文以本地的file geodatabase为例,为AGSLocalMapResource动态添加一个新的图层。

      首先,要得到地图的IMap接口才能对地图的图层进行操作。

    清单1. 获取IMap接口

    1.  AGSLocalMapResource res = (AGSLocalMapResource)webContext                               .getResources().get("ags0");

    2.  com.esri.arcgis.carto.MapServer mapServer = res.getLocalMapServer();

    3.  try {

    4.    IMap map = mapServer.getMap(mapServer.getDefaultMapName());

    5.    map.addLayer(ILayer layer);

    6.  }catch(Exception e){

    7.  }

      动态添加图层的核心代码就是第5行,它接收的参数是实现了ILayer接口的对象。因此,接下来我们需要把file geodatabase里的feature class组装成一个ILayer对象。

    清单2. 从Feature Class到ILayer

    1.  IServerContext sctx = res.getServerContext();

    2.   IWorkspaceFactory pWorkspaceFactory = (IWorkspaceFactory) sctx                                         .createObject(FileGDBWorkspaceFactory.getClsid());

    3.    IFeatureWorkspace pFWS = (IFeatureWorkspace) pWorkspaceFactory                                    .openFromFile("E:\\data\\qixiang\\qixiang.gdb", 0);

    4.    IFeatureClass fc = pFWS.openFeatureClass("Road");

    5.   IFeatureLayer fLayer = (IFeatureLayer) sctx                                                    .createObject(FeatureLayer.getClsid());

                               

    6.   fLayer.setFeatureClassByRef(fc);

    7.  fLayer.setName("Road");

      Server中的AO对象,必须在一个IServerContext上下文中使用,因此,AO对象的创建跟一般的Java类有所不同。因为数据是保存在filegeodatabase,所以在第2行代码中我们创建了一个FileGDBWorkspaceFactory,接下来的两行利用这个工厂类打开了一个IFeatureWorkspace,然后读取了其中的一个feature class。最后,用这个feature class设置了一个IFeatureLayer(ILayer的一个子类)。

      有了IMap和IFeatureLayer对象以后,其实就已经能动态添加图层了。但是这样添加的图层有一点欠缺的地方——它的渲染方式是随机的。就像我们用ArcMap直接打开一个polygon feature class时,ArcMap会随机选择一个填充色。为了保证每次用户添加图层以后能够看到同样的效果,我们需要为动态图层设置一个渲染方式。当然,我们可以在程序中为不同类型的要素分别设置一个Renderer,但是本文将探讨另一种方式。先用ArcMap设置好渲染方式,然后保存成一个*.lyr文件,动态添加图层的时候从lyr文件中读取Renderer信息,然后添加到IFeatureLayer。毕竟,用ArcMap设置Renderer比写代码要简单多了!而且,也更易于分发。

    清单3. 从*.lyr文件中读取Renderer信息

    1.  IMapDocument doc = (IMapDocument)sctx.createObject(MapDocument.getClsid());

    2.  doc.open(lyrFilePath, null);

    3.    ILayer lyr = doc.getLayer(0, 0);//get the first map's first layer

    4.    IFeatureRenderer renderer = null;

    5.    if(lyr instanceof IGeoFeatureLayer){

    6.                  IGeoFeatureLayer geoLyr = (IGeoFeatureLayer)lyr;

    7.                  renderer = geoLyr.getRenderer();

    8.   }

      在清单3中我们创建了一个MapDocument对象来读取lyr文件(API说明:The MapDocument CoClass encapsulates map document files (*.mxd, *mxt, *.pmf) and layer files (*.lyr))。第2行代码中的lyrFilePath就是lyr文件存放的路径。由于打开的是lyr文件,只有一个图层,所以第3行代码的两个参数都为零,表示打开的是第一个地图的第一个图层。接下来从图层文件中读取Renderer信息。

      接下来,我们就可以把Renderer信息赋给图层,然后将图层添加到地图上。

    清单4. 设置渲染方式,添加图层

    1.  if(renderer != null){

    2.           IGeoFeatureLayer geoFeatureLyr = (IGeoFeatureLayer)fLayer;

    3.           geoFeatureLyr.setRendererByRef(renderer);

    4.    }

    5.    fLayer.setVisible(true);

    6.    map.addLayer(fLayer);

    7.   map.moveLayer(fLayer, 1);

      至此,我们通过map service提供的AO接口完成了动态添加图层的工作,但是如果这时候我们去刷新浏览器,并不会看到新增加的图层!这是由于Web ADF层还不知道图层信息发生变化了。这与Web ADF的初始化有关,当一个session启动的时候,WebContext会根据map service的信息完成初始化,包括一些列的functionalities以及attributes,这些初始化信息中就包含图层信息(保存在com.esri.arcgisws.MapDescription和com.esri.arcgisws.MapLayerInfo等类中)。在WebContext初始化完成以后,如果map service的信息发生改变,必须由程序员自己去刷新Web ADF中的相关对象,实现Web ADF对象与map service同步。有趣的是,并不是所有对map service的修改都要自己去通知Web ADF,比如修改图层的Renderer信息就不需要。我觉得如果com.esri.arcgisws包中的与AO同名的对象,很可能就需要手工修改,因为这些对象都是初始化的时候创建的;如果没有,说明没有必要为其单独创建Web ADF对象,需要的时候就直接访问AO接口了。

    清单5. 刷新ADF对象

    1.  mapServer.refreshServerObjects();

                               

    2.  IMapServerInfo serverInfo = mapServer.getServerInfo(mapServer.getDefaultMapName());

                               

    3.  agsServerInfo = (com.esri.arcgisws.MapServerInfo)AGSUtil.createStubFromArcObject(serverInfo,com.esri.arcgisws.MapServerInfo.class,sctx);

     

    4.    com.esri.arcgisws.MapServerInfo si = mapFun.getMapServerInfo();

    5.    si.setMapLayerInfos(agsServerInfo.getMapLayerInfos());

    6.   mapFun.setMapDescription(agsServerInfo.getDefaultMapDescription());

      在清单5中,我们先刷新了map server object,然后获取了新的IMapServerInfo对象。第3行代码中我们完成了从AO对象到ADF对象的转换,这样,ADF就有了一个反映当前map service状态的com.esri.arcgisws.MapServerInfo。4到6行代码用新的com.esri.arcgisws.MapServerInfo刷新了AGSMapFunctionality,从而完成了ADF与map service的同步。下面的截图显示了动态添加图层的效果。

     

      由于WebContext以及它管理的一系列ADF资源只在session开始时进行一次初始化,因此动态添加的图层就无法用WebQuery来进行查询和高亮显示。在清单5中已经介绍了如何刷新ADF端的对象,因此,我们可以用更新以后的com.esri.arcgisws.MapServerPort对动态添加的图层进行查询。

      接下来的例子中,让用户在地图上拖一个矩形框,然后查询所有图层中与该矩形框相交的要素,并将它们高亮显示。首先需要将用户在地图上绘制的矩形框传递到服务器端,并创建一个com.esri.arcgisws.PolygonN对象。

    清单6. 捕获屏幕操作并构造服务器端几何要素

    1. WebExtent ext = (WebExtent)event.getWebGeometry().toMapGeometry(webContext.getWebMap());

    2. EnvelopeN env = (EnvelopeN)AGSUtil.toAGSGeometry(ext);

      接下来可以根据该PolygonN新建一个com.esri.arcgisws.SpatialFilter对象。

    清单7. 创建SpatailFilter对象

    1.  SpatialFilter spatialFilter = new SpatialFilter();

    2.  spatialFilter.setSpatialRel(EsriSpatialRelEnum.esriSpatialRelIntersects);

    3.  spatialFilter.setWhereClause("");

    4.  spatialFilter.setSearchOrder(EsriSearchOrder.esriSearchOrderSpatial);

    5.  spatialFilter.setSpatialRelDescription("");

    6.  spatialFilter.setGeometryFieldName("");

    7.  spatialFilter.setFilterGeometry(env);

       com.esri.arcgisws.MapServerPort的queryFeatureData()方法只能对某一个图层进行查询,所以,如果要查询所有的图层,需要对所有图层做一次循环。

    清单8. 空间查询

    1.  AGSMapFunctionality mapFunc = (AGSMapFunctionality)res.getFunctionality("map");

    2.  int layerCount = mapFunc.getLayerDescriptions().length;

    3.   MapServerPort svrPort = res.getMapServer();

    4.  try{

    5.           for(int i=0;i<layerCount;i++){

    6.       RecordSet rs = svrPort.queryFeatureData(“”,i, spatialFilter);

    7.     }

    8.  }catch(Exception e){

    9.  }

       第8行代码对每一个图层都做了一次空间查询,将查询结果保存在com.esri.arcgisws.RecordSet中。查询结果中包含了图层要素的所有信息,包括属性信息和空间信息,可以根据需要进行提取。这个例子中需要对查询结果做高亮显示,所以接下来我们关心的焦点就是获取查询结果的空间信息。

    清单9. 高亮显示查询结果

    1.  Record[] records = rs.getRecords();

    2.  for(int j=0;j<records.length;j++){

    3.           Record item = records[j];

    4.           int n = item.getValues().length;

    5.           for(int k=0;k<n;k++){

    6.               Object obj = item.getValues()[k];

    7.               if(obj instanceof com.esri.arcgisws.Geometry){

    8.                      WebGeometry geom = AGSUtil.fromAGSGeometry((com.esri.arcgisws.Geometry)obj);

    9.                      query.addDisplayGeometry(geom);

    10.             }

    11.         }

    12. }

       com.esri.arcgisws.Record对应的是某个图层的一条记录,它的getValues()方法获取该记录属性表中的所有信息(包括shape字段)。第6行开始我们读取每一个字段的值,判断该字段是否记录了shape信息,如果是,就将shape信息转成WebGeometry对象,然后用WebQuery进行高亮显示。

      下面两幅是查询然后高亮显示的效果图。

     

    原文链接:http://www.gissky.net/Article/1316.htm

     

  • 相关阅读:
    python_控制台输出带颜色的文字方法
    Django 知识总结(一)
    C# 实现俄罗斯方块
    一起学SpringMVC之Request方式
    一起学SpringMVC之RequestMapping详解
    一起学SpringMVC之Json
    一起学SpringMVC之注解
    一起学SpringMVC之入门篇
    一起学Android之Xml与Json解析
    一起学Android之AsyncTask
  • 原文地址:https://www.cnblogs.com/dwf07223/p/3024097.html
Copyright © 2020-2023  润新知