baidu地图API叠加自定义图层(二)- 使用代理层做缓存

在上文《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已初具功能,期待更多朋友的参与。

你可能感兴趣的:(baidu地图API叠加自定义图层(二)- 使用代理层做缓存)