Geoserver的WFS服务

标签: Geoserver 分类: Gis 创建时间:2019-05-07 07:44:26 更新时间:2025-01-17 10:39:22

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
<!-- http://localhost:8080/geoserver/sports/wfs -->
<?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>
<!-- pairs must form a closed ring -->
<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>
<!-- pairs must form a closed ring -->
<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>
<!-- pairs must form a closed ring -->
<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);
})
//也不能写
//cql_filter: 'name="s"'
//cql_filter: '"name"="s"'
参考文章:
1.GeoServer中WMS、WFS的请求规范
2.Ajax POST请求调用Geoserver的WFS服务
3.GeoServer的WFS空间查询:
4.Logical operators
5.gml图形
6.Geoserver Filtering
7.ECQL_Filter
8.WFS reference 这里有几个关于xml的语法说明,CreateStoredQuery、DropStoredQuery、ListStoredQueries

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即可。不再出现跨域问题:

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。