vue+leaflet示例:结合geoserver利用WFS服务实现图层新增功能(附源码下载)

demo源码运行环境以及配置

  • 运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。
  • 运行工具:vscode或者其他工具。
  • 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令:
    (1)下载demo环境依赖包命令:npm i
    (2)启动demo命令:npm run dev
    (3)打包demo命令: npm run build:release

示例效果



本篇实现的思路:主要是leaflet通过调用geoserver发布的地图服务WFS来达到图层新增记录的目的。与GeoServer的WFS进行基于Rest交互关键就在于请求参数,值得注意的是这些请求最好采用POST方法发送。查询可以采用json,但增加,删除,修改都只能采用XML形式Transaction。最后利用leaflet来叠加显示在地图上展示。

  • 用leaflet插件绘制图形工具draw的新增图形以及回调函数获取绘制图形空间信息,绘制工具的github地址:
    https://github.com/geoman-io/leaflet-geoman

  • geoserver默认WFS服务是没有编辑操作权限的,所以需要在geoserver设置权限,允许编辑操作才行,截图如下:



  • 核心源码

<template>
  <div id="map"></div>
  <div class="titleContainer center">
    <span>vue+leaflet示例:结合geoserver利用WFS服务实现图层新增功能</span>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref } from "vue";
import L from "leaflet";
import "proj4";
import "proj4leaflet";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
import config from "../config";
import { useRouter } from "vue-router";
const router = useRouter();
const geoserverUrl = "http://localhost:8080/geoserver/WebGIS";
let map = null;
let geojsonLayer = null;
let wmsLayer = null;
let latlng = null;
let isDraw = false;
onMounted(() => {
  initMap();
});
const initMap = () => {
  // 创建地图对象
  map = L.map("map", {
    attributionControl: false,
  }).setView(L.latLng(22.95186415, 113.90271877), 14);
  //创建底图切换数据源
  const baseLayer = L.tileLayer(
    "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}"
  );
  map.addLayer(baseLayer); //地图默认加载的底图
  // 创建geoserver发布的wms图层
  wmsLayer = L.tileLayer
    .wms(geoserverUrl + "/wms", {
      layers: "WebGIS:testLayer",
      transparent: true,
      maxZoom: 20,
      format: "image/png",
    })
    .addTo(map);
  // 监听地图点击事件
  map.on("click", onClickMap);
  //绘制工具draw
  const customTranslation = {
    tooltips: {
      finishLine: "单击任何存在的标记或者双击以完成",
      finishPoly: "单击第一个标记或者双击完成以完成",
    },
  };
  map.pm.setLang("customName", customTranslation, "zh");
  map.pm.addControls({
    position: "topleft",
    drawMarker: false,
    drawCircleMarker: false,
    drawCircle: false,
    drawPolyline: false,
    drawRectangle: false,
    editMode: false,
    dragMode: false,
    cutPolygon: false,
    drawText: false,
  });
  map.on("pm:drawstart", ({ workingLayer }) => {
    isDraw = true;
    if (geojsonLayer) {
      map.removeLayer(geojsonLayer);
      geojsonLayer = null;
    }
  });
  map.on("pm:create", (e) => {
    //console.log(e);
    isDraw = false;
    geojsonLayer = e.layer;
    geojsonLayer.addTo(map);
    e.layer.unbindPopup();
    const elements =
      '<span>名称:</span><input type="text" id="estate_num" /></br><span>备注:</span><input type="text" id="holder_nam" /></br><button type="button" id="addBtn">新增</button>';
    e.layer.on("popupopen", function (e) {
      $("#addBtn").click(function () {
        if (geojsonLayer) {
          //构造polygon
          let polygon = "";
          const data = geojsonLayer.toGeoJSON().geometry.coordinates[0];
          for (let i = 0; i < data.length; i++) {
            const item = data[i];
            polygon += item[0] + "," + item[1] + " ";
          }
          polygon += data[0][0] + "," + data[0][1];
          addLayers(
            polygon,
            $("#estate_num").val(),
            $("#holder_nam").val(),
            callbackAddLayersWFSService
          );
        }
      });
    });
    // 获取绘制多边形中心点
    // console.log(turf.centroid(geojsonLayer.toGeoJSON()));
    const geo = turf.centroid(geojsonLayer.toGeoJSON());
    const latlng = [geo.geometry.coordinates[1],geo.geometry.coordinates[0]];
    e.layer.bindPopup(elements).openPopup(latlng);
    // e.layer.unbindPopup();
  });
};
/*
 * 地图点击事件
 */
const onClickMap = async (e) => {
  if (isDraw) return;
  //console.log('地图点击事件',e);
  latlng = e.latlng;
  const point = e.latlng.lng + "," + e.latlng.lat;
  queryByPoint(point, "testLayer", callbackLastQueryWFSService);
};
/*图层新增
 *@method addLayers
 *@param polygon 图形
 *@param fieldValue1 字段1值
 *@param fieldValue2 字段2值
 *@return callback
 */
const addLayers = async (polygon, fieldValue1, fieldValue2, callback) => {
  let xml =
    '<wfs:Transaction service="WFS" version="1.0.0"    xmlns:opengis="http://webgis.com"    xmlns:wfs="http://www.opengis.net/wfs"    xmlns:ogc="http://www.opengis.net/ogc"   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-basic.xsd">';
  xml += '<wfs:Insert handle="WebGIS">';
  xml += "<opengis:testLayer>";
  xml += "<opengis:the_geom>";
  xml += '<gml:MultiPolygon srsName="EPSG:4326">';
  xml += "<gml:polygonMember>";
  xml += "<gml:Polygon>";
  xml += "<gml:outerBoundaryIs>";
  xml += "<gml:LinearRing>";
  xml +=
    '<gml:coordinates decimal="." cs="," ts=" ">' +
    polygon +
    "</gml:coordinates>";
  xml += "</gml:LinearRing>";
  xml += "</gml:outerBoundaryIs>";
  xml += "</gml:Polygon>";
  xml += "</gml:polygonMember>";
  xml += "</gml:MultiPolygon>";
  xml += "</opengis:the_geom>";
  xml += "<opengis:estate_num>" + fieldValue1 + "</opengis:estate_num>";
  xml += "<opengis:holder_nam>" + fieldValue2 + "</opengis:holder_nam>";
  xml += "</opengis:testLayer>";
  xml += "</wfs:Insert>";
  xml += "</wfs:Transaction>";
……
};
……
</script>

<style scoped>
#map {
  width: 100vw;
  height: 100vh;
}
.titleContainer {
  position: absolute;
  top: 0;
  background: rgba(0, 0, 0, 0.45);
  height: 50px;
  width: 100vw;
  z-index: 999;
  font-size: 14px;
  color: #fff;
  font-size: 28px;
}
.center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
</style>

几点说明:
1.xmlns:opengis="http://webgis.com",geoserver工作区的url;

2.WebGIS,geoserver工作区;
3.testLayer,操作图层名称;
4.the_geom,操作图层的几何字段;
5.estate_num,holder_nam,分别是操作图层的属性字段。

  • 图层新增回调函数,操作成功或者失败,可以在网页的控制台网络看请求结果

由于单位的geoserver地图服务数据保密性,矢量图层数据不公开

下载源码:GIS之家的学习交流圈

posted @ 2025-03-25 20:38  GIS之家  阅读(40)  评论(0)    收藏  举报