在上文《baidu地图API叠加自定义图层(一)》中基本实现了叠加自定义的图层,本文将继续完善,通过结合《使用代理请求Geoserver服务》一文中实现的代理方式,通过代理层实现自定义图层的本地缓存,减少GIS后台服务端WMS实时渲染的性能损耗,提高地图的交互速度。
为了实现代理层缓存的目的,需要在《使用代理请求Geoserver服务》文中的基础上做出修改,代码参考如下:
//代理层基类
public abstract class GeoserverBaseProxy : IHttpHandler
{
protected abstract string GeoserverUrl
{
get;
}
public void ProcessRequest(HttpContext context)
{
string targetUrl = GeoserverUrl;
if ( PreProcessRequest(context))
{
return;
}
HttpRequest sourceRequest = context.Request;
for (int i = 0, count = sourceRequest.QueryString.Count; i < count; i++)
{
targetUrl += sourceRequest.QueryString.Keys[i] + "=" + sourceRequest.QueryString.Get(i) + "&";
}
HttpWebRequest targetRequest = (HttpWebRequest)WebRequest.Create(targetUrl);
targetRequest.UserAgent = sourceRequest.UserAgent;
targetRequest.ContentType = sourceRequest.ContentType;
targetRequest.Method = sourceRequest.HttpMethod;
if (targetRequest.Method.ToUpper() == "POST")
{
Stream targetInputStream = targetRequest.GetRequestStream();
Stream sourceInputStream = sourceRequest.InputStream;
WriteStream(sourceInputStream, targetInputStream);
}
HttpWebResponse targetResponse = (HttpWebResponse)targetRequest.GetResponse();
ProcessResponse(targetResponse, context);
}
protected void WriteStream(Stream inputStream, Stream outputStream)
{
byte[] buffer = new byte[16 * 1024];
int bufferLength = 16 * 1024;
try
{
int ret = inputStream.Read(buffer, 0, bufferLength);
while (ret > 0)
{
outputStream.Write(buffer, 0, ret);
ret = inputStream.Read(buffer, 0, bufferLength);
}
}
finally
{
inputStream.Close();
}
}
protected virtual bool PreProcessRequest(HttpContext sourceContext)
{
return false;
}
protected virtual void ProcessResponse(HttpWebResponse inputResponse, HttpContext outputContext)
{
HttpResponse outputResponse = outputContext.Response;
outputResponse.ContentType = inputResponse.ContentType;
Stream inputStream = inputResponse.GetResponseStream();
Stream outputStream = outputContext.Response.OutputStream;
WriteStream(inputStream, outputStream);
}
public bool IsReusable
{
get
{
return false;
}
}
}
//代理缓存类:
public class GeoserverWmsCacheProxy : GeoserverBaseProxy
{
private static string _cacheFilePath = @"E:\99 sources\Gis\OpenLayers\DEMO\OpenLayersDemo_v_1_1\OpenLayersDemo\szgas_jd_tiles";
const string __geoserverUrl = "http://localhost:8080/geoserver/szgas/wms?";
protected override bool PreProcessRequest(HttpContext requestContext)
{
bool result = false;
HttpRequest sourceRequest = requestContext.Request;
string z = sourceRequest.QueryString["z"];
string x = sourceRequest.QueryString["x"];
string y = sourceRequest.QueryString["y"];
string tilePath = Path.Combine(_cacheFilePath, z, x + "_" + y + ".png");
if (File.Exists(tilePath))
{
using (FileStream fs = new FileStream(tilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Stream outputStream = requestContext.Response.OutputStream;
WriteStream(fs, outputStream);
}
result = true;
}
return result;
}
protected override void ProcessResponse(HttpWebResponse inputResponse, HttpContext outputContext)
{
HttpRequest request = outputContext.Request;
HttpResponse outputResponse = outputContext.Response;
outputResponse.ContentType = inputResponse.ContentType;
string z = request.QueryString["z"];
string x = request.QueryString["x"];
string y = request.QueryString["y"];
string tileFoldPath = Path.Combine(_cacheFilePath, z);
string tilePath = Path.Combine(tileFoldPath, x + "_" + y + ".png");
if (!Directory.Exists(tileFoldPath))
{
Directory.CreateDirectory(tileFoldPath);
}
byte[] buffer = new byte[16 * 1024];
int bufferLength = 16 * 1024;
using (Stream cacheFileStream = new FileStream(tilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
using (Stream outputStream = outputContext.Response.OutputStream)
{
using (Stream inputStream = inputResponse.GetResponseStream())
{
int ret = inputStream.Read(buffer, 0, bufferLength);
while (ret > 0)
{
cacheFileStream.Write(buffer, 0, ret);
outputStream.Write(buffer, 0, ret);
ret = inputStream.Read(buffer, 0, bufferLength);
}
}
}
}
}
protected override string GeoserverUrl
{
get
{
return __geoserverUrl;
}
}
}
页面代码修改如下,在《baidu地图API叠加自定义图层(一)》的基础上修改一点点,将tileLayer.getTilesUrl 的瓦片路径修改为代理层路径,同时将xyz通过链接发送到后台,后台以xyz缓存瓦片:
if (x < 0) { x = 'M' + (-x); } if (y < 0) { y = 'M' + (-y); } //根据geoserver WMS服务的规则设置URL var url = '/GeoserverWmsCacheProxy.ashx? service=WMS&version=1.1.0&request=GetMap&FORMAT=image/png&layers=szgas:jd_baidu&styles=&width=256&height=256&srs=EPSG:3857&TRANSPARENT=true&bbox=' + bbox2.join(',') + '&z=' + zoom + '&x=' + x + '&y=' + y; return url;
本文只是一个DEMO,使用过程中还应该根据自定义图层的地图范围作出限制,否则会导致缓存的瓦片过多,浪费性能。
推荐
F3Earth是一群志同道合的伙伴发起的国产Web 3D Engine项目,github地址:https://github.com/f3earth/f3earth , 目前正在开发中,DEMO已初具功能,期待更多朋友的参与。