首先吐槽下GeoServer(其实是GeoWebCache)的切片保存路径竟然如此奇葩,且不可配置,即不能迁移到其他系统,也不能发布其他系统生产的切片(虽然GeoWebCache有对ArcGIS Server切片的插件,但那个东西却无法和GeoServer集成)。这种情况似乎将在下个版本(GeoServer2.17/GeoWebCache1.17)中有所改善,加入了对TMS切片的支持,其切片路径是我们熟悉的{z}/{x}/{y},但这并不能满足我们的需求,首先它是TMS切片,与WMTS切片在y方向相反;其次我们想要的就是随心所欲。
看来短时间内指望GeoServer在这方面有所改观是不太可能了,于是,只好自己来写一个扩展吧,希望可以让GeoServer实现通过配置路径模板的方式来适应其他类型切片,如ArcGIS或者Cesiumlab。
1、首先下载插件(今天才发现,简书竟然不能上传文件,先上传到百度云吧)
链接:https://pan.baidu.com/s/16R5yIxh5Jz32fyi08qCixA
提取码:rn1p
将下载到的custom-filestroe-1.0-SNAPSHOT.jar,放到<geoserver>\webapps\geoserver\WEB-INF\lib中,重启geoserver。
2、配置BlobStore,在Add new BlobStore页面选择Custom FileStore,页面如下。
通过设置路径模板参数来匹配切片路径,如ArcGIS Server的切片路径是这样的:LayerName\L03\R00000002\C00000005.png,那么这里需要这样填写:{layer}\L{level:%02d}\R{row:%08x}\C{col:%08x}
而Cesiumlab切片路径是这样的:LayerName\{z}\{x}\{y}.png,则这里需要这样赶写:{layer}\{level:%d}\{col:%d}\{row:%d}
3、发布切片。在geoserver中的geowebcache.xml文件中添加一个wmsLayer:
<wmsLayer>
<blobStoreId>arcgis</blobStoreId>
<enabled>true</enabled>
<name>33</name>
<mimeFormats>
<string>image/jpeg</string>
</mimeFormats>
<gridSubsets>
<gridSubset>
<gridSetName>EPSG:900913</gridSetName>
<extent>
<coords>
<double>8176078.237521</double>
<double>704818.027536</double>
<double>1.5037685885628E7</double>
<double>7086873.419584</double>
</coords>
</extent>
</gridSubset>
</gridSubsets>
<wmsUrl>
<string>http://localhost:8081/geoserver/wms?</string>
</wmsUrl>
</wmsLayer>
其中,blobStoreId是第二步中所配置的BlobStore的Identifier;name为图层名称;mimeFormats为切片的mineType;gridSubsets配置EPSG和对应的坐标范围。
4、浏览。在GeoServer的Tile Layers页面找到刚刚配置的图层。
在PreView下拉列表中选择对应的EPSG/mineType,跳转到预览页面,如下:
此插件应该能自动匹配大多数切片路径,但像GeoServer这样奇葩的路径,这里不!兼!容!
5、核心代码 :该插件代码非常简单,简单到不好意思将其作为一个项目开源出来,就把其核心代码贴到下面吧:
public File tilePath(TileObject tile, MimeType mimeType) {
final long[] tileIndex = tile.getXYZ();
long x = tileIndex[0];
int z = (int) tileIndex[2];
long y =0;
try {
y = getY(tile.getLayerName(), tile.getGridSetId(), x, tileIndex[1], z);
}catch (GeoWebCacheException e) {
e.printStackTrace();
return null;
}
StringBuilder path =new StringBuilder(256);
String fileExtension = mimeType.getFileExtension();
path.append(cacheRoot);
path.append(File.separatorChar);
String layer = tile.getLayerName();
String[] wl = layer.split(":");
String templatePath ="";
if(wl.length ==2){
templatePath =template.replace("{workspace}",wl[0]);
templatePath =template.replace("{layer}",wl[1]);
}
else{
templatePath =template.replace("{workspace}","");
templatePath =template.replace("{layer}",layer);
}
templatePath = templatePath.replace("{gridset}", tile.getGridSetId());
long shift = z /2;
long half =2 << shift;
int digits =1;
if (half >10) {
digits = (int) (Math.log10(half)) +1;
}
long halfx = x / half;
long halfy = y / half;
templatePath = templatePath.replace("{halfx}",zeroPadder(halfx, digits));
templatePath = templatePath.replace("{halfy}",zeroPadder(halfy, digits));
String levelPattern ="\\{level:([^}]*)\\}";
String levelTemplate = getString(templatePath,levelPattern);
String rowPattern ="\\{row:([^}]*)\\}";
String rowTemplate = getString(templatePath,rowPattern);
String colPattern ="\\{col:([^}]*)\\}";
String colTemplate = getString(templatePath,colPattern);
String level = String.format(levelTemplate, z);
templatePath = templatePath.replace(levelTemplate, level.substring(7,level.length() -1));
String row = String.format(rowTemplate, y);
templatePath = templatePath.replace(rowTemplate, row.substring(5,row.length() -1));
String col = String.format(colTemplate, x);
templatePath = templatePath.replace(colTemplate, col.substring(5,col.length() -1));
path.append(templatePath);
path.append('.');
path.append(fileExtension);
File tileFile =new File(path.toString());
if(!tileFile.exists()){
if(fileExtension.toLowerCase() =="jpeg"){
tileFile =new File(path.toString().replace("jpeg","jpg"));
}
}
return tileFile;
}
本想基于GeoServer2.17版本开发,但2.17版本在BlobStore方面做了比较大的修改,因此只好基于现有版本GeoServer2.16开发。
谨以此篇为自己2019年的工作画一个句号,并恭祝大家2020年万事如意!
网友评论