目录

前言

二、实现步骤

1.postgis数据库和model的绑定

2.将pg库中的要素转换为geojson

(1)几何定义

(2)将wkb解析为几何类型

(3)定义geojson类型

(4)数据转换

(5)数据返回

2.前端传入的geojson储存到数据库

3、其他功能实现

总结


前言

停更了接近一个月都在研究一门新语言golang,以及如何利用golang完成一个webgis后端平台的开发。go语言作为一门强类型语言,在web后端开发中目前有高性能、语法简洁、编译速度快、自带高并发的特性,它既没有C/C++这样有着复杂,冗余的语法,又拥有一些弱类型语言的特性,比如自带垃圾回收机制,自带变量类型判断,关系是golang的打包是所有语言中最为先进的,编译器只会打包引入的代码,而不是像java,python一样会将导入的库整体打包。同样一个项目,用go打包出来可能只有几兆,而用python打包出来会有几十上百兆。其运行速度和Java不相上下,部分计算还快过java,但是占用的内存比java小太多。不得不说golang是一门伟大的语言,大名鼎鼎的容器docker,yarn都是go语言写出来的。

但是golang的缺点也很明显,就是生态不够完善,参考资料太少。很多功能都没有现成的需要自己手写一一实现,并且golang的各种类库的作者也是非常随意,各种变量,函数想改就改,让使用者门非常苦恼,只有按个看源码来学习功能。

这篇文章主要介绍如何用golang结合postgis数据库,使用gin、grom框架实现后端的MVC的接口搭建。


一、整体思路

一个健全的webgis后端必须实现以下几个功能:

1、postgis数据库和model的绑定。

2、如何将pg库中的要素转换为geojson

3、将前端传入的geojson储存到数据库

4、动态矢量瓦片的实现

5、实现地图数据几何分析功能

6、完成各类复杂业务的分析模型

二、实现步骤

1.postgis数据库和model的绑定

参考grom库的官方文档https://gorm.io/zh_CN/docs/create.html

grom是golang对数据库实现orm操作的第三方库,在github上面获得了广泛的好评,目前支持MySQL, PostgreSQL, SQLite, SQL Server 和 TiDB这几种数据库。

首先在项目中创建一个model的包,并在这个包中定义你需要的数据库映射表。我们设计了几个字段,其中geom为几何要素字段,MultiPolygon为几何要素类型,4326为坐标系

package modelstype MyTable struct {ID   uint   `gorm:"primary_key"`Name string `gorm:"type:varchar(255)"`Bh   string `gorm:"type:varchar(255)"`Geom string `gorm:"type:geometry(MultiPolygon,4326)"`
}

创建一个core.go 存储数据库链接信息,创建一个全局变量DB,注意在go中全局变量首字母名必须为大写

package modelsimport ("fmt""gorm.io/driver/postgres""gorm.io/gorm"
)var DB *gorm.DB
var err errorfunc init() {dsn := "host=localhost user=postgres password=1 dbname=gotest port=5432 sslmode=disable TimeZone=Asia/Shanghai"DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})if err != nil {fmt.Println(err)}}

2.将pg库中的要素转换为geojson

(1)几何定义

在pg数据库中,几何信息都是通过wkb格式进行存储,所以我们需要将wkb解析为golang中我们可以操作的几何对象,那么在解析wkb之前我们需要定义好全部的几何要素

1、定义点类型,直接用两位浮点切片定义,如果需要z值就三位,我这里目前只需要二维数据就定义的2维。

type Point [2]float64

2、定义线类型,线类型由点类型组成

type LineString []Point

3、定义环类型,该类型主要在存在环岛面的时候使用,环类型的特点就是起点和终点坐标一致

type Ring LineString

4、定义单面类型,该面由环类型切片构成,我们还可以给在该类型中定义一些简单的几何函数

type Polygon []Ring//判断两个面是否相等
func (p Polygon) Equal(polygon Polygon) bool {if len(p) != len(polygon) {return false}for i := range p {if !p[i].Equal(polygon[i]) {return false}}return true
}//复制面
func (p Polygon) Clone() Polygon {if p == nil {return p}np := make(Polygon, 0, len(p))for _, r := range p {np = append(np, r.Clone())}return np
}

5、定义聚合面MultiPolygon,该要素又面的切片构成

type MultiPolygon []Polygon

6、做一个几何类,整合所有几何要素,在golang中这个被叫做接口

type Geometry interface {GeoJSONType() stringDimensions() intBound() Bound
}

(2)将wkb解析为几何类型

wkb作为一种开源的二进制格式,存储几何信息具备高性能,占用空间小等特点。WKB编码包括两部分:类型及坐标信息, 类型部分用一个字节表示,其中前四位表示几何类型,后四位表示SRID(空间参考系统编号),坐标信息根据不同几何类型分别编码,如点的坐标用x,y两个double类型表示,线的坐标是一系列的点坐标等。以下代码实现了将wkb转换为上面定义的几何要素。因为每个几何类型的解析方式不一样这里我将每种方式单独做成了函数。

func Unmarshal(data []byte) (Geometry, int, error) {order, typ, srid, geomData, err := unmarshalByteOrderType(data)if err != nil {return nil, 0, err}var g Geometryswitch typ {case pointType:g, err = unmarshalPoint(order, geomData)case multiPointType:g, err = unmarshalMultiPoint(order, geomData)case lineStringType:g, err = unmarshalLineString(order, geomData)case multiLineStringType:g, err = unmarshalMultiLineString(order, geomData)case polygonType:g, err = unmarshalPolygon(order, geomData)case multiPolygonType:g, err = unmarshalMultiPolygon(order, geomData)case geometryCollectionType:g, _, err := NewDecoder(bytes.NewReader(data)).Decode()if err == io.EOF || err == io.ErrUnexpectedEOF {return nil, 0, ErrNotWKB}return g, srid, errdefault:return nil, 0, ErrUnsupportedGeometry}if err != nil {return nil, 0, err}return g, srid, nil
}

以下是解析MultiPolygon的代码

func readMultiPolygon(r io.Reader, order byteOrder, buf []byte) (geo.MultiPolygon, error) {num, err := readUint32(r, order, buf[:4])if err != nil {return nil, err}alloc := numif alloc > MaxMultiAlloc {alloc = MaxMultiAlloc}result := make(orb.MultiPolygon, 0, alloc)for i := 0; i < int(num); i++ {pOrder, typ, _, err := readByteOrderType(r, buf)if err != nil {return nil, err}if typ != polygonType {return nil, errors.New("面要素错误")}p, err := readPolygon(r, pOrder, buf)if err != nil {return nil, err}result = append(result, p)}return result, nil
}

(3)定义geojson类型

先定义几种基础的结构体

//定义Feature 结构体
type Feature struct {ID         interface{}  `json:"id,omitempty"`Type       string       `json:"type"`BBox       BBox         `json:"bbox,omitempty"`Geometry   geo.Geometry `json:"geometry"`    //这里为上一步定义的几何类型Properties Properties   `json:"properties"` //这里为空map类型
}//定义FeatureCollection 结构体
type FeatureCollection struct {Type     string     `json:"type"`BBox     BBox       `json:"bbox,omitempty"`Features []*Feature `json:"features"`
}

(4)数据转换

先将grom查询到的数据库对象传递到该函数,通过reflect映射字段,再将字段信息转换为properties的map对象,最后组装geojson返回

func Makegeojson(myTables []models.MyTable) interface{} {var FeaturesList []*geojson.FeatureFeaturesList = []*geojson.Feature{}for _, t := range myTables {properties := make(map[string]interface{})v := reflect.ValueOf(t)tt := reflect.TypeOf(t)for i := 0; i < v.NumField(); i++ {if tt.Field(i).Name != "Geom" {properties[strings.ToLower(tt.Field(i).Name)] = v.Field(i).Interface()}}wkbBytes, _ := hex.DecodeString(strings.Trim(t.Geom, "  "))geom, _ := wkb.Unmarshal(wkbBytes)feature := geojson.NewFeature(geom)feature.Properties = propertiesFeaturesList = append(FeaturesList, feature)}features := geojson.NewFeatureCollection()features.Features = FeaturesListGeoJSON, _ := json.Marshal(features)var obj interface{}json.Unmarshal(GeoJSON, &obj)return obj
}

(5)数据返回

type UserController struct{}func (uc *UserController) OutGeo(c *gin.Context) {name := c.PostForm("name")var mytable []models.MyTableDB := models.DBDB.Where("Name = ?", name).Find(&mytable)data := methods.Makegeojson(mytable)c.JSON(http.StatusOK, data)}

通过postman调接口,数据完美返回geojson

2.前端传入的geojson储存到数据库

这一步其实和取是一样的,只需要把思路反过来,将geojson解析为我们定义的几何结构,然后再将几何结构解析成wkb。直接上代码。

几何要素转换为wkb

func Marshal(geom geo.Geometry, byteOrder ...binary.ByteOrder) ([]byte, error) {buf := bytes.NewBuffer(make([]byte, 0, wkbcommon.GeomLength(geom, false)))e := NewEncoder(buf)if len(byteOrder) > 0 {e.SetByteOrder(byteOrder[0])}err := e.Encode(geom)if err != nil {return nil, err}if buf.Len() == 0 {return nil, nil}return buf.Bytes(), nil
}func GeoJsonToWKB(geo geojson.Feature) string {TempWkb, _ := wkb.Marshal(geo.Geometry)WkbHex := hex.EncodeToString(TempWkb)return WkbHex
}

完成数据存储

func (uc *UserController) InGeo(c *gin.Context) {var jsonData geojson.FeatureCollectionc.BindJSON(&jsonData)DB := models.DBfor _, t := range jsonData.Features {wkb_result := methods.GeoJsonToWKB(*t)DB.Model(models.MyTable{}).Create(map[string]interface{}{"Bh":   t.Properties["bh"],"Name": t.Properties["name"],"geom": clause.Expr{SQL: "ST_GeomFromWKB(decode(?, 'hex'))", Vars: []interface{}{wkb_result}},})}c.JSON(http.StatusOK, "ok")}

至于更新功能也是一样的,几何更新只需要更新geom字段就行了。

3、其他功能实现

动态矢量瓦片直接用go语言重写我之前博客用python做的那部分即可,至于复杂的地理数据分析可以采用postgis函数实现,复杂的业务分析模块可以直接使用golang调用fme实现,这里就不过多介绍,后期博客会更新相关内容。


总结

golang实在是太COOL了,语法简洁,运行高效,部署简单,打包完美,我愿称之为python之后最好用的语言,唯一的缺陷就是生态还有所欠缺,不过随着开发者们的拥护,我相信golang会有光明的未来。

golang实现webgis后端开发相关推荐

  1. 大红大紫的 Golang 真的是后端开发中的万能药吗?

    随着容器编排(Container Orchestration).微服务(Micro Services).云技术(Cloud Technology)等在 IT 行业不断盛行,2009 年诞生于 Goog ...

  2. python后端工程师简历_【社招】字节跳动 - 后端开发工程师( Python Golang)-懂车帝...

    [字节跳动-懂车帝-后端开发工程师] 想加入最有梦想最年轻有活力的团队么,懂车帝研发团队呼唤你!懂车帝今年 3 岁,已经成为发展最快的汽车类资讯平台. 如果你热爱编程,热爱汽车,那么动动手指投出简历吧 ...

  3. 后端开发需要学什么_都2020年了,还在纠结学什么语言?| 后端篇

    几个礼拜前,一个学弟问我: "Ray,我打算之后要找工作了,不过现在自己没有特别深入的语言,最近想找一门好好学一下,你觉得学什么语言好呀?" 我表示:"这个要看你求职方向 ...

  4. golang web php,golang 适合做web开发吗

    使用go语言来做web开发,是非常方便的.如果不使用框架,仅仅使用net/http包,也能快速开发一个web应用.但是,官方包不支持RESTful风格的API,所以我们依然还是需要选择一个框架来帮助我 ...

  5. Swift 后端开发

    原文来自静雅斋,转载请注明出处. 作为一门新兴的现代化语言,Swift 可以说是苹果在开发语言上的一次集大成之作,吸收了很多语言的优点.而且苹果还期望 Swift 能在服务端开发上能发挥作用.更加诱人 ...

  6. 字节跳动-后端开发岗最新春招面经分享,四面拿下,有惊无险

    校招过程中,除了面试前对于基础知识的积累掌握,在面试的长线战斗中,更重要的是去收集面经,从面经中获取到面试的岗位与公司的基本信息,整理与你背景相同的同学在面试中被考察的点,找寻它们之间的规律,当掌握了 ...

  7. 从后端开发转大数据开发怎么样?

    你为什么从后端开发(Java/golang)转到大数据开发(Hadoop/Spark)?转大数据的最初原因很简单,就是好几个同事都转了,他们的收入瞬间提高了好多,于是在同事的内推我也就跟着转了,转完以 ...

  8. 2022编程语言排名, 后端开发语言选型

    文章目录 1 2022 编程语言排名 1.1 IEEE Spectrum 2021年度 1.2 TIOBE指数 2022.05 2 后端开发语言选型 2.1 特点概览 2.2 「PHP 是世界上最好的 ...

  9. Python后端开发(主Django)面试题

    最近两个后端同事离职了,帮忙面试了些后端开发的实习生,虽然有过一些后端经验,但我不是主要写后端的,复习了下Django也稍微准备了一些主要是Django相关的面试题,数据库相关部分额外,没有在此举出, ...

最新文章

  1. cgo linux arm,Golang交叉编译各个平台的二进制文件
  2. waf可以检测哪个端口的流量_锐速云:CC防御过程中,WAF的主要特点有哪些?
  3. Leetcode每日一题:155.min-stack(最小栈)
  4. Jaxb2 转换XML文档
  5. Python 函数式编程,从入门到放弃
  6. android开启前台服务_Android 知识点必知之ANR与OOM
  7. Django框架(三)-- orm增删改查、Django生命周期
  8. css模块化配置---webpack4+less
  9. eclipse设置utf8编码_技术分享 | MySQL 8.0:字符集从 utf8 转换成 utf8mb4
  10. 88.合并两个有序数组(力扣leetcode)博主可答疑该问题
  11. python基础视频课件
  12. Python 正则表达式详解(建议收藏!)
  13. 年底绩效考核,领导让我背「C」
  14. Linux日文教程,【图片】#教程#修正配置 Noto Sans CJK 避免中文显示为异体(日文)字形【linux吧】_百度贴吧...
  15. java3d室外场景构建_3dmax里怎么渲染室外场景
  16. WeiRuan DaBing
  17. Excel表格导入校验
  18. 【nginx读取配置文件http模块】
  19. 6.xp 开机画面【欢迎使用】四个字更改方法:
  20. 请问如何使IE支持有swing的aaplet?

热门文章

  1. 三菱PLC定位模組介紹 PART1 功能簡介
  2. 利用USB摄像头,免费快速搭建浏览器远程监控
  3. 随机数随机性检测工具国密版
  4. 计算机控制系统在地铁应用,浅谈计算机技术在地铁通信系统中的应用
  5. 南京地平线机器人无人驾驶算法面经--已获offer!
  6. 数据结构精品电子书分享之《数据结构》算法实现及解析
  7. Maya插件的十个究极技巧,不会等着老板让你哭
  8. 修复依赖服务器,解决Win10系统依赖服务或组无法启动的五种方法
  9. 全新 ADAS 和自动驾驶车辆系统的处理器性能和安全要求
  10. NySQL 存储过程基本语法及实例