WMS服务 天地图 海量数据 性能优化 GeoServer 空间搜索 VUE

需求:

1秒内完成5w+条标注数据渲染到地图上,点击每个标注点显示该点的详情信息。

问题:

加载上万标注点到地图上性能特别差,天地图提供的组件MarkerClusterer,CloudMarkerCollection无法满足需求。

解决:

使用geoserver发布WMS地图服务+空间搜索获取标注点的基础信息

流程:

1、构造基础数据的shapfile文件

2、将shpfile文件通过geoserver发布成WMS服务

3、编写GeoServer的SLD文件 给发布的图层添加自定义图标

4、将WMS服务叠加到天地图地图上

5、监听用户图层点击事件,构造请求参数调用geosever获取基础信息。

结果:

注:图标的大小根据实际情况在SLD文件中设置

实现:

一、构造基础数据的shapfile文件+将shpfile文件通过geoserver发布成WMS服务

1)geosever核心依赖

        <repository>
                <id>osgeo</id>
                <name>OSGeo Release Repository</name>
                <url>https://repo.osgeo.org/repository/release/</url>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
                <releases>
                    <enabled>true</enabled>
                </releases>
            </repository>
        <repository>
                <id>osgeo-snapshot</id>
                <name>OSGeo Snapshot Repository</name>
                <url>https://repo.osgeo.org/repository/snapshot/</url>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
                <releases>
                    <enabled>false</enabled>
                </releases>
         </repository>


        <properties> 
           <geotools.version>25.1</geotools.version>
        </properties>
        <dependency>
            <groupId>it.geosolutions</groupId>
            <artifactId>geoserver-manager</artifactId>
            <version>1.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-process</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geotiff</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geojson</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-epsg-hsql</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-process-raster</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-process-feature</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${geotools.version}</version>
        </dependency>

2)发布shapfile到geoserver核心代码

public void autoPublishLayer() {
        //图层名称
        String layerName = "layer-" + layer.getId();
            try {
                //图层数据列表,包含经纬度坐标和基础信息
                List<LayerData> layerDatas = findLayerData(layer);
                GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
                SimpleFeatureType TYPE = DataUtilities.createType(layerName,
                      "the_geom:Point:srid=4326,name:String,address:String,id:String,layerId:String");
                List<SimpleFeature> features = new ArrayList<>();
                for (LayerData layerData : layerDatas) {
                    double longitude = layerData.getLon();
                    double latitude = layerData.getLat();
                    Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
                //设置图层基础信息   
                    features.add(SimpleFeatureBuilder.build(TYPE, new Object[]{point, layerData.getName(), layerData.getAddress(),
                            layerData.getId(), layerData.getLayerId()}, layerData.getId()));
                }
                SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
                //构造文件路径
                String path = SysFileUtil.getBaseDir(Global.getConfig("apps.file.upload")) + File.separator + "xf-layer" + File.separator + layerName + File.separator;
                File filePath = new File(path);
                if (!filePath.exists()) {
                    filePath.mkdirs();
                }
                File shpFile = new File(path + layerName + ".shp");
                if (!shpFile.exists()) {
                    shpFile.createNewFile();
                }

                //生成shapFile
                writeToShapeFile(shpFile, collection, TYPE);

                File zipFile = new File(path + layerName + ".zip");
                if (!zipFile.exists()) {
                    zipFile.createNewFile();
                }

                //geoserver发布需要压缩成ZIP
                ZipFileUtil.compressFiles2Zip(filePath.listFiles((dir, name) -> !name.endsWith("zip")), zipFile.getAbsolutePath());
                log.info("图层{}shp文件已生成。", layerName);

                //发布压缩后的文件
                if (weatherWarningService.publishShp(zipFile, "sc119", layerName, "sc119:" + layer.getIcon())) {
                    log.info("图层{}服务已发布。", layerName);
                }
            } catch (Exception e) {
                log.error("图层{}发布失败!,错误信息:{}", layerName, e.getMessage());
            }
}


public  void writeToShapeFile(File shapeFile, SimpleFeatureCollection collection, SimpleFeatureType CITY) throws Exception {

        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

        Map<String, Serializable> params = new HashMap<>();

        ShapefileDataStore dataStore = setDataStoreParams(dataStoreFactory, params, shapeFile, CITY);
        dataStore.setCharset(StandardCharsets.UTF_8);

        // If you decide to use the TYPE type and create a Data Store with it,
        // You will need to uncomment this line to set the Coordinate Reference System
        // newDataStore.forceSchemaCRS(DefaultGeographicCRS.WGS84);

        Transaction transaction = new DefaultTransaction("create");

        String typeName = dataStore.getTypeNames()[0];
        SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);

        if (featureSource instanceof SimpleFeatureStore) {
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;

            featureStore.setTransaction(transaction);
            try {
                featureStore.addFeatures(collection);
                transaction.commit();
            } catch (Exception problem) {
                problem.printStackTrace();
                transaction.rollback();
            } finally {
                transaction.close();
            }
        }
}

3)发布shapfile到geoserver后可以登录到geoserver管理页面进行图层预览。

二、编写GeoServer的SLD文件 给发布的图层添加自定义图标

1) 给图层设置单个图标的SLD文件

图标存放路径为geoserver工作空间的指定工作区下,按实际路径修 xlink:href="images/szd.png"即可。

<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld"
xmlns:sld="http://www.opengis.net/sld"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
version="1.0.0">
<sld:UserLayer>
<sld:LayerFeatureConstraints>
<sld:FeatureTypeConstraint/>
</sld:LayerFeatureConstraints>
<sld:UserStyle>
<sld:Name>xfs</sld:Name>
<sld:Title>xfs</sld:Title>
<sld:Abstract/>
<sld:FeatureTypeStyle>
<sld:Name>default</sld:Name>
<sld:Title/>
<sld:Abstract/>
<sld:FeatureTypeName>Feature</sld:FeatureTypeName>
<sld:SemanticTypeIdentifier>generic:geometry</sld:SemanticTypeIdentifier>
<sld:SemanticTypeIdentifier>simple</sld:SemanticTypeIdentifier>
<sld:Rule>
<sld:Name>default</sld:Name>
<sld:Title/>
<sld:Abstract/>
<sld:PointSymbolizer>
<sld:Graphic>
<ExternalGraphic>
<OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="images/szd.png"/>
<Format>image/png</Format>
</ExternalGraphic>
<sld:Mark>
<sld:WellKnownName>circle</sld:WellKnownName>
<sld:Stroke/>
</sld:Mark>
<sld:Size>25.000000px</sld:Size>
<sld:Rotation>0.0</sld:Rotation>
</sld:Graphic>
</sld:PointSymbolizer>
<sld:TextSymbolizer/>
</sld:Rule>
</sld:FeatureTypeStyle>
</sld:UserStyle>
</sld:UserLayer>
</sld:StyledLayerDescriptor>

2) 给图层设置多个图标的SLD文件

原理:根据图层某个基础属性字段的值做为判断依据,设置图标路径。

<?xml version="1.0" encoding="ISO-8859-1"?>
<StyledLayerDescriptor version="1.0.0"
  xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
  xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
  xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <NamedLayer>
    <Name>hidden-danger</Name>
    <UserStyle>
      <Title>A red line style</Title>
      <FeatureTypeStyle>

        <Rule>
          <ogc:Filter>
              <ogc:PropertyIsEqualTo>
                <ogc:PropertyName>属性名称</ogc:PropertyName>
                <ogc:Literal>1</ogc:Literal>
              </ogc:PropertyIsEqualTo>
          </ogc:Filter>
          <PointSymbolizer>
                <Graphic>
                  <ExternalGraphic>
                    <OnlineResource xlink:type="simple" xlink:href="images/xfs.png" />
                    <Format>image/png</Format>
                  </ExternalGraphic>
                  <Size><ogc:Literal>16</ogc:Literal></Size>
                </Graphic>
          </PointSymbolizer>
        </Rule>
        
        <Rule>
          <ogc:Filter>
              <ogc:PropertyIsEqualTo>
                <ogc:PropertyName>属性名称</ogc:PropertyName>
                <ogc:Literal>3</ogc:Literal>
              </ogc:PropertyIsEqualTo>
          </ogc:Filter>
          <PointSymbolizer>
                <Graphic>
                  <ExternalGraphic>
                    <OnlineResource xlink:type="simple" xlink:href="images/szd.png" />
                    <Format>image/png</Format>
                  </ExternalGraphic>
                  <Size><ogc:Literal>16</ogc:Literal></Size>
                </Graphic>
          </PointSymbolizer>
        </Rule>


      </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>

三、使用vue将WMS服务叠加到天地图地图上

addWmsLayer(item) {
      if (item.wmsLayer) {
        item.wmsLayer.setOpacity(1)
        return
      }
      var config = {
        version: "1.1.1",	//请求服务的版本
        layers: item.layer,
        transparent: true,	//输出图像背景是否透明
        styles: "",			//每个请求图层的用","分隔的描述样式
        format: "image/png",	//输出图像的类型
        zIndex: 100
      };
      var wmsLayer = new T.TileLayer.WMS(item.url, config);
      item.wmsLayer = wmsLayer
      this.Map.addLayer(wmsLayer);
}

四、监听用户图层点击事件,调用geosever获取基础信息。

1)监听图层点击事件

this.Map.addEventListener("click", function (e) {
  //调用处理函数
  that.clickMmsLayer(e)
});

2)调用geoserver的GetFeatureInfo请求获取基础数据

核心思路:

构造geoserver获取基础数据需要的几个请求参数:经纬度坐标、图层地址和名称、bbox参数

bbox参数由于天地图API不支持,需要动态调整bbox的大小。

clickMmsLayer(e) {
      let arr = []
      var lat = e.lnglat.lat   //点击事件返回的经纬度坐标
      var lon = e.lnglat.lng
      var zoom = this.Map.getZoom();
      //bbox数据根据不同层级自动调整大小
      var step = 0.001
      if (zoom < 14) {
        step = (70 - 4 * zoom) * 0.01;
      }
    
      let item={
           url:"http://localhost:8080/geoserver/workspace/wms",
           item.layer:"test",
      }
       //构造访问geoserver的获取基础数据的GetFeatureInfo请求
       var url = item.url + "?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&FORMAT=application/json&TRANSPARENT=true" +
                "&QUERY_LAYERS=" + item.layer + "&LAYERS=" + item.layer +
                "&exceptions=application/json&SRS=EPSG:4326&INFO_FORMAT=application/json&STYLES=&x=50&y=50&WIDTH=101&HEIGHT=101&BBOX=" + (lon - step).toFixed(6) + "," + (lat - step).toFixed(6) + "," + (lon + step).toFixed(6) + "," + (lat + step).toFixed(6)
         
       axios.get(url).then((res) => {
            console.log(res)
  
          }).catch(e => {
            console.log(e)
          })
        }
      })
    },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值