1.空间查询 geoserver提供了强大的cql_filter查询语言,通过它可进行简单的控件查询,比如点在圆内,图形是否相交等。使用axios.js进行get请求,然后构造cql_filter语句即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ajax ({ method : 'get' , url : 'http://localhost:8080/geoserver/wfs' , param : { service : 'WFS' , version : '2.0' , request : 'GetFeature' , typeName : 'sports:sports' , outputFormat : 'application/json' , cql_filter : 'WITHIN(the_geom,POLYGON ((120.16423419 30.260509218, 120.183486934 30.260187265)))' } }).then (res => { console .log (res); })
但是对于复杂的图形,cql_filter中的POLYGON会变的很大,超过了浏览器Get请求中url的最大4k限制,就需要使用POST请求,奇怪的是,geoserver的wfs不支持直接的post请求,需要直接发送一个filter的xml文件,示例xml如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8" ?> <wfs:GetFeature service ="WFS" version ="2.0.0" outputFormat ="JSON" xmlns:wfs ="http://www.opengis.net/wfs/2.0" xmlns:fes ="http://www.opengis.net/fes/2.0" xmlns:gml ="http://www.opengis.net/gml/3.2" xmlns:sf ="http://www.openplans.org/spearfish" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd" > <wfs:Query typeNames ="sports:sports" > <fes:Filter > <fes:Within > <fes:ValueReference > sports:the_geom</fes:ValueReference > <gml:Polygon srsName ='http://www.opengis.net/def/crs/EPSG/0/26713' > <gml:exterior > <gml:LinearRing > <gml:posList > 120.16423419 30.260509218 120.183486934 30.260187265 120.181412762 30.24883114 120.192881569 30.245103859 120.209696214 30.232216593 120.200896773 30.22410574 120.161972271 30.202492748 120.13462608 30.195389205 120.133982646 30.206557789 120.138751065 30.207865783 120.13480825 30.215837435 120.142587795 30.21482398 120.148572037 30.2200362 120.150019211 30.218123308 120.155348218 30.226250085 120.155248216 30.233308076 120.149367654 30.237859255 120.149904021 30.24344476 120.157804711 30.253641127 120.153225436 30.260573061 120.16423419 30.260509218</gml:posList > </gml:LinearRing > </gml:exterior > </gml:Polygon > </fes:Within > </fes:Filter > </wfs:Query > </wfs:GetFeature >
Filter也可以组合与嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?xml version="1.0" encoding="UTF-8" ?> <wfs:GetFeature service ="WFS" version ="2.0.0" outputFormat ="JSON" xmlns:wfs ="http://www.opengis.net/wfs/2.0" xmlns:fes ="http://www.opengis.net/fes/2.0" xmlns:gml ="http://www.opengis.net/gml/3.2" xmlns:sf ="http://www.openplans.org/spearfish" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd" > <wfs:Query typeNames ="sports:sports" > <fes:Filter > <fes:And > <fes:Within > <fes:ValueReference > sports:the_geom</fes:ValueReference > <gml:Polygon srsName ='http://www.opengis.net/gml/srs/epsg.xml#4490' > <gml:exterior > <gml:LinearRing > <gml:posList > </gml:posList > </gml:LinearRing > </gml:exterior > </gml:Polygon > </fes:Within > <fes:Within > <fes:ValueReference > sports:the_geom</fes:ValueReference > <gml:Polygon srsName ='http://www.opengis.net/gml/srs/epsg.xml#4490' > <gml:exterior > <gml:LinearRing > <gml:posList > </gml:posList > </gml:LinearRing > </gml:exterior > </gml:Polygon > </fes:Within > </fes:And > </fes:Filter > </wfs:Query > </wfs:GetFeature >
注意 1.在使用ajax发送xml时,应将headers的请求头中的Content-Type设置为text/xml格式。
2.GetFeature节点属性中可以添加任何get请求时的参数,比如:outputFormat=”JSON”
3.进行空间查询时srsName应设置正确,比如上例中使用了4490坐标系,则srsName=’http://www.opengis.net/gml/srs/epsg.xml#4490 ‘,如果不知道如何设置srsName,可以在geoserver的图层预览时擦看GML格式的数据,其中有srsName的描述,获知直接 http://localhost:8080/geoserver/sports/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=sports:sports&maxFeatures=50
, 其中typeName应填写自己的工作空间和图层名。
还有一种更加简洁的方式,openlayers3中提供了WFS这么一个类,以及filter函数,借助于XMLSerializer().serializeToString()可以将更加方便的构造上面的xml请求,详情请观看:vector-wfs-getfeature ,当然构造出的xml和上面的差不多,唯一的区别就是不需要学习gml语法了,只需要专注于openlayers提供的filter就可以了。举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { WFS } from 'ol/format.js' ;import { within as withinFilter } from 'ol/format/filter.js' ;var featureRequest = new WFS ().writeGetFeature ({ srsName : 'EPSG:4326' , featurePrefix : 'sports' , featureNS : 'sports' , featureTypes : ['sports' ], outputFormat : 'application/json' , filter :withinFilter ('the_geom' , polygonGeom) }); let filter=new XMLSerializer ().serializeToString (featureRequest);ajax ({ method : 'post' , dataType : 'xml' , url : 'http://localhost:8080/geoserver/wfs' , data : filter }).then (res => { console .log (res); })
注意 1.应该使用filter里面的withinFilter,而不是“import Within from ‘ol/format/filter/Within’;”,具体为什么,不得而知,但是使用Within会报错:Cannot set property ‘tagName_’ of undefined
2.withinFilter中的srsName为坐标系,withinFilter中的坐标系要写正确:
3.还有一个问题就是说最好把withinFilter中的srsName空着,如果写了EPSG:4326的坐标系,被序列化后,坐标串是纬度在前,精度在后,不写的化,就是精度在前,纬度在后。这涉及到一个坐标方向的问题,可以通过 getAxisOrientation 查看一个坐标系的坐标方向。
4.featureNS表示什么意思不太清楚,可以不写,featurePrefix是geoserver中的工作区的名字,featureTypes是geoserver中的图层名字,最终会形成 typeName=’sports:sports’的字样。
2.属性查询 属性查询的方法是直接构造cql_filter,比如name=’’,”address like ‘’”,但是像下面这中写法,是会报错的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ajax ({ method : 'get' , url : 'http://121.41.28.227:8080/geoserver/wfs' , data : { service : 'WFS' , version : '2.0' , request : 'GetFeature' , typeName : 'sports:sports' , outputFormat : 'application/json' , cql_filter : '"name"="s"' } }).then (res => { console .log (res); })
错误提示:
正确的姿势是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ajax ({ method : 'get' , url : 'http://121.41.28.227:8080/geoserver/wfs' , data : { service : 'WFS' , version : '2.0' , request : 'GetFeature' , typeName : 'sports:sports' , outputFormat : 'application/json' , cql_filter : 'name=\'s\'' } }).then (res => { console .log (res); })
3.Geoserver开启jsonp访问 有些时候,我们使用到了jsonp请求geoserver的wfs服务,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var vectorSource = new ol.source .Vector ({ format : new ol.format .GeoJSON (), features : new ol.Collection () }); var callName = "parseResponse" + new Date ().getTime ();var url = 'http://localhost:8080/geoserver/jdyj/wfs?service=WFS&' + 'version=2.0.0&request=GetFeature&typename=jdyj:xzc&' + 'outputFormat=text/javascript&format_options=callback:' + callName + '&srsname=EPSG:4490&' ; $.ajax ({ url : url, dataType : 'jsonp' , jsonpCallback : callName, jsonp : false }).done (function (response ) { var format = new ol.format .GeoJSON (); var features = format.readFeatures (response); vectorSource.addFeatures (features); });
但是默认的geoserver是没有开启jsonp服务的,所以找到geoserver的配置文件:/tomcat/webapps/geoserver/WEB-INF/web.xml,如果是geoserver独立安装的,可能路径为:GeoServer 2.13.0\webapps\geoserver\WEB-INF\web.xml,找到:
1 2 3 4 <context-param > <param-name > ENABLE_JSONP</param-name > <param-value > true</param-value > </context-param >
本来这段代码是被注释掉的,把前后的注释符去掉就好了,如果没有这个内容,就手动添加也是可以的,然后重启geoserver服务就好了。
4.Geoserver开启跨域访问 在请求wfs时,往往会出现跨域访问限制:
(1)一种方式是像上面一样,用jsonp请求,还有一直方式,就是配置geoserver的跨域请求。配置跨域请求时需要到 https://search.maven.org/search
下载cors-filter.jar,java-property-utils.jar,版本最新的就好了
(3)然后将两个jar放到tomcat目录的lib下。
(3)修改webapps目录下的geoserver\WEB-INF\web.xml,添加如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <filter > <filter-name > CORS</filter-name > <filter-class > com.thetransactioncompany.cors.CORSFilter</filter-class > <init-param > <param-name > cors.allowOrigin</param-name > <param-value > *</param-value > </init-param > <init-param > <param-name > cors.supportedMethods</param-name > <param-value > GET, POST, HEAD, PUT, DELETE</param-value > </init-param > <init-param > <param-name > cors.supportedHeaders</param-name > <param-value > Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value > </init-param > <init-param > <param-name > cors.exposedHeaders</param-name > <param-value > Set-Cookie</param-value > </init-param > <init-param > <param-name > cors.supportsCredentials</param-name > <param-value > true</param-value > </init-param > </filter > <filter-mapping > <filter-name > CORS</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
重启tomcat即可。不再出现跨域问题: