C# 自動化發佈GeoServer之NetCDF

来源:https://www.cnblogs.com/JessieR/archive/2023/02/23/17147851.html
-Advertisement-
Play Games

最近新接觸了GeoServer,從零開始的研究也是折磨了好幾天,發現GeoServer這塊很多大佬分享各種解決方案,也是幫了我大忙,剛好告一個段落了,所以也貢獻一下我這幾天的研究成果,希望能幫到大家。 目標:使用GeoServer自動化發佈NetCDF文件,實現部署在Linux上自動化更新圖層 環境 ...


最近新接觸了GeoServer,從零開始的研究也是折磨了好幾天,發現GeoServer這塊很多大佬分享各種解決方案,也是幫了我大忙,剛好告一個段落了,所以也貢獻一下我這幾天的研究成果,希望能幫到大家。

目標:使用GeoServer自動化發佈NetCDF文件,實現部署在Linux上自動化更新圖層

環境:.net6.0,GeoServer 2.21,Linux

先看一下目錄結構:

 

 

 AbstracPublishHandler抽象類中寫整體的處理方法,主要是對柵格文件處理的固定流程

 

附上源碼:

  1 using System.Runtime.InteropServices;
  2 
  3 namespace ReservoirModelAnalysis.Module.GeoServicePublish.Common
  4 {
  5     /// <summary>
  6     /// 發佈抽象類
  7     /// </summary>
  8     public abstract class AbstracPublishHandler
  9     {
 10         /// <summary>
 11         /// 測試的時候使用cmd命令,部署在linux伺服器上的時候使用shell命令
 12         /// </summary>
 13         private Func<string, string> processCommand = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ProcessHandler.CmdProcess : ProcessHandler.ShellProcess;
 14 
 15         /// <summary>
 16         /// 數據倉庫配置
 17         /// </summary>
 18         IDataTypeConfig dataTypeConfig;
 19         /// <summary>
 20         /// 發佈處理
 21         /// 1.先判斷數據倉庫是否存在,不存在直接進行第三步
 22         /// 2.更新數據倉庫,並且流程結束
 23         /// 3.發佈新的數據倉庫
 24         /// 4.發佈指定的圖層
 25         /// 5.圖層綁定已發佈好的樣式
 26         /// </summary>
 27         /// <param name="config">數據倉庫類型配置</param>
 28         /// <param name="path">文件路由</param>
 29         public void Handling(IDataTypeConfig config, string path)
 30         {
 31             dataTypeConfig = config;
 32             Console.WriteLine($"{DateTime.Now}:GeoServer發佈準備開始!");
 33 
 34             if (getCoverageStorebyName())
 35             {
 36                 //倉庫存在
 37                 UpdateCoverageStore(path);
 38             }
 39             else
 40             {
 41                 //倉庫不存在
 42 
 43                 //發佈柵格存儲
 44                 PublishCoverageStore(path);
 45 
 46                 //發佈指定圖層
 47                 PublishCoverages();
 48 
 49                 //綁定樣式
 50                 SetLayerStyle();
 51 
 52             }
 53 
 54             Console.WriteLine($"{DateTime.Now}:GeoServer發佈完成!");
 55         }
 56 
 57         /// <summary>
 58         /// 獲取指定類型的數據倉庫名稱
 59         /// </summary>
 60         /// <returns></returns>
 61         private bool getCoverageStorebyName()
 62         {
 63             string url = $"{GeoServerConfig.GeoServerUrl}/workspaces/{dataTypeConfig.WorkSpaceName}/coveragestores/{dataTypeConfig.StoreName}.json";
 64             string cmd = $"curl -v -u {GeoServerConfig.User}:{GeoServerConfig.Password} -XGET {url}";
 65 
 66             var result = processCommand.Invoke(cmd);
 67             Console.WriteLine($"判斷是否有指定的數據倉庫:\n【{result}】");
 68 
 69             //簡單的判斷一下,內容不為nosuch的情況還有可能報其他錯
 70             return !(result.IndexOf("No such") > -1);
 71         }
 72 
 73         /// <summary>
 74         /// 發佈一個柵格數據存儲
 75         /// </summary>
 76         /// <param name="path">柵格文件路徑 使用//分割</param>
 77         /// <returns></returns>
 78         protected bool PublishCoverageStore(string path)
 79         {
 80             string xml = $"<coverageStore><name>{dataTypeConfig.StoreName}</name><type>NetCDF</type><enabled>true</enabled><workspace><name>{dataTypeConfig.WorkSpaceName}</name></workspace><__default>false</__default><url>file://{path}</url></coverageStore>";
 81             string cmd = $"curl -v -u {GeoServerConfig.User}:{GeoServerConfig.Password} -XPOST -H \"Content-type: text/xml\" -d \"{xml}\" {GeoServerConfig.GeoServerUrl}/workspaces/{dataTypeConfig.WorkSpaceName}/coveragestores";
 82 
 83             var result = processCommand.Invoke(cmd);
 84 
 85             Console.WriteLine($"發佈柵格存儲結果:\n【{result}】");
 86 
 87             return true;
 88         }
 89 
 90         /// <summary>
 91         /// 發佈圖層
 92         /// </summary>
 93         /// <returns></returns>
 94         protected bool PublishCoverages()
 95         {
 96             dataTypeConfig.LayerList.ForEach(layerName =>
 97             {
 98                 string xml = $"<coverage><nativeCoverageName>{layerName}</nativeCoverageName><name>{layerName}</name></coverage>";
 99                 string url = $"{GeoServerConfig.GeoServerUrl}/workspaces/{dataTypeConfig.WorkSpaceName}/coveragestores/{dataTypeConfig.StoreName}/coverages";
100                 string cmd = $"curl -v -u {GeoServerConfig.User}:{GeoServerConfig.Password} -XPOST -H \"Content-type: text/xml\" -d \"{xml}\" {url}";
101 
102                 var result = processCommand.Invoke(cmd);
103 
104                 Console.WriteLine($"發佈{layerName}圖層結果:\n【{result}】");
105             });
106 
107             return true;
108         }
109         /// <summary>
110         /// 給圖層設置樣式
111         /// </summary>
112         /// <returns></returns>
113         protected bool SetLayerStyle()
114         {
115             for (int i = 0; i < dataTypeConfig.LayerList.Count; i++)
116             {
117                 string layerName = dataTypeConfig.LayerList[i];
118                 string styleName = dataTypeConfig.StyleList[i];
119 
120                 string xml = $"<layer><defaultStyle><name>{styleName}</name></defaultStyle></layer>";
121                 string url = $"{GeoServerConfig.GeoServerUrl}/layers/{layerName}";
122                 string cmd = $"curl -v -u {GeoServerConfig.User}:{GeoServerConfig.Password} -XPUT -H \"Content-type: text/xml\" -d \"{xml}\" {url}";
123 
124                 var result = processCommand.Invoke(cmd);
125 
126                 Console.WriteLine($"綁定{layerName}圖層{styleName}樣式結果:\n【{result}】");
127             }
128             return true;
129         }
130 
131         /// <summary>
132         /// 更新數據倉儲
133         /// </summary>
134         /// <param name="path">柵格文件路徑 使用//分割</param>
135         /// <returns></returns>
136         protected bool UpdateCoverageStore(string path)
137         {
138             string xml = $"<coverageStore><name>{dataTypeConfig.StoreName}</name><type>NetCDF</type><enabled>true</enabled><workspace><name>{dataTypeConfig.WorkSpaceName}</name></workspace><__default>false</__default><url>file://{path}</url></coverageStore>";
139             string cmd = $"curl -v -u {GeoServerConfig.User}:{GeoServerConfig.Password} -XPUT -H \"Content-type: text/xml\" -d \"{xml}\" {GeoServerConfig.GeoServerUrl}/workspaces/{dataTypeConfig.WorkSpaceName}/coveragestores/{dataTypeConfig.StoreName}";
140 
141             var result = processCommand.Invoke(cmd);
142 
143             Console.WriteLine($"更新數據倉庫{dataTypeConfig.StoreName}結果:\n【{result}】");
144 
145             return true;
146         }
147     }
148 }
View Code

 

 DataSourceType中放具體的柵格類型處理方法,目前只用到了NetCDF,NetCDFPublishHandler繼承抽象類AbstracPublishHandler直接調用Handling方法即可。

我這邊是使用Job定時執行發佈任務

 

 Linux上執行結果

  1 2023/2/23 下午2:14:00:GeoServer發佈準備開始!
  2 Note: Unnecessary use of -X or --request, GET is already inferred.
  3 *   Trying 192.168.1.51:8080...
  4   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
  5                                  Dload  Upload   Total   Spent    Left  Speed
  6   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
  7 * Server auth using Basic with user 'admin'
  8 > GET /geoserver/rest/workspaces/workspace_demo/coveragestores/demostore.json HTTP/1.1
  9 > Host: 192.168.1.51:8080
 10 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
 11 > User-Agent: curl/7.79.1
 12 > Accept: */*
 13 > 
 14 * Mark bundle as not supporting multiuse
 15 < HTTP/1.1 200 OK
 16 < X-Frame-Options: SAMEORIGIN
 17 < Content-Type: application/json
 18 < Transfer-Encoding: chunked
 19 < Server: Jetty(9.4.44.v20210927)
 20 < 
 21 { [496 bytes data]
 22 100   491    0   491    0     0   8196      0 --:--:-- --:--:-- --:--:--  8322
 23 * Connection #0 to host 192.168.1.51 left intact
 24 判斷是否有指定的數據倉庫:
 25 【{"coverageStore":{"name":"demostore","type":"NetCDF","enabled":true,"workspace":{"name":"workspace_demo","href":"http://192.168.1.51:8080/geoserver/rest/workspaces/workspace_demo.json"},"_default":false,"dateCreated":"2023-02-23 05:33:01.37 UTC","dateModified":"2023-02-23 05:34:01.101 UTC","url":"file://D:\\gsFile\\HadCRUT.5.0.1.0.analysis.anomalies.ensemble_mean.nc","coverages":"http://192.168.1.51:8080/geoserver/rest/workspaces/workspace_demo/coveragestores/demostore/coverages.json"}}】
 26 *   Trying 192.168.1.51:8080...
 27   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 28                                  Dload  Upload   Total   Spent    Left  Speed
 29   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
 30 * Server auth using Basic with user 'admin'
 31 > PUT /geoserver/rest/workspaces/workspace_demo/coveragestores/demostore HTTP/1.1
 32 > Host: 192.168.1.51:8080
 33 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
 34 > User-Agent: curl/7.79.1
 35 > Accept: */*
 36 > Content-type: text/xml
 37 > Content-Length: 252
 38 > 
 39 } [252 bytes data]
 40 * Mark bundle as not supporting multiuse
 41 < HTTP/1.1 200 OK
 42 < X-Frame-Options: SAMEORIGIN
 43 < Content-Length: 0
 44 < Server: Jetty(9.4.44.v20210927)
 45 < 
 46 100   252    0     0  100   252      0  16046 --:--:-- --:--:-- --:--:-- 16800
 47 * Connection #0 to host 192.168.1.51 left intact
 48 更新數據倉庫demostore結果:
 49 【】
 50 2023/2/23 下午2:14:00:GeoServer發佈完成!
 51 2023/2/23 下午2:15:00>>>>>>執行GeoService發佈
 52 2023/2/23 下午2:15:00:GeoServer發佈準備開始!
 53 Note: Unnecessary use of -X or --request, GET is already inferred.
 54 *   Trying 192.168.1.51:8080...
 55   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 56                                  Dload  Upload   Total   Spent    Left  Speed
 57   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
 58 * Server auth using Basic with user 'admin'
 59 > GET /geoserver/rest/workspaces/workspace_demo/coveragestores/demostore.json HTTP/1.1
 60 > Host: 192.168.1.51:8080
 61 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
 62 > User-Agent: curl/7.79.1
 63 > Accept: */*
 64 > 
 65 * Mark bundle as not supporting multiuse
 66 < HTTP/1.1 404 Not Found
 67 < X-Frame-Options: SAMEORIGIN
 68 < Content-Type: text/plain
 69 < Transfer-Encoding: chunked
 70 < Server: Jetty(9.4.44.v20210927)
 71 < 
 72 { [52 bytes data]
 73 100    48    0    48    0     0   6269      0 --:--:-- --:--:-- --:--:--  6857
 74 * Connection #0 to host 192.168.1.51 left intact
 75 判斷是否有指定的數據倉庫:
 76 【No such coverage store: workspace_demo,demostore】
 77 Note: Unnecessary use of -X or --request, POST is already inferred.
 78 *   Trying 192.168.1.51:8080...
 79   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 80                                  Dload  Upload   Total   Spent    Left  Speed
 81   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
 82 * Server auth using Basic with user 'admin'
 83 > POST /geoserver/rest/workspaces/workspace_demo/coveragestores HTTP/1.1
 84 > Host: 192.168.1.51:8080
 85 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
 86 > User-Agent: curl/7.79.1
 87 > Accept: */*
 88 > Content-type: text/xml
 89 > Content-Length: 252
 90 > 
 91 } [252 bytes data]
 92 * Mark bundle as not supporting multiuse
 93 < HTTP/1.1 201 Created
 94 < X-Frame-Options: SAMEORIGIN
 95 < Location: http://192.168.1.51:8080/geoserver/rest/workspaces/workspace_demo/coveragestores/demostore
 96 < Content-Type: text/plain
 97 < Content-Length: 9
 98 < Server: Jetty(9.4.44.v20210927)
 99 < 
100 { [9 bytes data]
101 100   261  100     9  100   252    510  14302 --:--:-- --:--:-- --:--:-- 15352
102 * Connection #0 to host 192.168.1.51 left intact
103 發佈柵格存儲結果:
104 【demostore】
105 Note: Unnecessary use of -X or --request, POST is already inferred.
106 *   Trying 192.168.1.51:8080...
107   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
108                                  Dload  Upload   Total   Spent    Left  Speed
109   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
110 * Server auth using Basic with user 'admin'
111 > POST /geoserver/rest/workspaces/workspace_demo/coveragestores/demostore/coverages HTTP/1.1
112 > Host: 192.168.1.51:8080
113 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
114 > User-Agent: curl/7.79.1
115 > Accept: */*
116 > Content-type: text/xml
117 > Content-Length: 91
118 > 
119 } [91 bytes data]
120 * Mark bundle as not supporting multiuse
121 < HTTP/1.1 201 Created
122 < X-Frame-Options: SAMEORIGIN
123 < Location: http://192.168.1.51:8080/geoserver/rest/workspaces/workspace_demo/coveragestores/demostore/coverages/tas_mean
124 < Content-Type: text/plain
125 < Content-Length: 8
126 < Server: Jetty(9.4.44.v20210927)
127 < 
128 { [8 bytes data]
129 100    99  100     8  100    91     38    436 --:--:-- --:--:-- --:--:--   478
130 * Connection #0 to host 192.168.1.51 left intact
131 發佈tas_mean圖層結果:
132 【tas_mean】
133 *   Trying 192.168.1.51:8080...
134   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
135                                  Dload  Upload   Total   Spent    Left  Speed
136   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.1.51 (192.168.1.51) port 8080 (#0)
137 * Server auth using Basic with user 'admin'
138 > PUT /geoserver/rest/layers/tas_mean HTTP/1.1
139 > Host: 192.168.1.51:8080
140 > Authorization: Basic YWRtaW46Z2Vvc2VydmVy
141 > User-Agent: curl/7.79.1
142 > Accept: */*
143 > Content-type: text/xml
144 > Content-Length: 63
145 > 
146 } [63 bytes data]
147 100    63    0     0  100    63      0   7387 --:--:-- --:--:-- --:--:--  7875* Mark bundle as not supporting multiuse
148 < HTTP/1.1 200 OK
149 < X-Frame-Options: SAMEORIGIN
150 < Content-Length: 0
151 < Server: Jetty(9.4.44.v20210927)
152 < 
153 100    63    0     0  100    63      0   1837 --:--:-- --:--:-- --:--:--  1852
154 * Connection #0 to host 192.168.1.51 left intact
155 綁定tas_mean圖層raster樣式結果:
156 【】
157 2023/2/23 下午2:15:00:GeoServer發佈完成!
Linux執行結果

目前只是一個簡單跑通的狀態,裡面其實還有許多需要完善的地方,包括對curl命令執行結果的判斷,多個倉庫的發佈等等,後面再持續更新吧!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.正常加鎖 當兩個用戶同時註冊一個用戶名時,為保證用戶名不能重覆,因此對其註冊的用戶名加鎖。 具體步驟: 獲得用戶註冊的用戶名,進行判斷,如果為空則對其進行加鎖,保存到資料庫,釋放鎖資源。 二.線程出現阻塞 當A線程加鎖後出現阻塞時,導致數據還沒有存到資料庫,鎖的時間便會失效。 B線程便會執行,對 ...
  • 睏倦的時候寫了個個獲取本地時間,列印總比當前時間大8小時,找了很久原因 package main import ( "fmt" "time" ) func main() { now := time.Now() fmt.Println(now) fmt.Println("nowStr:", now.F ...
  • pandas條件替換值(where&mask) 在日常分析中,經常會遇到對數據的篩選處理相關的工作,我們可以使用loc和iloc定位分析篩選的列或行數據,下麵介紹一種高級篩選的用法where和mask。 pd.where: 替換條件(condition)為Flase處的值 pd.mask: 替換條件 ...
  • 這篇文章主要描述分散式系統中經常討論的CAP理論,它從一致性、可用性和分區容錯性是分散式系統的三個特征,我們只能滿足其中兩個特征,對於分散式系統來說,根據不同的應用場景,可以是AP,也可以是CP。 ...
  • Java ”框架 = 註解 + 反射 + 設計模式“ 之 反射詳解 每博一文案 無論幸福還是苦難,無論光榮還是屈辱,你都要自己遭遇與承受。 —————— 《平凡的世界》 孫少平 多少美好的東西消失和毀滅了,世界還像什麼事也沒有發生,是的,生活在繼續著。 可是,生活中的每一個卻在不斷地失去自己最珍貴的 ...
  • RestSharp RestSharp是一個輕量的,不依賴任何第三方的模擬Http的組件或者類庫。RestSharp具體以下特性;支持net4.0++,支持HTTP的GET, POST, PUT, HEAD, OPTIONS, DELETE等操作,支持oAuth 1, oAuth 2, Basic, ...
  • 在使用應用程式的過程中,經常要求應用程式只能運行一次。如果發現重覆開啟,應從系統進程列表中搜索到已經開啟的進程,並將該進程視窗移到最前端顯示。 記錄一下過程。 實現過程 在 Program.cs 文件的 Program 類中聲明兩個外部調用函數 [DllImport("User32")] priva ...
  • 概述 裝飾器模式 允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作為現有的類的一個包裝。這種模式創建了一個裝飾類,用來包裝原有的類,併在保持類方法簽名完整性的前提下,提供了額外的功能。 簡單理解就是動態的給一個對象添加一些額外的職責,就增加功能來說,裝飾 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...