使用GeoServer进行图斑数据管理
本文将介绍如何使用GeoServer进行图斑数据的新增、删除和修改。我们将通过一个Vue.js应用来演示这些功能。
设置Vue.js应用
首先,我们设置Vue.js应用,并添加必要的组件和交互逻辑。
Check.vue
Check.vue
文件包含初始化地图和处理图斑交互的主要逻辑。
// filepath: /D:/workspace/check/client/src/views/Check.vue
<template>
<div class="page">
<Header />
<Map @map="init" />
<div class="tool">
<button @click="enableDraw">新增</button>
<button @click="enableModify">编辑</button>
<button @click="enableDelete">删除</button>
</div>
</div>
</template>
<script setup>
import Header from '../components/Header.vue'
import Map from '../components/Map.vue'
import { getBlockData, addBlockData, updateBlockData, deleteBlockData } from '../api'
// ...existing code...
function init(mapInstance) {
map = mapInstance
// ...existing code...
select.on('select', (e) => {
e.selected.forEach((feature) => {
const featureId = feature.getId()
deleteBlockData(featureId)
.then(response => {
vectorLayer.getSource().removeFeature(feature)
})
.catch(error => {
console.error('Error deleting block data:', error)
})
})
})
getBlock()
// ...existing code...
}
function getBlock() {
const view = map.getView()
const extent = view.calculateExtent()
getBlockData(extent)
.then(response => {
const features = new GeoJSON().readFeatures(response.data, {
featureProjection: map.getView().getProjection()
})
vectorLayer.getSource().clear()
vectorLayer.getSource().addFeatures(features)
})
.catch(error => {
console.error('Error fetching block data:', error)
})
}
function initAction() {
draw.on('drawend', (event) => {
const feature = event.feature
addBlockData([feature])
.then(response => {
console.log('Add Response:', response.data)
})
.catch(error => {
console.error('Error adding block data:', error)
})
})
modify.on('modifyend', (event) => {
const features = event.features.getArray()
updateBlockData(features)
.then(response => {
console.log('Update Response:', response.data)
})
.catch(error => {
console.error('Error updating block data:', error)
})
})
}
</script>
<style scoped>
.page {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f0f0f0;
}
.tool {
position: absolute;
bottom: 10px;
left: 10px;
display: flex;
gap: 10px;
}
</style>
API交互
接下来,我们来看一下api.js
中与GeoServer通信的函数。
api.js
api.js
文件包含获取、添加、更新和删除图斑数据的函数。
// filepath: /D:/workspace/check/client/src/api.js
import axios from 'axios';
import WFS from 'ol/format/WFS';
import GML from 'ol/format/GML';
// 创建 axios 实例
const api = axios.create({
baseURL: 'http://localhost:8080/geoserver/dahong',
timeout: 10000,
});
// 获取指定范围内的图斑数据
export function getBlockData(extent) {
const url = `/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=dahong:block&maxFeatures=50&bbox=${extent.join(',')}&outputFormat=application/json`;
return api.get(url);
}
// 新增图斑数据
export function addBlockData(features) {
const formatWFS = new WFS();
const formatGML = new GML({
featureNS: 'http://dahong.me',
featurePrefix: 'dahong',
featureType: 'block',
srsName: 'EPSG:4490',
});
const node = formatWFS.writeTransaction(features, null, null, formatGML);
const serializer = new XMLSerializer();
const data = serializer.serializeToString(node);
const d = data.replaceAll('geometry', 'geom');
const url = `/wfs?service=WFS&version=1.0.0&request=Transaction`;
return api.post(url, d, {
headers: {
'Content-Type': 'text/xml'
}
});
}
// 更新图斑数据
export function updateBlockData(features) {
const formatWFS = new WFS();
const formatGML = new GML({
featureNS: 'http://www.opengis.net/gml',
featureType: 'block',
srsName: 'EPSG:4490'
});
const node = formatWFS.writeTransaction(null, features, null, formatGML);
const serializer = new XMLSerializer();
const data = serializer.serializeToString(node);
const d = data.replaceAll('geometry', 'geom');
const url = `/wfs?service=WFS&version=1.0.0&request=Transaction`;
return api.post(url, d, {
headers: {
'Content-Type': 'text/xml'
}
});
}
// 删除图斑数据
export function deleteBlockData(featureId) {
const url = `/wfs?service=WFS&version=1.0.0&request=Transaction`;
const data = `
<wfs:Transaction service="WFS" version="1.0.0"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd">
<wfs:Delete typeName="dahong:block">
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:FeatureId fid="${featureId}"/>
</ogc:Filter>
</wfs:Delete>
</wfs:Transaction>
`;
return api.post(url, data, {
headers: {
'Content-Type': 'text/xml'
}
});
}
export default api;
补充
上述内容是由AI工具生成的,太好用了,也是我太懒了,整理的工作省去了。但是有些易错点上述内容没有表达出来,我这里补充一些:
-
GeoServer发布的数据是基于Postgresql。如果GeoServer发布的是Shapefile时,编辑和删除操作是没问题的,但新增不行!
新增可以将记录添加进去,但没有空间几何信息,我尝试着修改geometry为the_geom也没用,GeoServer控制台的错误信息:The problem is almost certainly caused by the fact that there are still locks being held on the shapefiles.
-
图层服务需给定权限,否则接口报错如下
设置方法如下
-
接口提交的参数类型应与数据库表中geom类型一致
比如数据库表geom字段类型是MULTI,而提交的没有MULTI,就会报错。我使用Openlayers生成的参数并没有MULTI,导致接口总是报错——Error performing insert: java.lang.String cannot be cast to org.locationtech.jts.geom.Geometry
。
我最终是重新用PostGIS执行导入,在导入时勾上简单Geometry,如下:
-
GML设置正确的坐标系,否则生成的经纬度是相反的(即纬度在前,经度在后)
这里我没仔细探究——地图和图层我设置为4490,GML设置为4326时会出现这种错误顺序。GML改为4490时就恢复正常了。
我猜测是两者经纬度不一致,导致GML使用了默认的3857.
const formatGML = new GML({
featureNS: 'http://www.opengis.net/gml',
featureType: 'block',
srsName: 'EPSG:4490'
});
-
最后,将新增、编辑、删除相关的参数列一下,供各位参考
新增代码如下:
<Transaction xmlns="http://www.opengis.net/wfs" service="WFS" version="1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<Insert>
<block xmlns="http://dahong.me">
<geom>
<Polygon xmlns="http://www.opengis.net/gml" srsName="EPSG:4490">
<exterior>
<LinearRing srsName="EPSG:4490">
<posList srsDimension="2">120.17887305370036 30.133373356323716 120.18868580467692 30.13552737483077 120.18425809996798 30.127389971581913 120.17887305370036 30.133373356323716</posList>
</LinearRing>
</exterior>
</Polygon>
</geom>
</block>
</Insert>
</Transaction>
编辑代码如下:
<Transaction xmlns="http://www.opengis.net/wfs" service="WFS" version="1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<Update typeName="feature:block"
xmlns:feature="http://www.opengis.net/gml">
<Property>
<Name>geom</Name>
<Value>
<feature:Polygon srsName="EPSG:4490">
<feature:exterior>
<feature:LinearRing srsName="EPSG:4490">
<feature:posList srsDimension="2">120.17887305 30.13337336 120.18333609178232 30.13696672765643 120.1886858 30.13552737 120.1842581 30.12738997 120.17887305 30.13337336</feature:posList>
</feature:LinearRing>
</feature:exterior>
</feature:Polygon>
</Value>
</Property>
<Property>
<Name>id</Name>
</Property>
<Filter xmlns="http://www.opengis.net/ogc">
<FeatureId fid="block.55409"/>
</Filter>
</Update>
</Transaction>
删除代码如下:
<wfs:Transaction service="WFS" version="1.0.0"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd">
<wfs:Delete typeName="dahong:block">
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:FeatureId fid="block.55409"/>
</ogc:Filter>
</wfs:Delete>
</wfs:Transaction>