• GeoServer 一键发布 Raster 数据服务(分片上传、GDAL)


    项目中需要上传影像数据并能查看。于是想到的思路是:上传后发布为 GeoServer 服务,再加载地图服务查看。

    要实现该功能用到的技术还是不少的,下面就分别介绍下。

    一、大文件上传

    因为影像文件一般比较大,上传的时候就遇到了问题。

    .net core 官网给出的是用流的方式上传,测试了没有成功。

    最后选择的是分片上传实现的。

    .net core + Vue 分片上传代码如下:

    前端代码:

        customRequest() {
          const url = BASE_API + '/multipartupload'
          const createGuid = function() {
            function S4() {
              return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
            }
            return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
          }
          // element 组件的 upload 绑定的文件,这里改变为正在上传状态,下面设置的上传百分比才有效
          this.uploadFile[0].status = 'uploading'
          this.fileUpload(url, this.uploadFile[0].raw, 0, createGuid())
        },
        // 上传文件,递归调用
        fileUpload(uploadUrl, file, chunk, guid) {
          // const file = option.file
          // 每次上传文件的大小 5M
          const chunkSize = 1024 * 1024 * 5
          // 最大上传大小  默认1000M
          const maxSize = 1024 * 1024 * 1000
          const maxChunk = Math.ceil((file.size / chunkSize))
          const formData = new FormData()
          // 将文件进行分段
          const fileSize = file.size
          if (fileSize > maxSize) {
            this.$message.error('文件大小不能超过1000M')
            return
          }
    
          // 当前上传进度
          const currentPercent = parseInt((chunk / maxChunk) * 100)
          // option.onProgress({ percent: currentPercent })
          formData.append('file', file.slice(chunk * chunkSize, (chunk + 1) * chunkSize))
          formData.append('name', file.name)
          formData.append('chunk', chunk)
          formData.append('maxChunk', maxChunk)
          formData.append('guid', guid)
          this.$request.post(uploadUrl, formData).then(result => {
            if (result.code === 0) {
              // upload 设置上传进度
              this.uploadFile[0].percentage = currentPercent
              if (result.message === '上传中') {
                this.fileUpload(uploadUrl, file, ++chunk, guid)
              } else {
                this.$message.success('文件上传成功')
                this.uploadFile[0].status = 'success'
              }
            } else {
              this.$message.error(result.message)
            }
          })
        }

    后端代码:

            public async Task<ResponseData> MultipartUpload(MultipartUploadDTO multipartUpload)
            {
                string _targetFilePath = @"D:DataUploadFiles";
                //临时保存分块的目录
                var dir = Path.Combine(_targetFilePath, multipartUpload.Guid);
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                //分块文件名为索引名,更严谨一些可以加上是否存在的判断,防止多线程时并发冲突
                var filePath = Path.Combine(dir, multipartUpload.Chunk.ToString());
                //获取文件扩展名
                //var extension = file.FileName.Substring(file.FileName.LastIndexOf(".") + 1, (file.FileName.Length - file.FileName.LastIndexOf(".") - 1));
                var filePathWithFileName = string.Concat(filePath, multipartUpload.Name);
                using (var stream = new FileStream(filePathWithFileName, FileMode.Create))
                {
                    await multipartUpload.Flie.CopyToAsync(stream);
                }
    
                //如果是最后一个分块, 则合并文件
                string message = "上传中";
                string path = "";
                if (multipartUpload.Chunk == multipartUpload.MaxChunk - 1)
                {
                    path = await MergeFileAsync(multipartUpload.Name, multipartUpload.Guid, _targetFilePath);
                    message = "上传完成!";
                }
                return new ResponseData() { Code = 0, Message = message, Data = path };
            }
    
            /// <summary>
            /// 合并分片的文件
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="guid"></param>
            /// <returns></returns>
            private async Task<string> MergeFileAsync(string fileName, string guid,string _targetFilePath)
            {
                //临时文件夹
                string dir = Path.Combine(_targetFilePath, guid);
                //最终的文件名
                string finalName = $"{DateTime.Now:yyyyMMddHHmmssff}{fileName}";
                string finalPath = Path.Combine(_targetFilePath, finalName);
    
                //获得下面的所有文件
                var files = Directory.GetFiles(dir);
                using (var fs = new FileStream(finalPath, FileMode.Create))
                {
                    //排一下序,保证从0-N Write
                    var fileParts = files.OrderBy(x => x.Length).ThenBy(x => x);
                    foreach (var part in fileParts)
                    {
                        var bytes = await File.ReadAllBytesAsync(part);
                        await fs.WriteAsync(bytes, 0, bytes.Length);
                        bytes = null;
                        //删除分块
                        File.Delete(part);
                    }
                    await fs.FlushAsync();
                    fs.Close();
                    //删除临时文件夹和分片文件
                    Directory.Delete(dir);
                }
    
                return finalName;
            }

    主要思路是:把同一个文件分成指定大小字节(byte)分片上传,全部上传后再合并为同一个文件。

    二、.NET Core 调用 GDAL 

    要发布 Raster 服务,需要知道文件的一些基本信息:坐标系、坐标范围等信息。

    GDAL 可以很方便操作 GIS 数据,GDAL 官方给的类库是 C++ 版本。

    要调用的话可以自己下载对应的 dll 进行调用。

    在这里查找到了一个已经封装好的类库,在这里直接调用。

    MaxRev.Gdal.Core

    使用还需要注意几点:

    1、需要的对应运行时:MaxRev.Gdal.LinuxRuntime.Minimal、MaxRev.Gdal.WindowsRuntime.Minimal (根据自己的平台来选择)

    2、使用前初始化配置:GdalBase.ConfigureAll()

    在项目中使用的主要功能有:

    // 读取数据
    Dataset dataset = Gdal.Open(tiffFile, Access.GA_ReadOnly);
    double[] tr = new double[6];
    // 获取 transform 数据
    dataset.GetGeoTransform(tr);
    // 获取 x、y 像素数
    int xSize = dataset.RasterXSize;
    int ySize = dataset.RasterYSize;
    // 获取坐标信息
    string projection = dataset.GetProjection();

    三、GeoServer REST API 使用

    上面的准备工作都已经完成,后面就是要发布对应的 Raster 服务了。

    GeoServer 提供了全部功能的 REST API 供调用。

    官方 REST 文档

    点进每一个里面都是 Swagger 文档

    只要具备后端经验的,查看该文档毫无压力。

  • 相关阅读:
    官方文档翻译-Today
    RAC & MVVM 学习资料整理
    35种常用字体
    中文字体的种类
    自言自语(三)--部分中文字体
    自言自语(二)--英文无衬线体和有衬线体
    sketch字体设置技巧(一)---通过锚点改变字体形态
    提高设计档次的8个方法
    知识汇总09~bootstrap-select在Vue中的封装
    知识汇总08~字符串截取
  • 原文地址:https://www.cnblogs.com/zhurong/p/15384912.html
Copyright © 2020-2023  润新知