GeoServer 一鍵釋出 Raster 資料服務(分片上傳、GDAL)
阿新 • • 發佈:2021-10-09
專案中需要上傳影像資料並能檢視。於是想到的思路是:上傳後釋出為 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:\Data\UploadFiles"; //臨時儲存分塊的目錄 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 供呼叫。
點進每一個裡面都是 Swagger 文件
只要具備後端經驗的,檢視該文件毫無壓力。