【MBtiles数据索引和服务发布】GeoServer改造Springboot番外系列二
xyz地图服务访问示例:http://192.168.1.240:8081/gmserver/raster/xyz/firstWP:Imagery-raster/{z}/{x}/{y}.jpg
访问示例如下:

mbtiles目录结构
根据z,x,y获取对应mbtiles文件路径的工具方法
说明:重点是使用getMbtilesPath方法,通过xyz获取mbtiles文件路径。
getTilesFile方法是通过图层(因为我做的项目是mbtiles数据集绑定在图层上)获取对应的mbtiles文件。
package com.gs.springboot.gmserver.util;import com.gs.springboot.gmserver.core.CommonConstants;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.StoreInfo;import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;/*** @Desc mbtiles工具类*/
public class MbtilesUtil {/*** 根据zxy索引mbtiles文件所在目录** @param z 层级* @param x 行* @param y 列* @param rootPath mbtiles根目录* @return java.lang.String*/public static String getMbtilesPath(int z, int x, int y, String rootPath) {int p = 0;//文件级别的列号int q = 0;//文件级别的行号int m = 0;//文件夹级别的列号int n = 0;//文件夹级别的行号if (z <= 8) {p = 0;q = 0;m = 0;n = 0;} else if (z >= 9) {double fileTotal = Math.pow(2, 2 * (z - 8));//文件总数double tileTotal = 65536 * fileTotal;//瓦片总数double maxTileNum = Math.sqrt(tileTotal);//行和列坐标轴方向的瓦片个数,行列相等double segmentNum = Math.sqrt(fileTotal);//行和列分的段数,即行和列坐标轴方向的mbtiles文件个数double tileNumOfEachMbtiles = maxTileNum / segmentNum;//单个mbtiles的最大行列的瓦片数,行列瓦片数相等p = (int) (x / tileNumOfEachMbtiles);q = (int) (y / tileNumOfEachMbtiles);if (z == 9 || z == 10) {m = 0;n = 0;} else {double dirTotal = fileTotal / 16;//文件夹总数double segmentDirNum = Math.sqrt(dirTotal);//行和列坐标轴方向的最大文件夹个数,行列相等double tileNumOfEachDir = segmentNum / segmentDirNum;//每段文件夹内的mbtiles的个数m = (int) (p / tileNumOfEachDir);n = (int) (q / tileNumOfEachDir);}}String mbtiles_file = rootPath + "/" + z + "/" + m + "_" + n + "/" + z + "_" + p + "_" + q + ".mbtiles";return mbtiles_file;}/*** 通过图层信息索引瓦片对应文件* @param layerInfo 图层* @param tilecol 列x* @param tilerow 行y* @param z 层级z* @param format 后缀* @return java.io.File*/public static File getTilesFile(LayerInfo layerInfo, int tilecol, int tilerow, Integer z, String format) {StoreInfo store = layerInfo.getResource().getStore();String type = store.getType();File file = null;Map<String, Serializable> connectionParameters = store.getConnectionParameters();for (String key : connectionParameters.keySet()) {if (key.contains("filePath")) {Serializable value = connectionParameters.get(key);String rootPath = (String) value;String tilesPath = null;if (type.equals(CommonConstants.DataStoreType.TilesFolderRaster.getValue())|| type.equals(CommonConstants.DataStoreType.TilesFolderVector.getValue())|| type.equals(CommonConstants.DataStoreType.TilesFolderDEM_terrain.getValue())) {tilesPath = rootPath + "/" + z + "/" + tilecol + "/" + tilerow + "." + format;} else if (type.equals(CommonConstants.DataStoreType.TilesFolderDEM_png.getValue())) {tilesPath = rootPath + "/" + z + "/" + tilecol + "/" + tilerow + ".png";}else if (type.equals(CommonConstants.DataStoreType.MbtilesFolderRaster.getValue())|| type.equals(CommonConstants.DataStoreType.MbtilesFolderVector.getValue())|| type.equals(CommonConstants.DataStoreType.MbtilesFolderDEM.getValue())) {tilesPath = getMbtilesPath(z, tilecol, tilerow, rootPath);}file = new File(tilesPath);if (file.exists() && file.length() > 0) {break;}}}return file;}}
发布mbtiles地图服务的接口。
说明:此处由于是项目的完整功能,所以代码是通过图层名称获取mbtiles的文件,你也可以将layer直接换成mbtiles数据集的根目录,或者直接写死根目录。通过xyz就可以访问瓦片。
package com.gs.springboot.gmserver.tiles;import cn.hutool.core.io.file.FileNameUtil;
import com.gs.springboot.gmserver.core.CommonConstants;
import com.gs.springboot.gmserver.util.MbtilesUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.StoreInfo;
import org.imintel.mbtiles4j.MBTilesReadException;
import org.imintel.mbtiles4j.MBTilesReader;
import org.imintel.mbtiles4j.Tile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.concurrent.CompletableFuture;@RestController
@Api(tags = "栅格瓦片服务发布接口")
public class RasterTilesController {@Autowiredprivate Catalog catalog;@GetMapping("/raster/xyz/{layer}/{z}/{x}/{y}.{format}")@ApiOperation(value = "发布栅格Mbtiles文件夹数据XYZ服务")@ApiImplicitParams({@ApiImplicitParam(name = "layer", value = "图层名称", dataType = "String", paramType = "path"),@ApiImplicitParam(name = "z", value = "z坐标", dataType = "int", paramType = "path"),@ApiImplicitParam(name = "x", value = "x坐标", dataType = "int", paramType = "path"),@ApiImplicitParam(name = "y", value = "y坐标", dataType = "int", paramType = "path"),@ApiImplicitParam(name = "format", value = "格式", dataType = "String", paramType = "path")})public void publishXYZ(@PathVariable("layer") String layer,@PathVariable("z") int z,@PathVariable("x") int x,@PathVariable("y") int y,@PathVariable("format") String format,HttpServletResponse response) {LayerInfo layerInfo = catalog.getLayerByName(layer);StoreInfo store = layerInfo.getResource().getStore();if (store.getConnectionParameters().get("scheme") != null) {String scheme = (String) store.getConnectionParameters().get("scheme");if (!CommonConstants.DataStoreScheme.XYZ.getValue().equals(scheme)) {y = (1 << z) - y - 1;//此处是将xyz转tms}}extracted(layerInfo, z, x, y, format, response);}private void extracted(LayerInfo layerInfo, int z, int x, int y, String format, HttpServletResponse response) {File file = MbtilesUtil.getTilesFile(layerInfo, x, y, z, format);String prefix = FileNameUtil.getSuffix(file);// 异步执行任务,返回一个 CompletableFutureCompletableFuture<Void> future = CompletableFuture.runAsync(() -> {InputStream data = null;if ("mbtiles".equals(prefix)) {MBTilesReader r = null;Tile tile;try {r = new MBTilesReader(file);tile = r.getTile(z, x, y);} catch (MBTilesReadException e) {throw new RuntimeException(e);}data = tile.getData();} try {if ("png".equals(format) || "jpg".equals(format)) {response.setContentType("image/" + format);} else {response.setStatus(400);return;}ServletOutputStream oStream = response.getOutputStream();IOUtils.copy(data, oStream);oStream.flush();oStream.close();} catch (IOException e) {throw new RuntimeException(e);}});// 等待 CompletableFuture 完成future.join();}}
相关文章:
【MBtiles数据索引和服务发布】GeoServer改造Springboot番外系列二
xyz地图服务访问示例:http://192.168.1.240:8081/gmserver/raster/xyz/firstWP:Imagery-raster/{z}/{x}/{y}.jpg 访问示例如下: mbtiles目录结构 根据z,x,y获取对应mbtiles文件路径的工具方法 说明:重点是使用getMb…...
Redis抓取数据到Logstash再推到Elasticsearch集群
一、安装Logstash 前面安装过Logstash了,不做解释直接跳过 参考:上一篇文章 二、配置Logstash 在logstash目录下,编辑我们之前的配置文件logstash.conf vim logstash.confinput、output字面意思,从redis去拿取数据,输出到Elasticsearch data_type:数据类型为list k…...
【代码随想录-链表】反转链表
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…...
32GPIO输入LED闪烁蜂鸣器
一.GPIO简介 所有的GPIO都挂载到APB2上,每个GPIO有16个引脚 内核可以通过APB2对寄存器进行读写,寄存器都是32位的,但每个引脚端口只有16位 驱动器用于增加信号的驱动能力 二.具体…...
Qt|QPushButton控件讲解
前提 按钮分为了四种状态:常态、聚焦、按下、禁用 前一段时间更新了MFC框架下CButton的自绘。因为MFC框架下的按钮限制性很高,所以只能由自绘实现各种风格,但是QT框架完美的解决了这个问题,我们只需要了解如何调用,就…...
再学webpack
1 优化 webpack 打包体积的思路 优化 webpack 打包体积的思路包括: 提取第三方库或通过引用外部文件的方式引入第三方库:将第三方库单独打包,并通过 CDN 引入,减少打包体积。使用代码压缩插件:例如 UglifyJsPlugin&a…...
systemd:service与target使用及相关命令
文章目录 一、 unit1.1 unit常用命令 二、 service系统服务2.1 unit service配置文件2.1.1 [Unit]区块2.1.2 [Service]区块2.1.3 [Install]区块2.1.4 示例介绍 2.2 service常用命令 三、target3.1 tartget有关命令 四、其他系统命令4.1 systemctl 相关系统管理命令4.2 journalc…...
FairGuard游戏加固入选《CCSIP 2023中国网络安全行业全景册(第六版)》
2024年1月24日, FreeBuf咨询正式发布《CCSIP 2023中国网络安全行业全景册(第六版)》。本次发布的全景图,共计展示20个一级分类、108个细分安全领域,旨在为广大企业提供网络安全产品选型参考,帮助企业了解中国网络安全技术与市场的…...
文心一言 VS ChatGPT :谁是更好的选择?
前言 目前各种大模型、人工智能相关内容覆盖了朋友圈已经各种媒体平台,对于Ai目前来看只能说各有千秋。GPT的算法迭代是最先进的,但是它毕竟属于国外产品,有着网络限制、注册限制、会员费高昂等弊端,难以让国内用户享受。文心一言…...
七街八巷×实在RPA丨财务凭证录入零出错,效率提升8倍
在如今的数字化时代,企业财务面临着海量且复杂的数据流程。特别是在凭证录入这一看似简单却又频繁的环节中,传统的手工操作已无法满足日益增长的业务需求。 中国轻食知名品牌七街八巷,通过部署实在智能集“自动化平台开箱即用解决方案咨询”…...
线性代数----------学习记录
线性代数发展历程 (1)线性方程组:例如二元一次方程组; (2)行列式:determinant,克莱默,莱布尼兹; (3)矩阵:方程个数与未知数的个数可…...
Ubuntu如何安装使用Nginx反向代理?
在Ubuntu上安装Nginx并配置使其生效是相对简单的过程。以下是一步一步的指南: 步骤 1:安装 Nginx 打开终端,并执行以下命令来安装 Nginx: sudo apt update sudo apt install nginx步骤 2:启动 Nginx 服务 安装完成…...
Linux系统——正则表达式
有一段时间本机访问量过高,如何查看日志提取出访问量前十的信息 1.使用提取命令(cut、awk、sed)提取出ip地址的那一列 2.使用sort按数字排序,将相同的地址整合到一起 3.使用uniq -c统计出数量 4.使用sort 数字 数字倒序排序 5.最…...
【文本到上下文 #9】NLP中的BERT和迁移学习
一、说明 BERT:适合所有人的架构概述:我们将分解 BERT 的核心组件,解释该模型如何改变机器理解人类语言的方式,以及为什么它比以前的模型有重大进步。 BERT的变体: 在BERT取得成功之后,已…...
github单文件下载——DownGit
记录一下一个好用的网站,支持github中某一特定文件夹下文件的下载 选择一个合适的梯子,访问Downgit网址 https://minhaskamal.github.io/DownGit/#/home 将所需网站连接粘贴到这里,点击download即可...
Java之Stream的应用与原理分析
前言 stream是怎么做到一次迭代中将所有流操作进行叠加?stream怎么做到只有在终止操作时进行元素遍历?那中间操作是做了些什么? Stream 与集合的区别 集合是内存中的数据结构抽象,描述了数据在内存中是如何存储的。流描述了对数据…...
Git 实战场景过程(工作总结篇)
目录 前言1. Git远程仓库建立分支,本地未显示1.1 问题所示1.2 知识补充 2. Git暂存内容切换分支2.1 问题所示2.2 知识补充 3. Git放弃修改数据3.1 问题所示3.2 知识补充 前言 主要总结工作中的疑惑点,如果你也有相应的场景,可以评论区见&…...
iperf3 打流工具的使用介绍
目录 1. iperf3简介 2. 详细命令参数 1. iperf3简介 iPerf3是用于主动测试IP网络上最大可用带宽的工具。它支持时序、缓冲区、协议(TCP,UDP,SCTP与IPv4和IPv6)有关的各种参数。对于每次测试,它都会详细的带宽报告&a…...
网络异常案例一_RST
本文以及后面几篇会整理输出下以前处理过的一些网络相关的异常 4G定向卡上网问题 问题现象,自研路由器,使用运营商定向的4G卡上网,访问服务器异常,相应的开发同学反馈被服务器拒绝了; 复现问题,同步在cli…...
提升工作效率,畅享便捷PDF编辑体验——Adobe Acrobat Pro DC 2023
作为全球领先的PDF编辑软件,Adobe Acrobat Pro DC 2023将为您带来前所未有的PDF编辑体验。无论您是个人用户还是企业用户,Adobe Acrobat Pro DC 2023将成为您提高工作效率、简化工作流程的得力助手。 一、全面编辑功能 Adobe Acrobat Pro DC 2023提供了…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
