最近新接觸了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命令執行結果的判斷,多個倉庫的發佈等等,後面再持續更新吧!