【MBtiles数据索引和服务发布】GeoServer改造Springboot番外系列二

news2024/11/14 19:54:42

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 {

    @Autowired
    private 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);
        // 异步执行任务,返回一个 CompletableFuture
        CompletableFuture<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();
    }


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1421267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

堆宝塔

L2-1 堆宝塔 分数 25 作者 陈越 单位 浙江大学 堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小&#xff0c;按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。聪明…

第六讲_JavaScript原型

JavaScript原型 1. 原型的概念2. 原型继承2.1 原型链 3. class类的原型对象 1. 原型的概念 原型是 JavaScript 对象相互继承特性的机制。 每个函数都有一个 prototype 属性&#xff0c;这个属性指向一个对象&#xff0c;这个对象称为原型对象。每个对象都有一个 [[Prototype]…

在线mockjson

在线mockjson体验地址 在调一个问题的时候&#xff0c;但是问题的数据可能并不能随着想到的场景就变化&#xff0c;譬如说又个数组长度的情况&#xff0c;可能默认的情况下是返回4个元素&#xff0c;但是想要返回为空的时候&#xff0c;如果联系服务给改一下&#xff0c;那么流…

Pyecharts炫酷热力图:参数详解与实战大揭秘

Pyecharts绘制多种炫酷热力图参数说明代码实战 引言 热力图在数据可视化中是一种强大的工具&#xff0c;可以直观地展示数据的分布情况和变化趋势。Pyecharts是一个基于Echarts的Python可视化库&#xff0c;提供了丰富的图表类型&#xff0c;包括热力图。在本文中&#xff0c…

防御保护---防火墙的NAT-easyip

文章目录 目录 文章目录 点击此处查看NAT技术详解 一.NAT分类 二.防火墙配置 一对多NAT配置 多对多NAT配置 练习 点击此处查看NAT技术详解 一.NAT分类 源IP-NAT(源IP与公网之间转换)&#xff1a;静态NAT&#xff0c;动态NAT&#xff0c;NAPT&#xff1b;使内网能够访问公网目…

Linux网络编程——网络初识

文章目录 1. 网络协议初识1.1 为什么要有网络协议1.2 协议分层 2. OSI七层模型3. TCP/IP五层&#xff08;或四层&#xff09;模型4. 网络传输基本流程5. 以太网通信 1. 网络协议初识 1.1 为什么要有网络协议 早期计算机是独立的&#xff0c;如果要进行数据交互&#xff0c;就…

安装好IntelliJ IDEA点击无反应,如何解决配置文件不一致导致的启动问题

在我们的开发生涯中&#xff0c;遇到IDE工具出现问题是在所难免的。最令人头疼的莫过于&#xff0c;你的IDEA(IntelliJ IDEA)无法启动&#xff0c;而且没有任何错误提示。这篇文章将详细讲解如何解决IntelliJ IDEA 2023.3.3版本启动失败的问题&#xff0c;这个问题可能也适用于…

【已解决】Centos安装不了podman问题(依赖无法安装)

今天安装podman一直安装不了&#xff0c;原因是containernetworking-plugins-1.1.1-1.el7.2.9.x86_64.rpm这个包因为网站的原因下载不了&#xff0c;不管是开启代理还是使用镜像源&#xff0c;都无法解决 最终是手动下载本地后上传至服务器解决&#xff0c;故把文件分享出来避…

【Web前端实操18】粘性定位——即固定顶层内容,可以继续滚动,但是顶层内容固定,不随着一起滚动

粘性定位 1、了解 可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。粘性定位是指网页或移动应用程序中的一种特性,即当用户滚动页面时,某个元素能够保持在屏幕上特定位置不动,直到用户滚动到达一定位置或进行特定操作。这个特性可…

【C++】C++入门—— 引用

引用 1 前情提要2 概念剖析3 引用特性4 常引用5 使用场景5.1做参数5.2 做返回值 6 传值 传引用的效率比较7 引用与指针的差异Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见 1 前情提要 在C语言中&#xff0c;我们往往会遇见复杂的指针&#xff08;如…

tcpdump在手机上的使用

首先手机得root才可以&#xff0c;主要分析手机与手机的通信协议 我使用的是一加9pro&#xff0c; root方法参考一加全能盒子、一加全能工具箱官方网站——大侠阿木 (daxiaamu.com)https://optool.daxiaamu.com/index.php tcpdump&#xff0c;要安装在/data/local/tmp下要arm6…

vite+vue3+ts项目上线docker 配置反向代理API

这次重点的坑是反向代理。 1。项目中配置代理&#xff0c;为了跨域请求数据 项目根目录中新建vite.config.ts文件 在文件中添加配置代理 注意&#xff1a;其中 /api 和target 的地址后面没有 / 2。在项目根目录中新建Httprequest.ts文件&#xff0c;引入axios&#xff0c;并…

矩阵键盘的使用

在定义局部变量时&#xff0c;一定要给该变量赋初值。在这个程序中&#xff0c;给按键按下的返回值变量 KeyNum 赋值为 20 。 矩阵键盘线行扫描法的学习链接&#xff1a;https://www.bilibili.com/video/BV1dv411z7Gd/?spm_id_from333.999.0.0&vd_sourceb91967c499b23106…

推荐系统|概要_基本概念

文章目录 基本概念曝光点击相关指标点击率点赞率/收藏率/转发率阅读完成率总结北极星指标 实验流程 基本概念 曝光 笔记出现在首页&#xff0c;叫作曝光。 点击 用户从笔记表面进入到相关笔记的详情页&#xff0c;叫作一次点击。 除此之外&#xff0c;用户的喜爱&#xff0c…

Mybatis-Plus扩展

7 MybatisX插件[扩展] 7.1 MybatisX插件介绍 MybatisX 是一款基于 IDEA 的快速开发插件&#xff0c;为效率而生。 安装方法&#xff1a;打开 IDEA&#xff0c;进入 File -> Settings -> Plugins -> Browse Repositories&#xff0c;输入 mybatisx 搜索并安装。 功…

基于Springboot的视频网站系统的设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的视频网站系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层…

Java入门高频考查基础知识8(腾讯18问1.5万字参考答案)

刷题专栏&#xff1a;http://t.csdnimg.cn/gvB6r Java 是一种广泛使用的面向对象编程语言&#xff0c;在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性&#xff0c;适用于多种应用场景&#xff0c;包括企业应用、移动应用、嵌入式系统等。 以下是几个面试技巧&…

Prometheus的pod部署

创建命名空间和账户以及集群账户 kubectl create ns monitor-sa kubectl create serviceaccount monitor -n monitor-sa kubectl create clusterrolebinding monitor-clusterrolebinding -n monitor-sa --clusterrolecluster-admin --serviceaccountmonitor-sa:monitor 创建…

电动汽车|不同类型电动汽车充电负荷蒙特卡洛法模拟研究(包括常规充电、快速充电、更换电池)

目录 主要内容 结果一览 常规充电 快速充电 更换电池 详实文档资料 下载链接 主要内容 本程序采用蒙特卡洛模拟了不同类型电动汽车充电负荷特点&#xff0c;包括常规充电、快速充电和更换电池三种。 充放电行为分为无序充电行为、受控充电行为和受控充放电行为…

大专生能不能学习鸿蒙开发?

目前安卓有2,000万的开发者。本科及以上学历占比为35%&#xff1b;iOS有2,400万开发者&#xff0c;本科及以上学历占比为40% 绝大多数的前端开发者都是大专及以下学历&#xff0c;在2023年华为开发者大会上余承东透露华为的开发者目前有200万&#xff0c;但鸿蒙开发者统计的数据…