14、WebGIS 从前端到后端:后台接口开发

欢迎来到 WebGIS 入门系列的第十四篇文章!在本文中,我们将介绍如何利用 Node.js 来实现 WebGIS 系统开发时后台接口的开发知识,其中包括数据库初始化、数据表创建、后端接口程序初始化、Vue 项目中路由配置等。

调整 Vue 项目路由配置

调整 src 目录下 App.vue 组件中的代码,配置菜单跳转地址及 router-view 信息:

<template>  <header>    <h1>我的 WebGIS 应用</h1>    <nav>      <ul>        <li><a href="/">首页</a></li>        <li><a href="/map">地图</a></li>        <li><a href="/data">数据管理</a></li>      </ul>    </nav>  </header>  <main>    <router-view></router-view>  </main></template>
<script setup lang="ts"></script>
<style>// ......</style>

在 src/views 目录下分别新建 MapView.vue 和 DataManageView.vue 组件:

// MapView.vue<template>  <main class="map-main">    <MapView />  </main></template>
<script setup lang="ts">import MapView from '@/components/MapView.vue'</script>
<style>.map-main {  width: 100%;  height: 100%;}</style>
// DataManageView.vue<template>  <main class="data-main">    <DataManage />  </main></template>
<script setup lang="ts">import DataManage from '@/components/DataManage.vue'</script>
<style>.data-main {  width: 100%;  height: 100%;}</style>

在 src/components 目录下新建 DataManage.vue 组件:

<template>  <div class="data-manage">data manage</div></template>
<script setup lang="ts"></script>
<style scoped>.data-manage {  width: 100%;  height: 100%;}</style>

优化调整 src/router 目录下的路由配置信息:

import { createRouter, createWebHistory } from 'vue-router'import HomeView from '../views/HomeView.vue'
const router = createRouter({  history: createWebHistory(import.meta.env.BASE_URL),  routes: [    {      path: '/',      name: 'home',      component: HomeView    },    {      path: '/map',      name: 'map',      component: () => import('../views/MapView.vue')    },    {      path: '/data',      name: 'data',      component: () => import('../views/DataManageView.vue')    }  ]})
export default router

界面预览如下所示:

图片[1]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

优化 DataManage 组件

在 src/components 目录下的 DataManage.vue 组件中拷贝下面代码,完善数据管理界面:

<template>  <div class="data-manage">    <div class="data-manage-form">      <div class="data-manage-header">        <el-alert title="填入以下信息后进行数据入库" type="info" show-icon />      </div>      <el-form :model="form" label-width="auto" style="max-width: 600px">        <el-form-item label="名称">          <el-input v-model="form.name" />        </el-form-item>        <el-form-item label="区域">          <el-select v-model="form.region" placeholder="请选择">            <el-option              v-for="item in regionData"              :key="item.value"              :label="item.label"              :value="item.value"            />          </el-select>        </el-form-item>        <el-form-item label="日期">          <el-date-picker v-model="form.date" type="date" placeholder="请选择" style="width: 50%" />        </el-form-item>        <el-form-item label="已激活">          <el-switch v-model="form.delivery" />        </el-form-item>        <el-form-item label="激活类型">          <el-checkbox-group v-model="form.type">            <el-checkbox              v-for="item in typeData"              :key="item.value"              :label="item.value"              :name="item.value"              >{{ item.label }}</el-checkbox            >          </el-checkbox-group>        </el-form-item>        <el-form-item label="资源">          <el-radio-group v-model="form.resource">            <el-radio v-for="item in resourceData" :key="item.value" :label="item.value">{{              item.label            }}</el-radio>          </el-radio-group>        </el-form-item>        <el-form-item label="备注">          <el-input v-model="form.desc" type="textarea" />        </el-form-item>        <el-form-item>          <el-button type="primary" @click="onSubmit">提交</el-button>          <el-button>取消</el-button>        </el-form-item>      </el-form>    </div>    <div class="data-manage-table">      <div class="data-manage-header">        <el-alert title="入库数据反显" type="info" show-icon />      </div>      <el-table :data="tableData" height="400" style="width: 100%" empty-text="暂无数据">        <el-table-column          v-for="item in tableColumn"          :key="item.prop"          :prop="item.prop"          :label="item.label"        />      </el-table>    </div>  </div></template>
<script setup lang="ts">import { reactive, ref } from 'vue'
const regionData = ref([  {    value: 'beijing',    label: '北京'  },  {    value: 'shanghai',    label: '上海'  },  {    value: 'chengdu',    label: '成都'  }])const typeData = ref([  {    value: 'type-1',    label: '类型一'  },  {    value: 'type-2',    label: '类型二'  },  {    value: 'type-3',    label: '类型三'  },  {    value: 'type-4',    label: '类型四'  }])const resourceData = ref([  {    value: 'resource-1',    label: '资源一'  },  {    value: 'resource-2',    label: '资源二'  }])const tableColumn = ref([  {    prop: 'name',    label: '名称'  },  {    prop: 'region',    label: '区域'  },  {    prop: 'date',    label: '日期'  },  {    prop: 'delivery',    label: '已激活'  },  {    prop: 'type',    label: '激活类型'  },  {    prop: 'resource',    label: '资源'  },  {    prop: 'desc',    label: '备注'  }])const tableData = ref([])
const form = reactive({  name: '',  region: '',  date: '',  delivery: false,  type: [],  resource: '',  desc: ''})
const onSubmit = () => {  console.log('submit!', JSON.parse(JSON.stringify(form)))}</script>
<style scoped>.data-manage {  width: 100%;  height: 100%;  display: flex;  padding: 16px;  box-sizing: border-box;}.data-manage-header {  margin-bottom: 16px;}.data-manage-form {  width: 480px;  border: 1px solid #dcdfe6;  border-radius: 4px;  margin-right: 8px;  padding: 16px;  box-sizing: border-box;}.data-manage-table {  flex: 1;  border: 1px solid #dcdfe6;  border-radius: 4px;  padding: 16px;  box-sizing: border-box;}</style>

界面预览如下:

图片[2]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

上述界面操作逻辑:左侧数据入库面板中依次填入相关信息后点击下方“提交”按钮,用户输入的信息数据会被提交到后台数据库中,此时右侧数据预览面板会更新,显示最新数据库中的数据。

数据库初始化

数据在前端界面被用户输入后,会经过后端接口程序,最终保存在数据库中,数据库可以安装部署在本地开发环境或远端服务器环境中。

此系列文章中为了简化操作,在腾讯云租了一个 PostgreSQL 云数据库,所以省去了安装部署流程,如果想安装部署在本机或服务器的话,建议大家通过搜索引擎去寻找一些相关教程,无脑安装即可。

数据库安装部署之后,接下来进行库表初始化。

首先在 PostgreSQL 数据库管理面板中选择新建数据库,名称为“webgis”:

图片[3]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

然后选择新建的“webgis”数据库进入该数据库,在 public 模式下选择操作中的“新建表”,新建一份数据表,其结构如下:

图片[4]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

图片[5]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

图片[6]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

至此,一个名为“webgis”的数据库创建成功,里面又新建了一份名为“webgis_project_bilibili”的数据表,我们后续入库的数据就存放在此。

后端接口程序初始化

为了降低后端接口开发门槛,避免短时间内又学习一门新的开发语言,此系列的后端接口开发我们使用 Node.js,它是一个类似于浏览器的 JavaScript 运行环境,允许 JavaScript 语言编写的程序在浏览器环境之外可以运行,简单理解就是:Node.js 让 JavaScript 可以在浏览器之外运行成为了可能!

Node.js 在使用之前必须要在本机安装部署,不过不用担心,我们已经安装部署过了,详见《6、快速上手:使用 Vue 3 创建您的第一个 WebGIS 地图》。

在现有的项目根目录下新建 node 目录,然后通过 npm init 命令初始化一个后端接口程序目录,此时该目录下会出现一个 package.json 文件,里面包含当前后端程序的项目名称、版本号、作者信息等,以及后续我们安装的依赖包信息。

运行命令 npm install express 安装 express 框架。

新建 index.js 文件,将下述代码拷贝至此:

// eslint-disable-next-line no-undefvar express = require('express')var app = express()
app.get('/', function (req, res) {  res.send('hello world')})
app.listen(3001)

通过上述操作,我们已经初始化了一个基础的后端接口程序,其中已经新建了一个路径为“/”的 get 类型接口,通过 node index 命令将其启动后,在浏览器地址栏中输入“:3001/”,可以访问该接口:

图片[7]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

GET 和 POST 接口开发

GET 和 POST 接口逻辑中都涉及到从 PostgreSQL 数据库中获取数据和插入数据,所以后端接口程序中需要安装 pg 模块,通过命令 npm install pg 安装。

在 node 目录下新建 routers 目录,然后该目录下新建 user.js 文件,在此文件中分别完成用户数据获取和插入接口:

 // eslint-disable-next-line no-undefvar express = require('express')var pg = require('pg')var router = express.Router()
// postgres://[数据库用户名]:[数据库密码]@[数据库地址及端口]/[数据库名称]var pgConfig = "postgres://postgres:webgis@localhost:5432/webgis";
// 获取全部用户数据router.get('/all-data', function (req, res) {  var client = new pg.Client(pgConfig)  client.connect(function (isErr) {    if (isErr) {      console.log('connect error:' + isErr.message)      client.end()      return    }    client.query('SELECT * FROM "webgis_project_bilibili"', function (isErr, rst) {      if (isErr) {        console.log('query error:' + isErr.message)        res.send({          status: 'fail',          msg: 'query error'        })      } else {        console.log('query success, data is: ' + rst)        res.send({          status: 'success',          data: rst.rows        })      }      client.end()    })  })})
// 插入数据router.post('/insert-data', function (req, res) {  var id = Number(req.body.id)  var name = req.body.name  var region = req.body.region  var date = req.body.date  var delivery = Boolean(req.body.delivery)  var type = req.body.type  var resource = req.body.resource  var desc = req.body.desc  var client = new pg.Client(pgConfig)  client.connect(function (isErr) {    if (isErr) {      console.log('connect error:' + isErr.message)      client.end()      return    }    client.query(      'INSERT INTO "webgis_project_bilibili" ("id", "name", "region", "date", "delivery", "type", "resource", "desc") VALUES ($1, $2, $3, $4, $5, $6, $7, $8);',      [id, name, region, date, delivery, type, resource, desc],      function (isErr, rst) {        if (isErr) {          console.log('query error:' + isErr.message)          res.send({            status: 'fail',            msg: 'insert error'          })        } else {          console.log('insert success, data is: ' + rst)          res.send({            status: 'success',            data: []          })        }        client.end()      }    )  })})
// eslint-disable-next-line no-undefmodule.exports = router

优化 node 目录下的 index.js 文件,在其中配置接口跨域、body数据解析、接口地址等信息:

/* eslint-disable no-undef */// eslint-disable-next-line no-undefvar express = require('express')var app = express()var bodyParser = require('body-parser')
var user = require('./routers/user')
//设置跨域访问app.all('*', function (req, res, next) {  res.header('Access-Control-Allow-Origin', '*')  res.header(    'Access-Control-Allow-Headers',    'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With'  )  res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')  res.header('X-Powered-By', ' 3.2.1')  res.header('Content-Type', 'application/json;charset=utf-8')  next()})
app.use(  bodyParser.urlencoded({    extended: true  }))app.use(bodyParser.json())
app.use('/user', user)
app.get('/', function (req, res) {  res.send('hello world')})
app.listen(3001)

至此,接口开发工作已完成。

DataManage 中数据插入和获取

在 DataManage.vue 组件中,优化完善 onSubmit 方法:

const onSubmit = () => {  const formData = JSON.parse(JSON.stringify(form))  axios    .post(      'http://localhost:3001/user/insert-data',      qs.stringify({        ...formData,        type: formData.type.join(','),        id: new Date().getTime()      })    )    .then((res) => {      openMessage('数据入库成功', 'success')      fetchData()    })    .catch((err) => {      console.error('err', err)      openMessage('数据入库失败', 'error')    })}

每次入库成功后,都需要重新获取一遍数据库中的最新数据,所以需要定义获取数据的方法 fetchData:

function fetchData() {  axios    .get('http://localhost:3001/user/all-data')    .then((res) => {      console.log('res', res)      tableData.value = lodash.map(res?.data?.data, (item) => {        return {          ...item,          region: lodash.find(regionData.value, { value: item.region })?.label,          date: new Date(item.date).toLocaleDateString(),          delivery: item.delivery ? '是' : '否',          type: item.type.split(',').map((type) => {            return lodash.find(typeData.value, { value: type })?.label          }),          resource: lodash.find(resourceData.value, { value: item.resource })?.label        }      })    })    .catch((err) => {      console.error('err', err)    })}
onMounted(() => {  fetchData()})

界面预览如下:

图片[8]-14、WebGIS 从前端到后端:后台接口开发-JieYingAI捷鹰AI

小作业:数据管理支持检索数据

对于 WebGIS 系统中前端和后端开发流程全部介绍完毕,数据管理界面完成了数据插入和获取,但是在数据获取时并没有按条件去筛选,接下来继续优化 GET 接口,使其按接口传参来获取相应的数据,并在界面中增加条件筛选模块。

结语

通过本文的介绍,应该对如何使用 Node.js 开发 WebGIS 系统的后台接口有了基本的了解。从数据库的初始化到后端接口的创建,再到 Vue 项目中的路由配置,每一步都是构建一个高效、可靠的 WebGIS 系统不可或缺的部分。完成小作业可以帮助巩固所学知识,并将其应用到实际的项目开发中。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享