使用GeoServer+OpenStreetMap搭建地图服务
使用GeoServer+OpenStreetMap搭建地图服务
一、背景
因为业务的需要,需要提供纯离线版本的全球地图。在这种情况下,全球地图的数据来源自然是来自OpenStreetMap,地图服务则采用GeoServer。
GeoServer是一款开放的地图服务,支持多种数据源,也支持自定义各类样式。
我不太喜欢暗色系,因此比较喜欢的明亮系的,于是其中样式和数据依赖geosolutions-it/osm-styles,然后在此基于上Fork了一份代码,做了一些优化:wuliang142857/osm-styles。
二、具体步骤
2.1 使用imposm3导入OpenStreetMap数据到PostgreSQL中
imposm3 是一款使用Go编写的将OpenStreetMap的PBF文件导入到PostgreSQL/PostGIS的工具。它官方提供了Linux已经预编译好的Linux可执行二进制文件。只要你的glibc版本不是太低的话,直接使用就行。

如果不幸你的Linux/glibc比较低,那么只能自己编译。如果自己编译的话,它依赖 libleveldb 和 libgeos ,因此得先编译安装这两个库。
对OpenStreetMap的PBF文件的导入比较简单,一个命令搞定:
imposm import -mapping <mapping.yml文件路径> -connection postgis://<username>:<password>@<hostname>:<port>/<dbname> -dbschema-import <schema_name> -overwritecache -read <PBF文件> -write -cachedir <缓存路径> -optimize
上述命令中有一些参数需要解释一下:
mapping.yml文件路径
:这个文件定义了OpenStreetMap (OSM) 数据映射到 PostGIS 数据库中的表结构。username
、password
、hostname
、port
、dbname
、schema_name
:这些都是PostgreSQL的基本信息。这里唯一需要注意的就是DB需要用户手动创建好,imposm会自动创建schema,但不会自己创建DB。缓存路径
:这个就一个路径也有,默认值是:/tmp/imposm3
-optimize
:开启这个参数的话,会对最终导入的数据的索引做优化(具体优化就是Clustering
和Analyse
)
因为我们这里是为了把GeoServer+OpenStreetMap快速应用起来,因此先不探究mapping.yml
具体怎么写,可以先用一个现成的:geosolutions-it/osm-styles中的mapping.yml就比较适合,可以直接拿来使用。
PS:
geosolutions-it/osm-styles是一个比较实用的GeoServer的数据目录集,可以clone下来,后面我们还得用上。
geosolutions-it/osm-styles中的mapping.yml算是比较完整的mapping文件了,但我实测时它漏掉了OpenStreetMap中的某些amenity,因此如果希望能够支持所有amenity的话,得自己稍微修改一下。
刚上手的话,不建议直接来个
planet.osm.pbf
,太大了,可以先搞一个国家、甚至更小省、市试试。
2.2 下载GeoServer并且解压
从[GeoServer][https://geoserver.org/release/stable/]下载稳定版,因为我本地环境没有tomcat之类的环境,因此直接 Platform Independent Binary:

解压:
unzip geoserver-x.y.z-bin.zip -d geoserver
另外,还需要两个插件:
- Pregeneralized Features:处理预先生成的简化矢量数据(generalized data),以提高地图服务的性能。因为我们待会会有一个预制的低缩放的OSM地图数据需要加载,因此需要这个插件。
- CSS Styling:允许用户使用类似于网页 CSS 的语法来编写样式(SLD),简化了样式的配置过程。比如当我们自定义一些POI数据的图标等,采用CSS的方式会简单很多。

两个插件下载下来后,解压到geoserver的webapps/geoserver/WEB-INF/lib/
目录下:
unzip geoserver-x.y.z-feature-pregeneralized-plugin.zip -d <geoserver的路径>/webapps/geoserver/WEB-INF/lib/
unzip geoserver-x.y.z-css-plugin.zip -d <geoserver的路径>/webapps/geoserver/WEB-INF/lib/
2.3 使用geosolutions-it/osm-styles提供的数据
正如前文所言,geosolutions-it/osm-styles是一个比较实用的GeoServer的数据目录集。我们将geosolutions-it/osm-styles下除了imposm外的所有文件/目录都拷贝到geoserver下的data_dir
目录下。
2.4 安装字体
因为OSM数据包含多国语言,因此需要安装多个国家的字体。在基于Debian的系统上可以:
apt install fonts-noto fonts-dejavu unifont fonts-hanazono fonts-noto-cjk fonts-noto-extra fonts-noto-color-emoji fonts-dejavu-core fonts-liberation fonts-arphic-ukai fonts-arphic-uming fonts-indic fonts-thai-tlwg ttf-mscorefonts-installer fonts-dejavu fontconfig
2.5 下载OSM下的低缩放的数据
下载:osm-lowres.gpkg 到 geoserver下的data_dir/data
目录下。
2.6 启动GeoServer进行进一步的配置
首先,GeoSever是用Java编写的服务,因此运行依赖JRE,最低要求:JAVA 11。
现在,可以启动GeoServer了,启动命令很简单:
./bin/startup.sh
如果需要关闭就:
./bin/shutdown.sh
启动过程中出现的类似missing style的ERROR日志可以暂且忽略:
24 Oct 14:53:46 ERROR [org.geoserver] - Layer 'poly_landmarks' references a missing style
24 Oct 14:53:46 ERROR [org.geoserver] - Layer 'tiger_roads' references a missing style
24 Oct 14:53:46 ERROR [org.geoserver] - Layer 'poi' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'states' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'countries' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'coastlines' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'populated_places' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'boundary_lines' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'streams' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'roads' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'restricted' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'bugsites' references a missing style
24 Oct 14:53:47 ERROR [org.geoserver] - Layer 'Arc_Sample' references a missing style
24 Oct 14:53:48 WARN [gce.imagemosaic] - Unable to set ordering between tiff readers spi
启动后,默认监听端口是:8080。
访问http://<hostname or ip>:<port>/geoserver
,默认的用户名:admin,密码:geoserver。
下面需要配置一下数据库连接信息:存储仓库 -> osm

连接参数都需要填写:

2.7 预览OSM地图
下面就预览一下:

在新打开的窗口上就可以看到预览的地图了:

当然也可以自己写一个demo页面:
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /* 防止滚动条影响布局 */
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://<主机+端口>/geoserver/osm/wms',
params: {
'LAYERS': 'osm:osm',
'VERSION': '1.3.0', // 使用 WMS 1.3.0 版本
'FORMAT': 'image/png', // 输出格式
'TRANSPARENT': 'true' // 背景透明
},
ratio: 1,
serverType: 'geoserver',
})
})
],
view: new ol.View({
center: ol.proj.fromLonLat([120.1551, 30.2741]),
zoom: 10
})
});
</script>
</body>
</html>
三、小技巧
3.1 自己编译imposm3
正如上文所言,假如你的Linux或者Glibc版本比较低,官方预编译的可执行二进制的imposm3不能运行:

那么,只能自己编译了。这里我以CentOS 7 为例。
CentOS 7的GCC和Libc版本都比较低,因此我们先安装较新版本的GCC:
# 新增scl源
yum install centos-release-scl centos-release-scl-rh
# 安装gcc-10和较新的git
yum install devtoolset-10-* rh-git227-git
# 激活使用
source /opt/rh/devtoolset-10/enable
imposm3依赖leveldb和libgeos。这两个都是cmake工程,编译&安装很简单。
然后clone imposm3代码,直接make build
就可以。
3.2 支持所有type
在地图上,很多POI信息都会被渲染成“图标+文字”的形式:

但我们使用geosolutions-it/osm-styles相比OpenStreetMap完整的amenity、Symbols,还是确实了不少的。要补充完整的话,得改两个地方:
(1)mapping.yml文件中tables -> amenities -> type_mappings -> points
下的所有类型都改成__any__
:
type_mappings:
points:
aeroway:
- __any__
tourism:
- __any__
amenity:
- __any__
shop:
- __any__
leisure:
- __any__
man_made:
- __any__
natural:
- __any__
historic:
- __any__
highway:
- __any__
power:
- __any__
(2)样式补充:进入 样式 ,找到 amenities:

修改其中的样式(内容比较长,可以复制出来修改):可以找一个已有的type
然后照着修改。

3.3 优化字体
采用geosolutions-it/osm-styles提供的样式后,发现在关于字体上有两个问题:
- 朝鲜/韩国字体没有显示出来,全成了方框。我不太确定其他国家的字体有没有类似的问题,朝鲜/韩国那是很明显。

- 自定义的
type
显示的字体太小
这两个的解决办法:
- 问题一:针对朝韩字体,问题在于geosolutions-it/osm-styles中关于朝韩文字的
font-family
配置的是:Noto Sans CJK KR Regular
,我们需要改成:Noto Sans CJK KR
:
cd data_dir/workspaces/osm/styles
# 对所有SLD文件进行替换
grep -rnil "font-family" *.sld|xargs grep -li "Noto Sans CJK KR"|xargs sed -s -i 's#<sld:CssParameter name="font-family">Noto Sans CJK KR Regular</sld:CssParameter>#<CssParameter name="font-family">Noto Sans CJK KR</CssParameter>#g'
# 对所有CSS文件进行替换
grep -rnil "font-family" *.css|xargs grep -il 'Noto Sans CJK KR'|xargs sed -s -i 's#Noto Sans CJK KR Regular#Noto Sans CJK KR#g'
- 问题二:针对自定义的
type
显示的字体太小,一个比较简单的办法是加入font-family
的定义,比如:
[type = 'weighbridge'][@sd < 6k] {
label: [name];
font-family: "Microsoft YaHei", "Noto Sans", "DejaVu Sans", "Arial", "Arphic Ukai", "MingLiU", sans-serif;
font-fill: #734a08;
halo-color: #ffffff;
label-offset: 0 -12;
};
[type = 'weighbridge'][@sd < 6k] {
shield: symbol('file://new/weighbridge.svg');
:shield { fill: #734a08 };
};
注意:这个font-family
的定义貌似必须在font-fill
之前,不然就不生效。此外,可以自己把类似微软雅黑的字体注册到系统中,然后采用微软雅黑,这个比较好看。
