WebGIS入门_GISer_Jing的博客-CSDN博客

在WebGIS入门篇,前端使用了纯HTML、CSS、Javascript、Jquery较为传统方式构建,服务器借助ArcGIS Srver发布相关地理服务且涉及到2DGIS,自行构建后端且涉及到数据库。

So,WebGIS进阶来了!!!!

本文大概是关于:Vue2+Cesium+Openlayers+Java+MySQL+Tomcat

1.前端

1.1Vue

进阶篇,除涉及传统的三件套,还涉及到主流的前端框架Vue

Vue安装部署和基本语法,相关资料网上有不少,可以自行参考学习

在这我仅提醒选择Vue时一定要注意版本,不同的Vue在后续结合Cesium(主流的GIS三维引擎)都不同,会出现不少问题,本文选择的是Vue2

<el-dialog>灰的,需:append-to-body="true"

1.2ElementUI

对应Vue2的样式库,需用NPM安装并导入,其提供不少前端所需样式和元素

1.3Webpack

Vue打包工具,后续结合Cesium\Openlayer等GIS引擎需配置相关参数,否则可能会报错,这部分也是最苦恼和麻烦的

1.4Axios

Axios用于请求后端或者服务器,是一个基于promise 的 HTTP 库(类似于jQuery的Ajax,用于HTTP请求),可以用在浏览器和 node.js中(既可以用于客户端也可以用于node.js编写的服务端)。

2.后端

本项目基于Java Spring-Boot,Spring核心大致有

  • Bean(组件,可以为一个类,需将其放入IOC容器中,其他类需要调用依赖该类时,利用相应方式注入即可)
  • DI(Dependence Injection,依赖注入)
  • AOP(Aspect Oriented Programming,面向切片编程,编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切片)。
  • Spring 三层架构 ,Controller(定义相关API,与前端进行响应)、Service(编写自己所需业务功能)、DAO(与数据进行操作)

3.MySQL数据库

需注意通常需利用连接池(Hikari\Druid)和数据库建立连接,还可利用MyBatis简化JDBC的操作

当然最基本的就是SQL语句、索引等数据库基本知识学习

4.服务器

4.1Tomcat服务器

【精选】Web应用服务器——Tomcat_笨笨在努力的博客-CSDN博客

本项目用Tomcat服务器存放3D Tiles数据(数据量近7G,存放在前端或者后端会大大影响打包运行速度)

4.2.Geoserver服务器

开源,用于发布与GIS相关服务,类似于ArcGIS Server

上述大致介绍了相关技术,下面将介绍嵌入GIS引擎、请求3D Tiles数据时碰到的问题

5.Vue2+Cesium

对于Vue2项目,推荐安装1.95.0版本Cesium

npm install cesium@1.95.0 --save

安装最新版本,会报loader找不到(loader,将浏览器无法解析的相关文件和代码解析成浏览器能识别的文件和代码),是在vue.config.js中配置。例如,在Cesium中常常需要加载glb\gltf文件,就需架子啊相应loader,否则就会报错。

    module: {
      rules: [
        {
          test: /\.(gltf)$/,
          loader: 'url-loader'
        },
        {
          test: /\.(glb)$/,
          loader: 'url-loader'
        },
          {
          test: /\.js$/,
          use: {
          loader: '@open-wc/webpack-import-meta-loader',
          },
          },
          {
            test: /\.(js)$/,
            loader: 'babel-loader'
          },
          {
            test: /\.(png|jpg|gif|webp|svg)$/,
            type:'asset/resource'
          },
          {
            test: /\.ts$/,
               loader: 'ts-loader',
               options: { appendTsSuffixTo: [/\.vue$/] }
           }
      ],
    },

对于Vue2+Cesium1.95.0,不会报loader错误但是需要配置webpack配置项,否则运行时不报错但无法展示三维地球🌏,在vue.config.js文件配置,可自行将自己文件和下面文件比对:

// const { defineConfig } = require('@vue/cli-service')
// module.exports = defineConfig({
//   transpileDependencies: true
// })
 
const { defineConfig } = require('@vue/cli-service')
 //安装相关插件并引入
const CopyWebpackPlugin = require('copy-webpack-plugin')
const webpack = require('webpack')
//Node.js中路径模块
const path = require('path')

 //定义与cesium相关的路径变量,后续会用到
let cesiumSource = './node_modules/cesium/Source/' //按理说应该是未打包的
// 此处必需,因为高版本cesium没有这个Workers报错。必写-1
const cesiumWorkers = '../Build/Cesium/Workers'
 
module.exports = defineConfig({
  transpileDependencies: true,
 //静态资源地址,gltf、glb文件存放,或者存放在下面的static文件下,否则打包时会找不到相关文件
  publicPath: './',
  outputDir: "dist", // 输出文件目录
  lintOnSave: false, // eslint 是否在保存时检查 关闭语法检查
  // assetsDir: 'static', // 配置js、css静态资源二级目录的位置
  
  configureWebpack: {
    module: {
      rules: [
        {
       //配置相关loader
          test: /\.(gltf)$/,
          loader: 'url-loader'
        },
        {
          test: /\.(glb)$/,
          loader: 'url-loader'
        },
          {
          test: /\.js$/,
          use: {
          loader: '@open-wc/webpack-import-meta-loader',
          },
          },
          {
            test: /\.(js)$/,
            loader: 'babel-loader'
          },
          {
            test: /\.(png|jpg|gif|webp|svg)$/,
            type:'asset/resource'
          },
          {
            test: /\.ts$/,
               loader: 'ts-loader',
               options: { appendTsSuffixTo: [/\.vue$/] }
           }
      ],
    },
    output: {
      sourcePrefix: ' '
    },
    amd: {
      toUrlUndefined: true
    },
    resolve: {
      alias: {
        //别名,在vue文件中有@会自动解析为相应路径
        //path.resolve()合并路径得到绝对路径
        '@': path.resolve('src'),
        'cesium': path.resolve(__dirname, cesiumSource)
      },
      // 参考别人说的,我不太懂webpack,所以都不知道咋解决https zlib问题  必写-2
      fallback: { "https": false, "zlib": false, "http": false, "url": false },
    },
    plugins: [
      // 对于webpack版本此处有不同配置,webpack低版本5.x执行下面4行注释的代码,对于webpack高版本9.x及以上,patterns是可以的。
      new CopyWebpackPlugin({
        patterns: [
          { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' },
          { from: path.join(cesiumSource, 'Assets'), to: 'Assets' },
          { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' },
          { from: path.join(cesiumSource, 'ThirdParty/Workers'), to: 'ThirdParty/Workers' },
        ],
      }),
      // new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Workers'), to: 'Workers'}]),
      // new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets'}]),
      // new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets'}]),
      // new CopyWebpackPlugin([ { from: path.join(cesiumSource, 'ThirdParty/Workers'), to: 'ThirdParty/Workers'}]),
      new webpack.DefinePlugin({
        //cesium基本路径,若报Uncaught SyntaxError: Unexpected token '<'
        //是路径问题,尝试不要加点
        CESIUM_BASE_URL: JSON.stringify('./')
        // CopyWebpackPlugin from的绝对路径
      })
    ],
 
  },
})

配置好后,在Vue中所需应用Cesium的文件中,引入Cesium和样式即可:

  import * as Cesium from "cesium/Cesium.js";
    // 导入cesium的css样式库,其实有点类似element-plus库全部导入时的样子
  import "cesium/Widgets/widgets.css";

🎉Vue+Cesium

6.Vue+Openlayer

相信解决Vue+Cesium, it may be easy to perform this task!在这仅提供版本和配置好的代码

npm install ol@7.4.0 --save
<template>
  <div>
    <div id='map' style='width: 100%; height: 620px'></div>
  </div>
</template>
 
<script>
import 'ol/ol.css'//导入样式
import {Map, View, Feature} from 'ol'
import OSM from 'ol/source/OSM'
import VectorSource from 'ol/source/Vector'
import Cluster from 'ol/source/Cluster'
import {Vector as VectorLayer, Tile as TileLayer} from 'ol/layer'
import {Style, Fill as StyleFill, Stroke as StyleStroke, Circle as StyleCircle, Text as StyleText} from 'ol/style'
import { Circle as GeomCircle, Point as GeomPoint, LineString as GeomLineString, Polygon as GeomPolygon } from 'ol/geom'
import { Draw as InteractionDraw } from 'ol/interaction'
 
export default {
  name: 'OpenLayersMap',
  data () {
    return {
      map: null,//初始化map
      points: [],
      // 线条点数组
      linePoints: [],
      // 多边形数组
      polygonPoints: [],
    }
  },
  methods: {
    createMap () {
      let _this = this
    
      this.map = new Map({
        target: 'map',
        layers: [
          new TileLayer({
            source: new OSM({})
          }),
        ],
        view: new View({
          // 设置中心点,默认厦门,用于规划厦门市的未来发展
          center: [118.15075122802735, 24.482664909344276],
          projection: 'EPSG:4326',
          // 设置缩放倍数
          zoom: 13,
          minZoom: 6,
          maxZoom: 20
        })
      })
      // 绑定点击事件
      this.map.on('click', function (e) {
        let coor = e.coordinate//获取坐标
        // console.log(e.coordinate)
        console.log('lon:' + coor[0] + ',lat:' + coor[1])
        _this.handleClick(coor)
      })
      // 绘制聚合点
      _this.addMarker()
    },
    // 设置统一控制点击事件,需要画图方式在此处切换
    handleClick(point) {
      // 绘制连线
    //   this.drawLineString(point)
      // 绘制点
    //   this.drawPoint(point)
      // 绘制圆形
      this.drawCircle(point)
      // 绘制多边形
      // this.drawPolygon(point)
    },
    // 绘制点位
    drawPoint (center) {
        //map->layer->feature
      let vectorLayer = this.getLayer()
 
      let point = new GeomPoint(center)
      let feature = new Feature(point)
      vectorLayer.getSource().addFeature(feature)
      this.map.addLayer(vectorLayer)
    },
    // 绘制连线
    drawLineString(point) {
      this.linePoints.push(point)
      let featureLine = new Feature({
        geometry: new GeomLineString(this.linePoints),
      });
      let source = new VectorSource()
      source.addFeature(featureLine)
      let layer = new VectorLayer()
      layer.setSource(source)
      this.map.addLayer(layer)
    },
    // 绘制区域圆形
    drawCircle (center) {
      let vectorLayer = this.getLayer()
 
      // 设置半径
      let circle = new GeomCircle(center, 0.003)// 新建圆对象
      let feature = new Feature(circle)// 新建Feature对象 并将circle传入
      vectorLayer.getSource().addFeature(feature)// 将Feature对象填入图层源
      this.map.addLayer(vectorLayer) // 将图层添至地图对象
    },
    //画多边形
    drawPolygon(point){
      this.polygonPoints.push(point)
      let feature = new Feature({
        geometry: new GeomPolygon([this.polygonPoints]),
        attributes: null
      });
      // 添加线的样式
      let lineStyle = new Style({
        fill: new StyleFill({
          color: 'rgba(1, 210, 241, 0.1)'
        }),
        stroke: new StyleStroke({
          color: 'rgba(255, 0, 0)',
          width: 4,
        }),
      });
      feature.setStyle(lineStyle);
      let source = new VectorSource();
      source.addFeature(feature)
      let vectorLayer = new VectorLayer({
        source: source
      })
      this.map.addLayer(vectorLayer)
    },
    // 设置聚合点
    addMarker() {
      let source = new VectorSource();
      // 随机创建200个要素,后台点位取出后按此格式处理
      for (let i = 1; i <= 200; i++) {
        let coordinates = [118.10 + Math.random() * 0.05, 24.48 + Math.random() * 0.05];
        let feature = new Feature(new GeomPoint(coordinates));
        source.addFeature(feature);
      }
 
      // 聚合
      let clusterSource = new Cluster({
        source: source,
        distance: 50
      })
 
      let clusters = new VectorLayer({
        source: clusterSource,
        style: function (feature, resolution) {
          let size = feature.get('features').length;
          let style = new Style({
            image: new StyleCircle({
              radius: 20,
              stroke: new StyleStroke({
                color: 'white'
              }),
              fill: new StyleFill({
                color: '#AAD3DF'
              })
            }),
            text: new StyleText({
              text: size.toString(),
              fill: new StyleFill({
                color: 'black'
              })
            })
          })
          return style;
        }
      });
 
      this.map.addLayer(clusters)
    },
    // 获取新的 layer 图层对象
    getLayer () {
      return new VectorLayer({
        source: new VectorSource({
          features: ''
        }),
        // 设置样式,但不完全兼容
        // style: function (feature) {
        //   let style = new Style({
        //     stroke: new StyleStroke({
        //       color: '#E80000',
        //       width: 2
        //     }),
        //     fill: new StyleFill({
        //       color: 'rgba(0,0,0,0)'
        //     })
        //   })
        //   return style
        // }
      })
    }
  },
  mounted () {
    this.createMap()
  }
 
}
</script>
 

7.Vue+Tomcat跨域问题 

本项目将近7G(>5G,否则可以部署在Cesium个人云服务器上)的3D Tiles数据部署在Tomcat

而因为端口号不同所以出现了跨域问题,为了解决该问题在Tomcat服务器端和Vue端皆需配置。

7.1Tomcat允许跨域

在 tomcat/conf/web.xml配置下列代码,可能版本不同部分版本还需下载相应jar包

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


 <filter>
 <filter-name>CorsFilter</filter-name>
 <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>CorsFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

7.2Vue中配置代理解决跨域 

7.2.1配置vue.config.js
 devServer: {
    host: '0.0.0.0',
    port: port,
    open: false,
    proxy: {
      '/api': {
        target: `http://localhost:8090`,//请求的基本路径
        changeOrigin: true,//跨域
        pathRewrite: {
          '^/api' : ''
        }//发请求时,在处理请求路径时,将 '^/api'匹配为''
      },
        //可能部分前端无法匹配识别'/api',仅将它处理为字符串,这时就需要用下列方式配置
        //VUE_APP_BASE_API时定义在.env.development下的变量,如下:
        //VUE_DATA_PROXY = '/api'
      [process.env.VUE_APP_BASE_API]: {
        target: `http://localhost:8080`,
        changeOrigin: true,
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: ''
        }
      },
      

    },
    disableHostCheck: true
  },
7.2.2axios发get/post请求时路径配置
import axios from "axios";
axios.get('/api/Model/modelUrl1.json').then(response=>{},err=>{})

提示:配置时一定要注意细节,仔细!!!

8.cesium加载倾斜模型报错Uncaught (in promise) abort({}) at Error

Uncaught (in promise) RuntimeError: Aborted(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 21 44 4f @+0). Build with -s ASSERTIONS=1 for more info.


 解决方法:

将Cesium/ThridParty/文件夹放置Vue项目的public文件下(ThirdParty【第三方库】文件夹下包含了draco_decoder.wasm文件)

本文大致内容就这些了,框架性介绍了WebGIS的内容,希望对各位GISer、IT小白有帮助~ 

👍👍👍+收藏 :别忘记路径了哈~~~

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐