GeoServer 学习手册
更新时间:2023-11-05 01:03:01 阅读量: 综合文库 文档下载
- geoserver推荐度:
- 相关推荐
GeoServer Eclipse 搭建
矢量数据库搭建
安装数据库
sudo apt-get install postgresql postgresql-contrib postgis postgresql-9.1-postgis 安装完毕,我们需要更改postgres用户的密码,否则我们就没法使用这个数据库服务器。以postgres这个系统用户的身份运行psql命令,在终端中输入如下: sudo su postgres -c psql template1
这时候会出现新的提示符,输入下面两个命令,用新密码替换 <***password***>: ALTER USER postgres WITH PASSWORD ' <***password***> ';
b)创建用户及数据库
postgres# CREATE USER zuefir WITH PASSWORD 'xxxx'; postgres# CREATE DATABASE osm;
postgres# GRANT ALL PRIVILEGES ON DATABASE osm to zuefir;
c)为数据库添加空间扩展
CREATE EXTENSION postgis; -- Enable Topology
CREATE EXTENSION postgis_topology; -- fuzzy matching needed for Tiger CREATE EXTENSION fuzzystrmatch; -- 地理编码
CREATE EXTENSION postgis_tiger_geocoder; -- 用于存储属性tags,key-value CREATE EXTENSION hstore;
修改PostgreSQL数据库的默认用户postgres的密码
2.PostgreSQL登录(使用psql客户端登录)
root@server2-virtual-machine:~# sudo -u postgres psql //其中,sudo -u postgres 是使用postgres 用户登录的意思
//PostgreSQL数据默认会创建一个postgres的数据库用户作为数据库的管理员,密码是随机的,所以这里 //设定为'postgres'
3.修改PostgreSQL登录密码:
postgres=# ALTER USER postgres WITH PASSWORD 'postgres'; //postgres=#为PostgreSQL下的命令提示符 4.退出PostgreSQL psql客户端 postgres=# \\q [代码说明]
‘#’和’#'之前的字符是系统提示符,’postgres=#’是psql客户端的提示符,红色字符为输入命令(本文其它部分亦如此); [功能说明]
PostgreSQL数据默认会创建一个postgres的数据库用户作为数据库的管理员,密码是随机的,我人需要修改为指定的密码,这里设定为’postgres’
修改linux系统的postgres用户的密码
1.删除PostgreSQL用户密码
root@server2-virtual-machine:~# sudo passwd -d postgres passwd: password expiry information changed. //passwd -d 是清空指定用户密码的意思 2.设置PostgreSQL用户密码
PostgreSQL数据默认会创建一个linux用户postgres,通过上面的代码修改密码为'postgres’(这取决于
第二步中的密码,只要与其相同即可)。 现在,我们就可以在数据库服务器上用 postgres帐号通过psql或者pgAdmin等等客户端操作数据库了。
root@server2-virtual-machine:~#sudo -u postgres passwd 输入新的 UNIX 密码: 重新输入新的 UNIX 密码: passwd:已成功更新密码
修改PostgresSQL数据库配置实现远程访问
root@server2-virtual-machine:~# vi /etc/postgresql/9.1/main/postgresql.conf 1.监听任何地址访问,修改连接权限
#listen_addresses = ‘localhost’改为 listen_addresses = ‘*’ 2.启用密码验证
#password_encryption = on改为password_encryption = on 3.可访问的用户ip段
root@server2-virtual-machine:~# vi /etc/postgresql/9.1/main/pg_hba.conf,并在文档末尾加上以下内容
# to allow your client visiting postgresql server host all all 0.0.0.0 0.0.0.0 md5 4.重启PostgreSQL数据库
root@server2-virtual-machine:~# /etc/init.d/postgresql restart
管理PostgreSQL用户和数据库
1.登录postgre SQL数据库
root@server2-virtual-machine:~# psql -U postgres -h 127.0.0.1 2.创建新用户zhaofeng,但不给建数据库的权限
postgres=# create user “zhaofeng” with password ‘123456’ nocreatedb; //注意用户名要用双引号,以区分大小写,密码不用 3.建立数据库,并指定所有者
postgres=# create database “testdb” with owner=”zhaofeng”; 4.在外部命令行的管理命令
root@server2-virtual-machine:~# -u postgres createuser -D -P test1
//-D该用户没有创建数据库的权利,-P提示输入密码,选择管理类型y/n root@server2-virtual-machine:~# -u postgres createdb -O test1 db1 //-O设定所有者为test1
安装postgresql数据库pgAdmin3客户端管理程序
root@server2-virtual-machine:~# apt-get install pgadmin3
添加PostGIS功能到数据库,执行如下命令
psql -U postgres -d osm -f “你PostgreSQL安装路径/share/contrib/postgis-2.1/postgis.sql”
添加EPSG: 900913支持
psql -U postgres -d osm -f “本地的文件路径/900913.sql”
900913.sql没有可以在osm2pgsql的github中下载到
添加OSM数据到数据库
下载github上的osm2pgsql中的default.style文件并拷贝到本地osm2pgsql的x64目录中,把下载的chain.osm.bz2文件解压得到的chain.osm文件也拷贝到osm2pgsql的x64目录中。
新打开一个命令行进入osm2pgsql的x64目录中,执行如下命令:
osm2pgsql -U postgres -d osm -s -S ./default.style ./china.osm
一般情况下会报一个”Error reading style file line 151 (fields=4) flag ‘phstore’ is invalid in non-hstore mode“的错误,
这说明确实hstore表示所以我们需要添加这个标识。点击pgAdmin III 工具栏中的SQL标识
在弹出的SQL编辑器中输入:create extension hstore;命令点击顶部工具栏中的
这时还需要为命令添加一个“–hstore “选项 完整的执行命令是:“osm2pgsql -U postgres -d osm –hstore -s -S ./default.style ./china.osm “这样就正确了。
后面导入可以不添加 S ./default.style
GeoServer导入eclipse
下载GeoServer 源码 http://geoserver.org/
cd 进入src目录
mvn clean install
成功之后 生成导入eclipse的文件
mvn eclipse:eclipse
GeoServer二次开发
GeoServer相关概念的介绍
Geoserver是一个功能齐全,遵循OGC开放标准的开源WFS-T和WMS服务器。利用Geoserver可以把数据作为maps/images来发布(利用WMS来实现)也可以直接发布实际的数据(利用WFS来实现),同时也提供了修改,删除和新增的功能(利用WFS-T)。
GeoServer, 顾名思义,是一个Server. 它是开源的,允许用户查看和编辑地理数据。这是地理信息系统(GIS) 领域。GeoServer 是符合OGC 规范的一个全功能的WFS-T 和WMS server。
GeoServer能够发布的数据类型:
l 地图或影象——应用WMS,
l 实时数据——应用WFS,
l 用户更新、删除和编辑的数据——应用WFS-T。
相关概念的:
WMS: Web Map Service(Web地图服务)
l 利用具有地理空间位置信息的数据制作地图。其中将地图定义为地理数据可视的表现。这个规范定义了三个操作:
n GetCapabitities 返回服务级元数据,它是对服务信息内容和要求参数的一种描述; n GetMap 返回一个地图影像,其地理空间参考和大小参数是明确定义了的; n GetFeatureInfo(可选)返回显示在地图上的某些特殊要素的信息
第三步 执行操作(见org.geoserver.ows.Dispatcher.dispatch(Request, Service))
这一步主要的操作就是创建执行对象org.geoserver.platform.Operation,这个对象采用了Java的反射原理来实现函数调用,所以需要创建函数参数数组。前面提到过OWS参数的格式有KVP和XML两种,因此对参数的处理也分为两种,具体到类就是org.geoserver.ows.KvpRequestReader和org.geoserver.ows.XmlRequestReader。这两个类将参数字符串转换成相应的对象,在这点上与前面的Parser类似,不同的是这里的转换对应的是一个服务调用,而不是具体一个参数。例如org.geoserver.wms.kvp.GetMapKvpRequestReader就负责将GetMap的参数转换成org.vfny.geoserver.wms.requests.GetMapRequest对象。
这一步的扩展点就是以上两个Reader,来看WMS中GetMap Reader的定义 class=\ class=\ 与前面的扩展一样,我们只需要把我们设计的相关Reader注册到系统中,程序就会自己找到它。下面说说匹配Reader的算法。 第二步提到了一个service对象,除了知道它是一个Object之外,我们并没有过多说明。实际上,Operation类会持有这个对象,并且从里面查找与注册的操作同名的公共成员函数,这个函数将通过反射来调用。显然,我们提供给这个函数的参数必须符合它声明的参数类型。所以,匹配KVP Reader的算法就是匹配参数类型的过程。DefaultWebMapService的getMap函数的签名如下: public GetMapResponse getMap(GetMapRequest request) 程序会遍历所有注册的GetMapKvpRequestReader,将注册函数的参数类型与org.geoserver.ows.KvpRequestReader.getRequestBean()的返回值比较,如果两者可以交换(Assignable)则匹配成功。 XML Reader的匹配与KVP Reader完全不同,这一点很奇怪,它是根据注册的操作名称,服务ID和服务版本来匹配的。 至于执行操作,实在没什么需要特殊说明的,就是调用方法而已,唯一值得注意的是它的返回值,因为我们要把它写到返回流(Response Stream)中。而这是下一步的事情了。 第四步 返回结果(见org.geoserver.ows.Dispatcher.response(Object, Request, Operation)) 现在需要把结果返回给客户端了,这个步骤叫做Response。这一步的扩展点是一个叫org.geoserver.ows.Response的类,程序会遍历所有注册的Response类(与前面的那些匹配完全一样),比较返回值的类型与org.geoserver.ows.Response.getBinding()的值,如果两者可以交换(Assignable)则匹配成功。匹配成功后就调用org.geoserver.ows.Response.write(Object, OutputStream, Operation)函数回写结果。下面是 WMS GetMap的Response配置信息 class=\ 这里用到了一个叫ResponseAdapter的类主要是为了适配接口。 到此OWS的处理就介绍完了,下面来看看GeoServer的资源API。 二 资源对象模型 这是我起的名称,实际上是一套接口。在包“main”的命名空间org.geoserver.catalog下面有许多接口描述了GeoServer中许多基本概念,搞清楚这些是学习GeoServer的关键之一。 特别需要说明一下,GeoServer所有的资源都派生自接口org.geoserver.catalog.Info,它唯一的方法是org.geoserver.catalog.Info.getId()。这说明,GeoServer里面所有的资源都有一个全局唯一的ID。我们会在后面的文章中详细介绍,包括它的产生和保存。 1 Catalog 这里有一段摘录自main配置文件的脚本 里面定义了一个叫“catalog”的变量,下面是一个引用它的例子 这就是我们要说的Catalog。查看Catalog接口的代码,会看到它定义了许多函数(代码太长就不贴出了),这些函数基本涵盖了“增删改查”所有的方法,而每一套“增删改查”都对应了我们将要介绍一个概念,例如这一段: void add(LayerInfo layer); void remove(LayerInfo layer); void save(LayerInfo layer); LayerInfo getLayer(String id); 后面还有很多getLayer方法就不赘述了。 我们可以这样定义:Catalog是一个抽象概念,它提供了一套访问GeoServer资源的方法,通过这些方法程序可以对GeoServer的资源进行“增删改查”的操作,而无需知道资源的具体保存形式。当然,目前唯一的实现就是CatalogImpl,但是我们完全可以用我们自己的Catalog来替换它,只需要修改一下上面的配置信息就可以了。 需要说明的是,很多时候我们都是通过GeoServer这个对象来获得Catalog的,下面我们就来说说GeoServer。 2 GeoServer 它的完整名称是org.geoserver.config.GeoServer,根据注释的解释,它是用来访问GeoServer服务器的配置信息的接口,而它的名称也反映出这个特点。我们可以通过它来获得与具体服务无关的数据,例如服务的字符集,服务的联系人,发布了哪些OWS服务等。当然还有服务的资源接口Catalog。在自定义的配置文件里,可以用“geoServer”来引用它。 3 Layer Layer是空间数据源与表现样式的组合,WMS GetMap中我们指定的参数LAYERS指的就是它。org.geoserver.catalog.LayerInfo是它的代码形式。通过这个接口,我们可以访问与Layer相关联的资源,主要有空间数据源(Resource),样式(Style),图例(Legend)等。Layer可以相互嵌套形成LayerGroup,LayerGroup在行为上与Layer完全一样,这是一个组合模式的应用。 4 Resource 这里的Resource并非泛指的资源,而是与空间相关联的资源,所以org.geoserver.catalog.ResourceInfo中有访问空间参考(SRS或CRS)的方法。另外,通过这个接口我们可以访问资源的Store(又是一个概念,我们姑且就使用原文),也就是资源的存储器。GeoServer中有两个概念是从Resource派生来的,Coverage和FeatureType,并且它们有各自的Store。 5 Store Store表示Resource的存储。org.geoserver.catalog.StoreInfo是它的代码形式,最重要的函数是org.geoserver.catalog.StoreInfo.getConnectionParameters(),返回连接参数,参数的具体含义由具体的存储介质来决定。Coverage和FeatureType都有各自的Store,org.geoserver.catalog.CoverageStoreInfo和org.geoserver.catalog.DataStoreInfo。 6 Coverage Coverage一直是让我迷惑的概念,我把wiki的解释原文抄录在这里:In geographic information systems, a coverage is a mapping of one aspect of data in space.大意是:在GIS领域,一个Coverage就是一附地图,它反应了空间数据的一个方面。(很笼统是吧,如果你有准确的解释,希望你能发给我,我将不胜感激)。org.geoserver.catalog.CoverageInfo是这个概念的代码形式。 7 FeatureType 要解释FeatureType就必须先解释Feature。Feature,即要素,是一个具有空间意义的实体,并且拥有附加的属性。例如:某个城市,它的位置是东经116.46度 北纬 39.92 度,它的名字是“北京”,它的常住人口是1972万。我们就可以用一个要素来表示它,这个要 素是一个点,点的坐标是[116.46 39.92],它的属性表示为 属性名称 属性值 Name 北京 Popu 1972 如果我们有许多城市数据,都具有相似的特征,我们就可以定义一个叫“CITIES”的FeatureType,它的几何类型是Point(点),它的属性Scehma是 属性名称 值类型 Name 字符串 Popu 数值 可以把FeatureType与Feature的关系想象为类与类实例的关系。也可以把它们的关系想象为数据表与数据记录的关系。后者其实更实用,因为许多时候Feature数据就是以表的形式组织和访问的。 org.geoserver.catalog.FeatureTypeInfo是它的代码形式。它最重要的方法就是org.geoserver.catalog.FeatureTypeInfo.getFeatureSource(ProgressListener, Hints),这个方法会返回数据源,我们可以用这个数据源来查询Feature。 8 Style Style,可以翻译成渲染样式,提供了一套方法用来描述如何渲染Feature。WMS GetMap中我们指定的参数STYLES指的就是它。OGC的标准SLD提供了一种语言用来描述Style。GeoServer采用了这个语言,其他很多GIS平台也支持这个语言。推荐我的一篇文章《OGC之路(2) 之 Style之谜》说得比较详细,还附有代码。 org.geoserver.catalog.StyleInfo是它的代码形式。它最重要的方法就是org.geoserver.catalog.StyleInfo.getStyle(),返回样式对象org.geotools.styling.Style。我们可以通过它来获得SLD里面定义的元素。 算法小结: 经纬度坐标转换为屏幕坐标 地理坐标定义规则:X轴(代表经度)向右递增,Y轴(纬度)向上递增,就好比小学学过的平面坐标。向左、向下的规则。屏幕坐标定义规则:X轴向右递增,Y轴向下递增。 可以看出,地理坐标和屏幕坐标的区别仅仅只是在于Y轴递增方向是相反的(这就是不同)。 这里强调一点的就是为了保证精度,地理坐标的度*3600换算成秒,所有的取值用double来计算,最后的结果再转换成int。 1 已知道屏幕的高(y)和宽(h),地理坐标区域的范围(maxLon,minLon,maxLat,minLat),这里我们知道了这些已知的参数。 2 我们可以算出每像素所代表的经度和纬度(有人称这个为比例因子)。 公式:scaleX = ((maxLon-minLon)*3600)/h ----------X轴上每像素代表的经度秒数; 公式:scaleY = ((maxLat-minLat)*3600)/y ----------Y轴上每像素代表的纬度秒数; 这两个比例因子就是两个坐标系之间的关系。 3 很简单的一步了,那就是算出该地理坐标区域中的任何一点(lon,lat)在屏幕上的坐标了。 公式:screenX = lon*3600/scaleX;---------屏幕坐标X轴坐标 公式:screenY = lat*3600/scaleY; ---------屏幕坐标Y轴坐标 还有最后一步,那就是我们要把该地理区域占满占个屏幕该怎么办呢? 4 接着我们需要该地理区域占满占个屏幕该怎么办呢 公式:minX = minLon*3600/scaleX;区域左边置最左端 公式:minY = minLat*3600/scaleY; 区域上面置最上端 5 当地地理范围区域占满整个屏幕时,我们需要用到第三步计算出来的 screenX和screenY两个参数,该区域中的任何一点的公式如下: 公式:X = screenX - minX = (lon - minLon)*3600/scaleX; 公式:Y = screenMaxLat - screenLat = (maxLat - lat)*3600/scaleY; 6 总结: 经纬度转屏幕坐标的最终公式如下: 公式:X = (lon - minLon)*3600/scaleX; 公式:Y = (maxLat - lat)*3600/scaleY; 接着我们由上面的公式可以推出屏幕坐标转经纬度坐标公式如下: 公式:lon = X * scaleX/3600 + minLon; 公式:lat = maxLat - y* scaleY/3600; } } OpenLayers中每一个类的构造函数都是以initialize命名的。 再看看其成员函数: destroy函数,相当于析构函数; onMapResize,removeMap 虚函数,提供给子类继承; //移动函数 moveTo:function(bounds, zoomChanged, dragging) { var display = this.visibility; if (!this.isBaseLayer) { display = display && this.inRange; } this.display(display); } 下面一组函数是Baselayer Functions函数,就是layer是Baselayer 的话,所用的函数。 比如,initResolutions、getResolution、getExtent等。 通过这两次的分析,可以发现,Map和Layers的关系:它们是相互引用的。实际上是这样,OpenLayers的Map类主要包含了对每个图层的引用,对每个控件的引用,对事件的引用,对装载容器的引用(其实就是那些map上层的div)以及对pop的引用,而其自身又包含有大量的方法和属性。图层主要包含了对map的引用,对自身div容器的引用以及事件的引用,而图层自身又包含了大量的属性和方法。map引用了layer,而layer又引用了map,这里就直接形成了循环引用关系。 这样的组成和关联关系,每动一下,就会涉及到大量的对象,影响了性能 OpenLayers项目分析——(九)控件 (九)OpenLayers中的控件 OpenLayers中的控件,是通过加载到地图上而起作用的,也算地图表现的一部分。同时,控件需要对地图发生作用,所以每个控件也持有对地图(map对象)的引用。 前面说过,控件是于事件相关联的。具体的说就是控件的实现是依赖于事件绑定的,每个OpenLayers.Control及其子类的实例都会持有一个handler的引用的。 那么,怎么来创建并添加一个控件呢?用下面的语句: //实例化一个控件 var control1 = new OpenLayers.Control({div: myDiv}); //向地图中添加控件 var map = new OpenLayers.Map('map', { controls: [] }); map.addControl(control1 ); 对一些常用的OpenLayers控件,项目本身都封装好了,用下面的语句添加: map.addControl(new OpenLayers.Control.PanZoomBar()); map.addControl(new OpenLayers.Control.MouseToolbar()); map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false})); map.addControl(new OpenLayers.Control.Permalink()); map.addControl(new OpenLayers.Control.Permalink('permalink')); map.addControl(new OpenLayers.Control.MousePosition()); map.addControl(new OpenLayers.Control.OverviewMap()); map.addControl(new OpenLayers.Control.KeyboardDefaults()); 先看看OpenLayers. Control基类的实现过程,再选择几个典型的子类分析一下。 OpenLayers. Control: //设置控件的map属性,即控件所引用的地图 setMap: function(map) { this.map = map; if (this.handler) { this.handler.setMap(map); } } //drew方法,当控件准备显示在地图上是被调用。当然,这个方法只对有图标的控件起 //作用。 draw: function (px) { if (this.div == null) { this.div = OpenLayers.Util.createDiv(); this.div.id = this.id; this.div.className = this.displayClass; } if (px != null) { this.position = px.clone(); } this.moveTo(this.position); return this.div; } 前面说过,OpenLayers.Control及其子类的实例都是会持有一个handler的引用的,因为每个控件起作用时,鼠标事件都是不一样的,这需要动态的绑定和接触绑定。在OpenLayers.Control中是通过active和deactive两个方法实现,就是动态的激活和注销。 //激活方法 activate: function () { if (this.active) { return false; } if (this.handler) { this.handler.activate(); } this.active = true; return true; } //注销方法 deactivate: function () { if (this.active) { if (this.handler) { this.handler.deactivate(); } this.active = false; return true; } return false; } 再来看OpenLayers.Control的子类,即各类“特色”控件。选鹰眼控件OpenLayers. Control. OverviewMap和矢量编辑工具条控件OpenLayers. Control. EditingToolbar来说。 顺便说一句,OpenLayers中的控件有些是需要图标的,像EditingToolbar,有些是不需要的,像OpenLayers. Control. DragPan。 OpenLayers. Control. OverviewMap: “鹰眼”实际上也是地图导航的一种形式,在外部形态上跟图层开关控件有点儿像。 添加鹰眼控件的语句: map.addControl(new OpenLayers.Control.OverviewMap()); 在它实现的成员函数中,draw函数是核心,继承基类OpenLayers.Control,在地图中显示这个控件。 此控件关联了一些浏览器事件,比如 rectMouseDown: function (evt) { if(!OpenLayers.Event.isLeftClick(evt)) return; this.rectDragStart = evt.xy.clone(); this.performedRectDrag = false; OpenLayers.Event.stop(evt); }。 OpenLayers. Control. EditingToolbar: OpenLayers从2.3版就对矢量编辑进行了支持,就是图上右上角几个图标。完成点、线、面的编辑功能。 同样,它也是用drew方法激活: draw: function() { Var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); this.activateControl(this.controls[0]); return div; } 下面的代码是使用此控件的具体过程: Var map, layer; map = new OpenLayers.Map( 'map', { controls: [] } ); layer = new OpenLayers.Layer.WMS( \\map.addLayer(layer); vlayer = new OpenLayers.Layer.Vector( \map.addLayer(vlayer); map.addControl(new OpenLayers.Control.PanZoomBar()); map.addControl(new OpenLayers.Control.EditingToolbar(vlayer)); map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); OpenLayers项目分析——(十)事件机制分析 (十)OpenLayers事件机制分析 OpenLayers中的事件封装是其一大亮点,非常值得学习。说到事件机制,在宏观上不得不涉及控件OpenLayers.Control类、OpenLayers. Marker类、OpenLayers.Icon类等。是这样,在外观上控件通过Marker和Icon表现出来,而事件包含在控件之后,用他们自己的话说就是:The controls that wrap handlers define the methods that correspond to these abstract events 。顺便再说一句,控件实现的核心是handler类,每个控件中都包含对handler的引用,通过active和deactive两个方法,实现动态的激活和注销。 OpenLayers中的事件有两种:一种是浏览器事件(比如onclick,onmouseup等),另一种是自定义的事件。自定义的事件像addLayer ,addControl等,不象浏览器事件会绑定相应的dom节点,它是与layer、map等关联的。 OpenLayers中支持的浏览器事件类型有(以常量的形式提供的): BROWSER_EVENTS: [ \ \\ \ 看看构造函数的的实现过程: initialize: function (object, element, eventTypes, fallThrough) { this.object = object; this.element = element; this.eventTypes = eventTypes; this.fallThrough = fallThrough; this.listeners = {}; // keep a bound copy of handleBrowserEvent() so that we can // pass the same function to both Event.observe() and .stopObserving() this.eventHandler = OpenLayers.Function.bindAsEventListener( this.handleBrowserEvent, this ); // if eventTypes is specified, create a listeners list for each // custom application event. if (this.eventTypes != null) { for (var i = 0; i < this.eventTypes.length; i++) { this.addEventType(this.eventTypes[i]); } } // if a dom element is specified, add a listeners list // for browser events on the element and register them if (this.element != null) { this.attachToElement(element); } } 可以这样理解: initialize(object, element, eventTypes, fallThrough)方法会将以数组eventTypes的每个元素为key建立哈希表listeners,表中每个键对应一个数组。还会给this.eventHandler赋值,它实际只是一个包装了triggerEvent事件触发函数的方法,所有的事件,包括浏览器事件和自定义事件都是通过它来中转的。然后initialize将所有的浏览器事件放入listeners中,并为其绑定相应的dom节点element和this.eventHandler事件处理函数 OpenLayers.Event.observe(element, eventType, this.eventHandler),节点上事件触发的时候会把事件传给this.eventHandler,它调用triggerEvent,从而将事件传出来。 来看其他的成员函数: addEventType:Add a new event type to this events object; attachToElement:把浏览器事件关联到相应的DOM元素上; register: Register an event on the events object. register: function (type, obj, func) { if (func != null) { if (obj == null) { obj = this.object; } var listeners = this.listeners[type]; if (listeners != null) { listeners.push( {obj: obj, func: func} ); } } } 其中,func参数是预先定义的回调函数。 unregister:注销方法; remove:Remove all listeners for a given event type. triggerEvent:Trigger a specified registered event。 OpenLayers的Vector与Markers OpenLayers在2.4版本中历史性地添加了Vector图层的支持。这个功能分别在不同的浏览器上用SVG/VML实现,其难度可以想象。Vector的出现可能大大增加开源WebGIS客户端的功能。 不过问题也随之而来,在使用Vector的时候,我们通常还要添加一个SelectFeature控件。这个控件的功能是使矢量的Feature可选,或是响应其他鼠标事件。问题就在于添加了SelectFeature之后,原本的Marker就不能再捕捉到事件,导致Popup之类的功能失效(包括Popup本身也不能捕捉到事件)。 鱼和熊掌不能兼得,不过OpenLayers 2.4中已经给Vector图层里增加了createMarker和createPopup两个方法,它的注释是“HACK - we need to decide if all vector features should be able to create markers”。料想利用这两个方法构造的marker和应该是可以解决前面的问题。 Vector的Marker的冲突可能还是会继续一段时间,看起来确实是一个小小的缺陷。 下一个 OpenLayers是一个开源的js框架,用于在您的浏览器中实现地图浏览的效果和基本的zoom,pan等功能。OpenLayers支持的地图来源包括了WMS,GoogleMap,KaMap,MSVirtualEarth等等,您也可以用简单的图片作为源,在这一方面OPenLayers提供了非常多的选择。 要使用OpenLayers,您可以到它的官方网站http://www.openlayers.org下载他的压缩包,解压后可以看到其中的一些目录和文件。拷贝dist目录下的OpenLayer.js、根目录下的lib目录、根目录下的img目录到你网站的scripts目录下(当然,这个只是例子,您网站的目录结构您自己说得算,只要保证OpenLayers.js,/lib,/img在同一目录中即可)。 接下来创建一个index.html作为查看地图的页面。导入OpenLayers.js和你将要创建的js。内容需要一个div,我们给它的id起名叫做area。你有必要在写一些CSS限定#area的宽度和高度,如果乐意,加上一个border也是很不错的选择。 废话不多说,我们首先要创建一个OpenLayer.Map对象的实例: var map = new OpenLayers.Map(\ 其中的参数可以传id,也可以传ElementObject,当然id更加方便一些。 接下来就是向地图中添加图层,通常情况下使用OpenLayers.Layer的子类来完成图层的初始化。 OpenLayers提供了一下Layers的扩展: OpenLayers.Layer.Image OpenLayers.Layer.HTTPRequest OpenLayers.Layer.Grid OpenLayers.Layer.WMS OpenLayers.Layer.KaMap OpenLayers.Layer.EventPane OpenLayers.Layer.Google OpenLayers.Layer.VirtualEarth OpenLayers.Layer.Markers OpenLayers.Layer.Text OpenLayers.Layer.GeoRSS OpenLayers.Layer.Boxes OpenLayers.Layer.TMS Image类封装一个实际图象作为图曾内容 HTTPRequest类可以接收一个动态生成的图片,你可以通过HTTPRequest类的参数向服务器发送参数 Grid类是HTTPRequest类的子类,提供更加详细的方法 WMS类用于连接WMS服务器以获得图象 KaMap类用于连接MapServer EventPane类作为用于接收用户操作的图层 Google类用于从Google获得图象,它仍然需要你从Google获得API KEY,并且include VirtualEarth类用于操作VirtualEarth的图层 Markers类用于生成接收和显示用户本地标记的图层 Text类用于接收CSV文件 GeoRSS类是Marker类的子类,用于封装接收GeoRSS并在图层中作出marker Boxes同样也是Marker类的子类,可以用div来做marker,而非image TMS用于接收TMS服务器的地图 创建完图层后,可以用Map的addLayer(layer)方法插入,并执行Map的zoomToMaxExtent()方法让地图合适地显示。 OpenLayers还提供了丰富的Control类为地图浏览添加一些工具,继承自OpenLayers.Control类 OpenLayers.Control.LayerSwitcher OpenLayers.Control.MouseDefaults OpenLayers.Control.MousePosition OpenLayers.Control.MouseToolbar OpenLayers.Control.OverviewMap OpenLayers.Control.PanZoom OpenLayers.Control.PanZoomBar OpenLayers.Control.Permalink OpenLayers.Control.Scale 这些类的实例会在地图浏览的“窗口”上增加一些工具栏或是“按钮”,增加互动性和功能性。 OpenLayers对常用的数据结构进行了封装 OpenLayers.LonLat OpenLayers.Size OpenLayers.Pixel OpenLayers.Bounds 以便于操作。 此外OpenLayers.Util类可以对图片载入错误时图片框的颜色和图片框中默认的图片进行自定义,这一点是非常方便的。OpenLayers的Ajax类对创建XHR对象的过程进行了封装,可以使用它进行简单的Ajax操作。 Geoserver基础源码分析 注:排除掉所有web大头的包 重点关注:“platform”,“main”,“ows”,“wfs”,“wcs”,“wms”这6个包上 核心包之间的关系 展现了包之间的依赖关系,下面的包依赖上面的包,最顶端是“platform”。 “platform”,“ows”和“main”(这3个完全可以合在一起嘛)包含了GeoServer最基础最核心的类和接口,下面介绍一些重要的类和接口,“wfs”,“wcs”,“wms”将利用这些类来完成具体的功能: 1)platform包的org.geoserver.platform.Service类代表一个具体的服务,例如WMS,它用ID和VERSION来唯一标定,每一个服务都会提供若干操作(Operation); 2)platform包的org.geoserver.platform.Operation类代表某个服务下可以被请求的操作,例如GetCapabilities,这个类利用Java的反射机制; 3)ows包的org.geoserver.ows.Dispatcher类处理所有OWS的请求,这个类将是我们调试的重点,我们会在后面的章节详细描述它; 4)main包的org.geoserver.catalog.Catalog接口包含资源访问的方法,这些资源有“Layer”,“Layer Group”,“Map”,“Namesapce”,“Resource”,“Store”,“Style”和“Workspace”,我们会在后面对这些资源做详细的讲解,了解了它们就知道GeoServer是如何组织和使用数据的了; 5)main包的org.geoserver.config.GeoServer接口包含访问服务器公共配置信息的方法,我们将会在很多场合看到它; 6)main包里面还有一些描述资源的接口,例如org.geoserver.catalog.LayerInfo代表“Layer”资源,这些接口我们也会在后面的章节逐一介绍。 第三方库 GeoServer使用了近百个第三方软件包(丰富第三方软件包也许是Java最迷人也最迷惑人的地方)。下面我会介绍一些我认为比较重要或者比较有趣的: 1)GeoTools可以说是Java语言的GIS标准包,它继承了GeoAPI,一个符合OGC简 单要素访问协议(Simple Feature Access)的Java包,提供了大量GIS操作,包括多种格式的空间数据源访问,地图渲染,空间几何操作,GeoServer的GIS部分完全使用它来实现; 2)SpringFramework是一个程序框架(wiki的解释),GeoServer用它来构建运行时环境,我们会在“main”,“wcs”,“wfs”和“wms”下面看到这样一个文件“applicationContext.xml”,这个文件告诉spring框架需要创建哪些类实例,以及如何创建。下面来看个典型配置: 这是“main”的配置文件的一部分,它构建一个基本的运行环境; 3)FreeMarker是一个模板引擎(官网的定义),用它提供的模板语言,我们可以很容易实现对象模型与输出格式的分离,GeoServer用它来实现某些HTML文本的输出(我觉得GeoServer对FreeMarker的使用还不够充分,我会把所有的文本输出全部交给它来完成)。 GeoServer处理请求的全过程 GeoServer使用Spring框架来构建,这里就可以看到Spring的使用,虚线框中的Restlet就是用Spring引入系统的,每个服务包的“applicationContext.xml”文件里都包含了描述Route映射的信息,例如WMS就有如下片段: class=\