之前我們分享過如何 在本地發布OSM矢量瓦片地圖,里面介紹了生成的矢量瓦片會存放在 .mbtiles 文件中,然后用 tileserver-gl 軟件發布。
mbtiles 是基於sqllite數據庫存儲地圖瓦片數據的標准規范,
.mbtiles文件就是實現了這個規范的sqllite數據庫。
最近遇到個相關的問題,項目上需要將這份.mbtiles格式的矢量瓦片部署到客戶服務器上並發布。
之前分享過我在用的 開源GIS解決方案,里面將 postgis、geoserver、tomcat 都搞成了綠色版,並且可以通過批處理腳本將它們一鍵注冊成系統服務,這樣就形成了一個套開源GIS的綠色版安裝包,部署時會很方便。
這套安裝包的整體技術架構是偏 java 的,而這次發布矢量瓦片用到的 tileserver-gl 是基於 nodejs 開發的,按上面的思路,需要將 nodejs 也搞成綠色版的,並且可以使用批處理注冊成系統服務。
因為不想把安裝包搞的太大,也不想用太多的技術體系,讓后期維護變得復雜,所以就想能不能在現有的技術體系下搞定 .mbtiles 發布的問題。
按這個思路,需要去研究有沒有相關的geoserver插件,或是 java 的軟件或項目。
下面是我研究的具體過程,不想看過程的同學可以直接跳到末尾看總結。
geoserver插件
先研究了geoserver插件,還真有。
geoserver有個mbtiles的擴展插件(https://docs.geoserver.org/latest/en/user/community/mbtiles/index.html),支持對.mbtiles文件的讀寫。
geoserver 安裝 mbtiles 插件的教程可以參考這篇:https://blog.csdn.net/dyxcome/article/details/98375453
從官網下載插件,安裝測試后,發現跟想的有點不一樣。
geoserver安裝完插件后,新建數據源的界面多了兩個 mbtiles 相關的選項,如下圖,上面的是發布矢量瓦片,下面的是發布柵格瓦片。

我用第二個紅框,發布柵格瓦片的選項,發布了下矢量瓦片,會報錯。
用第一個紅框,發布矢量瓦片的選項,可以走的通,但就是過程有點曲折,需要把 pbf 中的圖層再挨個發布一遍。

.mbtiles 文件中存的是處理好的 pbf 文件,按說插件只需要根據請求參數,從 sqllite 數據庫中查詢 pbf 文件,返回給前台就 ok 了。
但 geoserver 不是這么做的,它是將 .mbtiles 文件中的 pbf 瓦片作為矢量數據源來使用,類似於讀取 .mdb 文件。
可以推理出,geoserver 內部的處理方式大概是:
- 先將
pbf瓦片拼起來,讀取拼接后的各圖層原始數據 - 把圖層原始數據發布成 geoserver 的矢量瓦片服務
- 前台調用矢量瓦片服務時,geoserver 把數據處理成
pbf文件返回給前台
怎么說呢,這么做和把 pbf 文件直接扔給前台相比,結果是一樣的,但就是感覺 geoserver 的戲太足,內耗太嚴重,還有就是這個發服務的操作過程也很麻煩。
只能說,這個插件針對矢量瓦片的設計,僅是用來讀取原始數據的,不適合用來發布數據。
java項目
再看 java 這邊。
在 github上搜了一下,找到了這個項目:mbtiles4j(https://github.com/jtreml/mbtiles4j)。
是個現成的 java 工程,拉取下來研究了一下,邏輯很簡單,就是直接讀取 mbtiles 中的瓦片返回給前台,這一點很符合要求,美中不足的是,這個項目是針對柵格瓦片的,默認只支持 .png 文件,不支持 .pbf 。
這個好說,有源碼,改改就是了。
改完后發現,前端地圖不顯示,瓦片請求地址報 404 ,
將請求地址中的瓦片編號和 mbtiles 庫中的瓦片編號對了一下,確實沒有。
為啥呢?
哈哈,這個我有經驗,持續關注我們的同學還記不記的,我之前分享過關於 如何讓 maputinik 支持 geoserver 的問題,里面最關鍵的一點就是設置 mapboxgl 請求瓦片的模式 scheme,模式包括 xyz 和 tms,默認使用 xyz 。
難道 openmaptile 生成的這個 mbtiles 文件是按 tms 存儲的?試一下就知道了
果然 ~ 沒那么簡單,地圖還是沒有出來,但瓦片可以請求到了,看來確實是 tms 的。
事后簡單翻了一下 mbtiles 規范,里面有明確寫到,數據源是以 tms 格式來存儲的。
看來還是要多研究標准規范和說明文檔。
但為啥地圖還是沒有出來呢?
對比了下 tileserver-gl(下圖左) 和 mbtiles4j(下圖右) 的返回參數,發現了問題所在。

pbf 文件是采用 gzip 壓縮過的,需要在返回參數中明確告知返回內容的類型是 gzip,而剛才將 mbtiles4j 中的png 改成 pbf 后,沒有加這個設置。
加上試試,哈哈,搞定。

這個通了,剩下的就簡單了,工程編譯成 war 包,直接扔到tomcat下就可以了。
大比例時地圖顯示
本來以為可以收工了,但瀏覽地圖時發現了另一個問題。
我的地圖只切到了14級,因為在矢量瓦片中,14級包含的內容就已經很細了,所以沒有必要再往下切。
但用地圖瀏覽時,超過14級后,因為后台沒有對應的瓦片,前台就請求不到數據,地圖就不顯示了。
用 tileserver-gl 發布同樣的 mbtiles 文件,再用它的默認地圖查看器瀏覽地圖,就沒有這個問題。
看來后台需要把超過14級的請求參數處理一下,超過14級時,直接返回14級的瓦片。
翻了翻 tileserver-gl 的代碼,並沒有找到相關的邏輯。
在同事的提醒下,發現 tileserver-gl 的默認地圖查看器,它的前台請求在超過14級時,是按14級來請求的,這說明我要找的邏輯是在前台完成的。
去翻 tileserver-gl 的地圖樣式配置,和我自己的配置對比后發現,對數據源設置 maxzoom 就可以解決這個問題。

看一下官網的解釋,大概意思是,如果你設置maxzoom=14,那么當地圖縮放超過14級時,地圖仍然會使用14級的瓦片。

這個設置正是我要的。
我把改完后的后台代碼上傳到了github,方便以后遇到同樣問題的同學使用。
源碼:
地址:http://gisarmory.xyz/blog/index.html?source=OSMMbtiles
總結:
-
本地發布的OSM矢量瓦片地圖,生成的矢量瓦片存放在 mbtiles 文件中
-
發布mbtiles 中的矢量瓦片,目前主流的方式是 tileserver-gl ,它基於nodejs開發的
-
geoserver有個讀取 mbtiles 的插件,但它針對矢量瓦片的設計是用來讀取 pbf 中原始數據的,不適合用來發布數據。
-
github上有個 mbtiles4j 的項目,java 開發的,稍加修改后,可以用來直接發布 mbtiles
-
mapboxgl 使用發布的地圖瓦片時,需要設置數據源的 maxzoom 屬性。
原文地址:http://gisarmory.xyz/blog/index.html?blog=OSMMbtiles。
關注《GIS兵器庫》公眾號, 第一時間獲得更多高質量GIS文章。

本文章采用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名《GIS兵器庫》(包含鏈接: http://gisarmory.xyz/blog/),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。
