zoukankan      html  css  js  c++  java
  • Web GIS离线解决方案

    1、背景

    在离线环境下(局域网中)的GIS系统中如何使用地图?这里的地图主要指的是地图底图,有了底图切片数据,我们就可以看到地图,在上面加上自己的业务数据图层,进行相关操作。

    要在离线环境下看到GIS地图,就要有底图切片数据,地图的底图切片数据在一定时间内是不会变化的,可以使用一些地图下载器下载地图切片,如这个地图下载器

    在CS系统中可以基于GMap.Net来做,参考《百度谷歌离线地图解决方案》。

    下面介绍下Web系统如何使用GIS切片数据,开发web GIS系统。

    2、使用GeoWebCache发布WMS服务

    Geowebcache是基于Java的Web开源项目,主要用于缓存各种WMS数据源的地图瓦片,它实现了多种服务接口,包括WMS-C,WMTS,TMS,KML。

    Geowebcache作为一个独立的开源项目,在最近被Geosever的几个版本所集成,主要是对发布的WMS图层建立缓存切片。

    服务发布步骤:

    1)官网下载 geowebcache-1.8.0-war.zip,直接解压得到geowebcache.war文件,将该文件直接拷贝至tomcat目录下的webapps下即可,启动tomcat会对war包进行解压。

    2)修改geowebcache的配置文件geowebcache-core-context.xml。该文件在Tomcat的webappsgeowebcacheWEB-INF下,修改如下:

    <bean id="gwcXmlConfig" class="org.geowebcache.config.XMLConfiguration">
    <constructor-arg ref="gwcAppCtx" />
    <!--<constructor-arg ref="gwcDefaultStorageFinder" />-->
        <constructor-arg value="D:\GisMap\" />
    <!-- By default GWC will look for geowebcache.xml in {GEOWEBCACHE_CACHE_DIR},
             if not found will look at GEOSEVER_DATA_DIR/gwc/
             alternatively you can specify an absolute or relative path to a directory
             by replacing the gwcDefaultStorageFinder constructor argument above by the directory
             path, like constructor-arg value="/etc/geowebcache"     
        -->
    <property name="template" value="/geowebcache.xml">
    <description>Set the location of the template configuration file to copy over to the
            cache directory if one doesn't already exist.
    </description>
    </property>
    </bean>

    修改gwcXmlConfig实例化时使用固定路径,该路径可以为任意新建路径文件夹。Geowebcache启动之后会检查此文件夹下是否存在gewebcache.xml文件,如果不存在则按模板新建立并读取使用,如果存在则直接读取使用。

    3)修改第2步中的gewebcache.xml文件:

    <layers>
        <arcgisLayer>
            <name>ARCGIS-Demo</name>
            <tilingScheme>D:\GisMap\Layer\conf.xml</tilingScheme>
            <tileCachePath>D:\GisMap\Layer\_alllayers</tileCachePath>
        </arcgisLayer>
    </layers>

    在layers节点里添加arcgisLayer节点(默认生成的gewebcache.xml的layers节点有许多其他冗余数据,可删除可保留)。Name节点表示待添加图层的名称(这里配置为ARCGIS-Demo),titlingscheme节点为conf.xml文件的路径,tileCachePath为瓦片数据的路径。

    4)瓦片地图的准备

    其中conf.xml为配置文件,conf.cdi为显示区域约束文件,_alllayers文件夹下则存放了切片数据,Status.gdb为切片状态情况记录(可直接删除)。

    通过瓦片下载器下载瓦片地图,然后生成的切片数据_alllayers文件夹:

    L01-L10表示地图缩放级数,按照ArcGIS切片目录组织,切片命名规则也和ArcGIS切片数据命名规则一致。(conf.xml、conf.cdi和_alllayers在同级目录)。

    5)启动tomcat,继而启动Geowebcache服务,浏览器访问 localhost:8080/geowebcache,如果一切正确的话可以看到下面的页面

    该页面简单说明了Geowebcache的一些情况。

    点击“A list of all the layers and automatic demos”连接可以看到下面:

    该页面显示了geowebcache.xml配置的图层信息。图中可以看到只配置了一个名字为ARCGIS-Demo的图层,使用的EPSG3857坐标系,发布的图片格式为png格式,点击png链接即可看到瓦片地图。

    这里地图显示的级别和坐标系配置都来自conf.xml文件。这里的前端js使用的是Openlayers。查看网页源码:

    <html xmlns="http://www.w3.org/1999/xhtml"><head>
    <meta http-equiv="imagetoolbar" content="no">
    <title>ARCGIS-Demo EPSG:3857_ARCGIS-Demo image/png</title>
    <style type="text/css">
    body { font-family: sans-serif; font-weight: bold; font-size: .8em; }
    body { border: 0px; margin: 0px; padding: 0px; }
    #map {  85%; height: 85%; border: 0px; padding: 0px; }
    </style>
    <script src="../openlayers/OpenLayers.js"></script>    
    <script type="text/javascript">               
    var map, demolayer;                               
      // sets the chosen modifiable parameter        
      function setParam(name, value){                
       str = "demolayer.mergeNewParams({" + name + ": '" + value + "'})" 
       // alert(str);                                   
       eval(str);                                    
      }                                              
    OpenLayers.DOTS_PER_INCH = 96.0;
    OpenLayers.Util.onImageLoadErrorColor = 'transparent';
    function init(){
    var mapOptions = { 
    resolutions: [156543.033928, 78271.5169639999, 39135.7584820001, 19567.8792409999, 9783.93962049996, 4891.96981024998, 2445.98490512499, 1222.99245256249, 611.49622628138, 305.748113140558, 152.874056570411, 76.4370282850732, 38.2185141425366, 19.1092570712683, 9.55462853563415, 4.77731426794937, 2.38865713397468, 1.19432856685505, 0.597164283559817, 0.298582141647617],
    projection: new OpenLayers.Projection('EPSG:3857'),
    maxExtent: new OpenLayers.Bounds(-20037508.342787,-20037508.342780996,20037508.342780996,20037508.342787),
    units: "meters",
    controls: []
    };
    map = new OpenLayers.Map('map', mapOptions );
    map.addControl(new OpenLayers.Control.PanZoomBar({
            position: new OpenLayers.Pixel(2, 15)
    }));
    map.addControl(new OpenLayers.Control.Navigation());
    map.addControl(new OpenLayers.Control.Scale($('scale')));
    map.addControl(new OpenLayers.Control.MousePosition({element: $('location')}));
    demolayer = new OpenLayers.Layer.WMS(
    "ARCGIS-Demo","../service/wms",
    {layers: 'ARCGIS-Demo', format: 'image/png' },
    { tileSize: new OpenLayers.Size(256,256),
     tileOrigin: new OpenLayers.LonLat(-2.0037508342787E7, 2.0037508342787E7)});
    map.addLayer(demolayer);
    map.zoomToExtent(new OpenLayers.Bounds(-20037497.2108,-19929239.113399997,20037497.2108,18379686.9965));
    // The following is just for GetFeatureInfo, which is not cached. Most people do not need this 
    map.events.register('click', map, function (e) {
      document.getElementById('nodelist').innerHTML = "Loading... please wait...";
      var params = {
        REQUEST: "GetFeatureInfo",
        EXCEPTIONS: "application/vnd.ogc.se_xml",
        BBOX: map.getExtent().toBBOX(),
        X: e.xy.x,
        Y: e.xy.y,
        INFO_FORMAT: 'text/html',
        QUERY_LAYERS: map.layers[0].params.LAYERS,
        FEATURE_COUNT: 50,
        Layers: 'ARCGIS-Demo',
        Styles: '',
        Srs: 'EPSG:3857',
        WIDTH: map.size.w,
        HEIGHT: map.size.h,
        format: "image/png" };
      OpenLayers.loadURL("../service/wms", params, this, setHTML, setHTML);
      OpenLayers.Event.stop(e);
      });
    }
    function setHTML(response){
        document.getElementById('nodelist').innerHTML = response.responseText;
    };
    </script>
    </head>
    <body onload="init()">
    <div id="params"></div>
    <div id="map"></div>
    <div id="nodelist"></div>
    </body>
    </html>
    View Code

    个人比较喜欢leaflet这个GIS javascript库,使用leaflet加载GeoWebCache发布的这个服务:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Leaflet - Offline Demo</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
        <script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
    </head>
    <body>
        <div id="map" style="height:100vh;" ></div>
        <script type="text/javascript">
            
        var mapCenter = new L.LatLng(32.1280, 118.7742); //南京
            
        var map = new L.Map('map', {
            center : mapCenter,
            zoom : 4
        });
    
        var wmsLayer = L.tileLayer.wms("http://localhost:8080/geowebcache/service/wms", {
            layers: 'ARCGIS-Demo',
            format: 'image/png'
        });
        wmsLayer.addTo(map);
    
        var marker = new L.Marker(mapCenter);
        map.addLayer(marker);
        marker.bindPopup("<p>Hello! ;}</p>").openPopup();
            
        </script>
    </body>
    </html>

    3、使用自定义的Http服务

    GeowebCache本质上就是个Http服务,通过请求参数获取配置文件中的路径中的切片数据,返回给请求方。

    我们可以自己写个独立的Http服务,从数据库中读取切片数据返回给请求方。

    切片请求地址类似:http://localhost:8899/1818940751/{z}/{x}/{y}

    其中“1818940751”是下载器下载的地图类型,z/x/y分别是zoom和地图切片行列号。

    前端js使用leaflet加载:

    var amapNormalUrl = 'http://localhost:8899/788865972/{z}/{x}/{y}';
    var amapNormalLayer = new L.TileLayer(amapNormalUrl, {
        minZoom : 1,
        maxZoom : 18,
        attribution : '高德普通地图'
    });
    
    var mapCenter = new L.LatLng(32.1280, 118.7742); //南京
    var map = new L.Map('map', {
            center : mapCenter,
            zoom : 9,
            minZoom: 1,
            maxZoom: 18,
            layers : [ amapNormalLayer ]
    });

    前端js可以自定义投影Projection算法,而国内google地图、高德地图和腾讯地图都是标准的墨卡托投影,可以直接用leaflet加载。

    配合一些画图插件,再配合一些后台POI检索服务,如:

    《使用Lucene索引和检索POI数据》

    《使用Solr进行空间搜索》

    则能做出如下效果:

    总结:介绍了如何使用下载的离线切片数据在局域网环境下发布Web GIS地图服务,前端配合使用一些js插件,实现web下空间数据的检索。

    在Github上开源了一些代码,包含自定义的Http地图服务,和一个简单的页面WebGISDemo。

    地址:

    https://github.com/luxiaoxun/MapDownloader

    https://github.com/luxiaoxun/Code4Java

    附件:

    <?xml version="1.0" encoding="utf-8" ?>
    <EnvelopeN xsi:type='typens:EnvelopeN' 
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
        xmlns:xs='http://www.w3.org/2001/XMLSchema' 
        xmlns:typens='http://www.esri.com/schemas/ArcGIS/10.1'>
        
        <XMin>-20037497.2108</XMin>
        <YMin>-19929239.113399997</YMin>
        <XMax>20037497.2108</XMax>
        <YMax>18379686.9965</YMax>
    
    </EnvelopeN>
    conf.cdi
    <?xml version="1.0" encoding="utf-8"?>
    <CacheInfo xsi:type="typens:CacheInfo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:typens="http://www.esri.com/schemas/ArcGIS/10.1">
        <TileCacheInfo xsi:type="typens:TileCacheInfo">
            <SpatialReference xsi:type="typens:ProjectedCoordinateSystem">
                <WKT>PROJCS["WGS_1984_Web_Mercator_Auxiliary_Sphere",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Mercator_Auxiliary_Sphere"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",0.0],PARAMETER["Standard_Parallel_1",0.0],PARAMETER["Auxiliary_Sphere_Type",0.0],UNIT["Meter",1.0],AUTHORITY["EPSG",3857]]</WKT>
                <XOrigin>-20037700</XOrigin>
                <YOrigin>-30241100</YOrigin>
                <XYScale>148923141.92838538</XYScale>
                <ZOrigin>-100000</ZOrigin>
                <ZScale>10000</ZScale>
                <MOrigin>-100000</MOrigin>
                <MScale>10000</MScale>
                <XYTolerance>0.001</XYTolerance>
                <ZTolerance>0.001</ZTolerance>
                <MTolerance>0.001</MTolerance>
                <HighPrecision>true</HighPrecision>
                <WKID>3857</WKID>
            </SpatialReference>
            
            <TileOrigin xsi:type="typens:PointN">
                <X>-20037508.342787001</X>
                <Y>20037508.342787001</Y>
            </TileOrigin>
        
            <TileCols>256</TileCols>
            <TileRows>256</TileRows>
            <DPI>96</DPI>
            <LODInfos xsi:type="typens:ArrayOfLODInfo">
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>0</LevelID>
                    <Scale>591657527.591555</Scale>
                    <Resolution>156543.03392799999</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>1</LevelID>
                    <Scale>295828763.79577702</Scale>
                    <Resolution>78271.516963999893</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>2</LevelID>
                    <Scale>147914381.89788899</Scale>
                    <Resolution>39135.758482000099</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>3</LevelID>
                    <Scale>73957190.948944002</Scale>
                    <Resolution>19567.879240999901</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>4</LevelID>
                    <Scale>36978595.474472001</Scale>
                    <Resolution>9783.9396204999593</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>5</LevelID>
                    <Scale>18489297.737236001</Scale>
                    <Resolution>4891.9698102499797</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>6</LevelID>
                    <Scale>9244648.8686180003</Scale>
                    <Resolution>2445.9849051249898</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>7</LevelID>
                    <Scale>4622324.4343090001</Scale>
                    <Resolution>1222.9924525624899</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>8</LevelID>
                    <Scale>2311162.2171550002</Scale>
                    <Resolution>611.49622628138002</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>9</LevelID>
                    <Scale>1155581.108577</Scale>
                    <Resolution>305.74811314055802</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>10</LevelID>
                    <Scale>577790.55428899999</Scale>
                    <Resolution>152.874056570411</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>11</LevelID>
                    <Scale>288895.27714399999</Scale>
                    <Resolution>76.437028285073197</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>12</LevelID>
                    <Scale>144447.638572</Scale>
                    <Resolution>38.218514142536598</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>13</LevelID>
                    <Scale>72223.819285999998</Scale>
                    <Resolution>19.109257071268299</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>14</LevelID>
                    <Scale>36111.909642999999</Scale>
                    <Resolution>9.5546285356341496</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>15</LevelID>
                    <Scale>18055.954822</Scale>
                    <Resolution>4.7773142679493699</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>16</LevelID>
                    <Scale>9027.9774109999998</Scale>
                    <Resolution>2.38865713397468</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>17</LevelID>
                    <Scale>4513.9887049999998</Scale>
                    <Resolution>1.1943285668550501</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>18</LevelID>
                    <Scale>2256.994353</Scale>
                    <Resolution>0.59716428355981699</Resolution>
                </LODInfo>
                <LODInfo xsi:type="typens:LODInfo">
                    <LevelID>19</LevelID>
                    <Scale>1128.4971760000001</Scale>
                    <Resolution>0.29858214164761698</Resolution>
                </LODInfo>
            </LODInfos>
        </TileCacheInfo>
        <TileImageInfo xsi:type="typens:TileImageInfo">
            <CacheTileFormat>PNG</CacheTileFormat>
            <CompressionQuality>0</CompressionQuality>
            <Antialiasing>false</Antialiasing>
        </TileImageInfo>
        <CacheStorageInfo xsi:type="typens:CacheStorageInfo">
            <StorageFormat>esriMapCacheStorageModeExploded</StorageFormat>
            <PacketSize>0</PacketSize>
        </CacheStorageInfo>
    </CacheInfo>
    conf.xml

    参考:

    http://leafletjs.com/

    http://leafletjs.com/examples/quick-start/

    http://www.cnblogs.com/luxiaoxun/p/4454880.html

    http://www.cnblogs.com/luxiaoxun/p/5020247.html

  • 相关阅读:
    图解:在资深架构师眼中的架构应该是怎样的?
    面试必看|面试官之间的“潜规则”
    职业规划:专属程序员的巡礼之年
    互联网企业如何应对网站架构演化带来的“蝴蝶效应”
    阿里首席架构师,是如何选择并落地架构方案的
    你真的了解微服务架构吗?听听八年阿里架构师怎样讲述Dubbo和Spring Cloud微服务架构
    大型分布式电商系统架构演进史?
    大厂面试官:Java工程师的“十项全能”
    打包签名时出现Conversion to Dalvik format failed with error 1
    Android项目混淆打包
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/5022333.html
Copyright © 2011-2022 走看看