xyz地图服务访问示例:http://192.168.1.240:8081/gmserver/raster/xyz/firstWP:Imagery-raster/{z}/{x}/{y}.jpg
访问示例如下:
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 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 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();
}
}