深入解析ArcGIS Server二次开发之SOE开发

2023-11-06 00:30

本文主要是介绍深入解析ArcGIS Server二次开发之SOE开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一般情况下,一个ArcGIS Engine 工程师转向Web端开发,如果没有相关的web思想,很难转换这个角色,但是如果你有ArcGIS Engine的开发经验,势必会对Web API的开发有很大的帮助,至少今天的主题需要你有ArcGIS Engine开发的经验

 

         Web API 已经提供了足够多个功能供开发者去完善相关的业务功能,特别是GP Service的加入,让Web API在分析方面如虎添翼,但是不可否认,Web技术由于受到网络的限制,浏览器的限制,一些大数据量的分析可能让Web开发者比较挠头,而且如果想实现目前WebAPI还没有提供的功能,基本上无路可走,但是幸好,我们可以使用ArcObject的资源来完善我们的Web应用,也就是ArcGIS for Server的SOE的扩展。

 

参考文档

 

ArcGIS for Server的SOE扩展:http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/#/What_is_a_server_object_extension/0001000000zv000000/

关于GP和SOE 的对比问题

         这方面不是本博客的主题,但是有必要简单给大家进行说明一下:

1.GP适合复杂业务流程,较低并发下的应用 

2.SOE适合单一功能的模块,较高并发下的应用

 

SOE开发环境

        ArcObject10.1、VS2010(AO支持的版本)、ArcGIS10.1 for Server、ArcSDE10.1、ArcGIS for JS 3.9

开发目的

         一个地图服务,该地图服务包含一个subway的点图层,该图层有一个name字段,存储相关的地铁站名称,比如东直门站、北京站,使用一个查询条件获得某一个点要素,然后再进行缓冲区(半径1000),然后进行叠加分析,获得该缓冲区下所有的地铁站要素信息,在web端进行渲染。

         当然该需求不管通过ArcGIS for JS基础API或者GP Service都可以实现,但是本次主题的目的就是通过这个例子来了解一下ArcGIS for Server的SOE扩展的开发流程。

 

开发思路

1:首先我们需要进行核心需求的ArcObject代码编程实现,也就是获得要素类对象,然后根据用户提供的属性条件过滤,获得相关要素,然后进行buffer,然后再对该要素类进行空间查询获得符合条件的数据,其实这个熟悉AO开发的是一个非常简单的功能,但是如果希望进行SOE扩展就需要了解SOE开发的相关问题

 

2:在VS上创建SOE程序,系统会自动生成一个相关模板,我们以开放REST为例

 

生成完毕之后,我们就可以看到相关的模板代码。

为了便于用户了解SOE的生命周期和对应接口,我觉得先给大家介绍SOE的部署和调试,如果我们会使用调试,那么我们就可以根据相关模板代码,一步步的进行了解SOE是怎样一个相关原理。

SOE部署

         我们生成了相关的SOE版本,在ArcGIS 10.2版本,支持了影像服务的扩展,所以在我们需要在模板里面输入支持地图服务还是影像服务。如下所示“MapServer”。


 

 [ServerObjectExtension("MapServer",AllCapabilities = "",DefaultCapabilities = "",Description = "",DisplayName = "RestSOE2",Properties = "",SupportsREST = true,SupportsSOAP = false)]

         我们需要在初始化函数Init里面添加如下代码,才能进入调试状态
 

public void Init(IServerObjectHelper pSOH){//生命周期开始时调试System.Diagnostics.Debugger.Launch();serverObjectHelper = pSOH;}

         生成解决方案,在bin目录下可以看到以.soe后缀名的文件。

PS:该.soe后缀的文件可以将.soe名称修改为.zip,那么用户可以看到相关dll以及元数据xml文件信息。

 

打开Manger,点击site选项,在GIS Server页选择Extensions

 

         然后再Services选项中,选择某个服务比如JS 地图服务,在该服务的Capablities选择新的RestSOE2扩展,然后保存和重新启动服务即可。

 

SOE调试

         如果前面在init函数中已经添加了调试代码,那么在该服务重启过程中就会弹出如下对话框

 

 

         选择相应的SOE 程序点击是,那么系统就会进入调试状态

 

 

         掌握了SOE的调试,用户可以跟踪相关的调试顺序,了解SOE的具体执行步骤。

注意:

1:我的VS、AO、ArcGIS  Server都在同一个环境下,相关调试没有问题,但是如果VS和Server不再一台机器上,调用调试可能会有问题,咨询相关人员回答在不同环境下是可以调试的,但是我并没有解决。

2:因为64Bit的关系,代码不能像C#+ArcGIS Engine 开发可以实时修改代码进行调试

3:SOE的代码如果需要修改,停止调试,然后修改代码,然后重新生成SOE,然后删除manager的扩展项,然后添加新修改的soe文件,然后再针对某个服务添加扩展重新启动服务,这个就比较麻烦,建议现在纯AO环境下进行调试,这样会减少比较多的麻烦。

 

SOE生命周期

通过跟踪代码,我们可以了解SOE的生命周期,建议用户还需要提前查看相关帮助

                   ============在添加扩展SOE服务的重启过程============

 

1:MapServer初始化

2:SOE初始化
 

public void Init(IServerObjectHelper pSOH){System.Diagnostics.Debugger.Launch();serverObjectHelper = pSOH;}

3:MapServer启动

4:SOE构造

public void Construct(IPropertySet props){configProps = props;}

 

         ===============生成相关的SOE服务连接,点击该连接=====

5:SOE活动——REST/SOAP处理请求——SOE停止活动

这是一个相关循环的过程。

         在点击链接时会创建Schema
 

 public string GetSchema(){return reqHandler.GetSchema();}

         然后进行REST/SOAP处理请求

 public byte[] HandleRESTRequest(string Capabilities, string resourceName, string operationName, string operationInput, string outputFormat, string requestProperties, out string responseProperties){return reqHandler.HandleRESTRequest(Capabilities, resourceName, operationName, operationInput, outputFormat, requestProperties, out responseProperties);}

 

         请求完毕之后,创建Root资源,也就是可以看到的SOE介绍信息

 

 

private byte[] RootResHandler(NameValueCollection boundVariables, string outputFormat, string requestProperties, out string responseProperties){responseProperties = null;JsonObject result = new JsonObject();result.AddString("hello", "world");return Encoding.UTF8.GetBytes(result.ToJson());}

         点击相关的sampleOperation函数,我们输入相关参数值,点击GET请求

 

 

         我们可以看到系统还会进行REST/SOAP请求,然后进入相关的主体函数中,核心的代码应该在该函数中编写即可

 private byte[] SampleOperHandler(NameValueCollection boundVariables,JsonObject operationInput,string outputFormat,string requestProperties,out string responseProperties){responseProperties = null;string parm1Value;bool found = operationInput.TryGetString("parm1", out parm1Value);if (!found || string.IsNullOrEmpty(parm1Value))throw new ArgumentNullException("parm1");string parm2Value;found = operationInput.TryGetString("parm2", out parm2Value);if (!found || string.IsNullOrEmpty(parm2Value))throw new ArgumentNullException("parm2");JsonObject result = new JsonObject();result.AddString("parm1", parm1Value);result.AddString("parm2", parm2Value);return Encoding.UTF8.GetBytes(result.ToJson());}

6:MapServer停止

7:SOE关闭
 

 public void Shutdown(){}

关闭之后需要用户释放相关的对象资源。

 

关于Schema

 

         一般情况下,我们实现一个功能都会需要输入相关参数,和参与该功能的图层或者字段等,那么我们将Schema称之为SOE中的资源和操作的层次结构,资源(resource)就是从服务器端返回的信息块,比如图层列表、缓存服务的比例尺级别,如果这次实验用的的图层名称subway,字段名称name,操作(operations)就是让服务器资源做的一些事情,比如我们设置的where条件以及缓冲区bufferRedius等

 private RestResource CreateRestSchema(){RestResource rootRes = new RestResource(soe_name, false, RootResHandler);RestOperation sampleOper = new RestOperation("QueryBuffer",new string[] { "WhereClause", "BufferRadius" },new string[] { "json" },DoQueryBuffer);rootRes.operations.Add(sampleOper);RestResource propertiesResource = new RestResource("properties", false, PropertiesResHandler);rootRes.resources.Add(propertiesResource);return rootRes;}

 

关于SOE的处理流程

 

1:客户端请求参数,请求参数反序列化

 

2:SOE业务逻辑实现处理

 

3:结果序列化

 

         关于参数的序列化或者反序列化,都使用了ESRI.ArcGIS.SOESupport;

 

序列化 

 

 反序列化

 

         我个人觉得一句话总结,一切皆JSON。最终返回的结果都是JSON格式即可。

 

         比如本次主题的目的就是查询出来符合条件和缓冲区面积的点要素几何,那么我们需要获得这些相关Geometry对象的JSON格式的集合即可。


 

private byte[] GetResultJson(List<IFeature> pList){List<JsonObject> pJoList = null;if (pList!=null){IFeature pfea = null;pJoList = new List<JsonObject>();for (int i = 1; i < pList.Count; i++){pfea = pList[i];pJoList.Add(Conversion.ToJsonObject(pfea.ShapeCopy));}}JsonObject resultJson = new JsonObject();resultJson.AddArray("geometries", pJoList.ToArray());byte[] result = Encoding.UTF8.GetBytes(resultJson.ToJson());return result;}

关于获取数据源信息

 

         SOE开发与AO开发不一样的地方,AO可以直接获得SDE连接对象,然后打开获得相关的IFeatureClass对象等,那么SOE跟这个不太一样,它需要通过服务来获得对象,主要关注IMapServerDataAccess获得相关的MSD数据,有两个功能可以使用

 

一般情况下使用GetDataSource,那么如果有关联关系的可以使用GetDisplayDataSouce。

 //获取数据             IMapServer3 mapServer = (IMapServer3)serverObjectHelper.ServerObject;IMapLayerInfo layerInfo;IMapLayerInfos layerInfos = mapServer.GetServerInfo(mapServer.DefaultMapName).MapLayerInfos;// 获取查询图层idint layercount = layerInfos.Count;int layerIndex = 0;string sName = "";for (int i = 0; i < layercount; i++){layerInfo = layerInfos.get_Element(i);//默认的oracle数据库的sde用户,查询出来的layerInfo.Name为sde.subway所以需要去掉sde.信息sName=layerInfo.Name;if (sName != ""){sName= sName.Substring(sName.IndexOf(".") + 1, (sName.Length - sName.IndexOf(".")) - 1).Trim();}if (sName == m_LayerName){layerIndex = i;break;}}IMapServerDataAccess dataAccess = (IMapServerDataAccess)mapServer;this.m_FeatureClass = (IFeatureClass)dataAccess.GetDataSource(mapServer.DefaultMapName, layerIndex);

 

相关SOE源代码
 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;using System.Collections.Specialized;using System.Runtime.InteropServices;using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.SOESupport;//TODO: sign the project (project properties > signing tab > sign the assembly)
//      this is strongly suggested if the dll will be registered using regasm.exe <your>.dll /codebasenamespace RestSOE1
{[ComVisible(true)][Guid("99611947-9d7d-4f6f-a4c4-d835ce4a7fa5")][ClassInterface(ClassInterfaceType.None)][ServerObjectExtension("MapServer",//use "MapServer" if SOE extends a Map service and "ImageServer" if it extends an Image service.AllCapabilities = "",DefaultCapabilities = "",Description = "Query Buffer SOE",DisplayName = "RestSOE1",Properties = "Field_Name=name;Layer_Name=subway",SupportsREST = true,SupportsSOAP = false)]public class RestSOE1 : IServerObjectExtension, IObjectConstruct, IRESTRequestHandler{private string soe_name;private IPropertySet configProps;private IServerObjectHelper serverObjectHelper;private ServerLogger logger;private IRESTRequestHandler reqHandler;private IFeatureClass m_FeatureClass = null;//查询图层名称private string m_LayerName = "";//查询字段名称private string m_FieldName = "";public RestSOE1(){soe_name = this.GetType().Name;logger = new ServerLogger();reqHandler = new SoeRestImpl(soe_name, CreateRestSchema()) as IRESTRequestHandler;}#region IServerObjectExtension Memberspublic void Init(IServerObjectHelper pSOH){//生命周期开始时调试System.Diagnostics.Debugger.Launch();serverObjectHelper = pSOH;}public void Shutdown(){this.soe_name = null;this.m_FeatureClass = null;this.logger = null;this.m_FieldName = null;this.m_LayerName = null;this.serverObjectHelper = null;this.configProps = null;this.reqHandler = null;}#endregion#region IObjectConstruct Memberspublic void Construct(IPropertySet props){configProps = props;if (props.GetProperty("Field_Name") != null){this.m_FieldName = props.GetProperty("Field_Name") as string;}else {throw new ArgumentNullException();}if (props.GetProperty("Layer_Name") != null){this.m_LayerName = props.GetProperty("Layer_Name") as string;}else{throw new ArgumentNullException();}try{//获取数据              IMapServer3 mapServer = (IMapServer3)serverObjectHelper.ServerObject;IMapLayerInfo layerInfo;IMapLayerInfos layerInfos = mapServer.GetServerInfo(mapServer.DefaultMapName).MapLayerInfos;// 获取查询图层idint layercount = layerInfos.Count;int layerIndex = 0;string sName = "";for (int i = 0; i < layercount; i++){layerInfo = layerInfos.get_Element(i);//默认的oracle数据库的sde用户,查询出来的layerInfo.Name为sde.subway所以需要去掉sde.信息sName=layerInfo.Name;if (sName != ""){sName= sName.Substring(sName.IndexOf(".") + 1, (sName.Length - sName.IndexOf(".")) - 1).Trim();}if (sName == m_LayerName){layerIndex = i;break;}}IMapServerDataAccess dataAccess = (IMapServerDataAccess)mapServer;this.m_FeatureClass = (IFeatureClass)dataAccess.GetDataSource(mapServer.DefaultMapName, layerIndex);if (this.m_FeatureClass == null){logger.LogMessage(ServerLogger.msgType.error, "Construct", 8000, "SOE custom error: Layer name not found.");return;}if (this.m_FeatureClass.FindField(this.m_FieldName) == -1){logger.LogMessage(ServerLogger.msgType.error, "Construct", 8000, "SOE custom error: Field not found in layer.");}}catch (Exception e){ }}#endregion#region IRESTRequestHandler Memberspublic string GetSchema(){return reqHandler.GetSchema();}public byte[] HandleRESTRequest(string Capabilities, string resourceName, string operationName, string operationInput, string outputFormat, string requestProperties, out string responseProperties){return reqHandler.HandleRESTRequest(Capabilities, resourceName, operationName, operationInput, outputFormat, requestProperties, out responseProperties);}#endregionprivate RestResource CreateRestSchema(){RestResource rootRes = new RestResource(soe_name, false, RootResHandler);RestOperation sampleOper = new RestOperation("QueryBuffer",new string[] { "WhereClause", "BufferRadius" },new string[] { "json" },DoQueryBuffer);rootRes.operations.Add(sampleOper);RestResource propertiesResource = new RestResource("properties", false, PropertiesResHandler);rootRes.resources.Add(propertiesResource);return rootRes;}private byte[] PropertiesResHandler(NameValueCollection boundVariables, string outputFormat, string requestProperties, out string responseProperties){responseProperties = "{\"Content-Type\" : \"application/json\"}";JsonObject result = new JsonObject();result.AddString("Field_Name", this.m_FieldName);result.AddString("Layer_Name", this.m_LayerName);return Encoding.UTF8.GetBytes(result.ToJson());}private byte[] RootResHandler(NameValueCollection boundVariables, string outputFormat, string requestProperties, out string responseProperties){responseProperties = null;JsonObject result = new JsonObject();result.AddString("名称", "查询缓冲Soe");result.AddString("描述", "通过属性查询条件,获得一个点要素,然后再做缓冲区");result.AddString("方法", "条件过滤加上缓冲区");return Encoding.UTF8.GetBytes(result.ToJson());}private byte[] DoQueryBuffer(NameValueCollection boundVariables,JsonObject operationInput,string outputFormat,string requestProperties,out string responseProperties){responseProperties = null;string WhereClause;bool found = operationInput.TryGetString("WhereClause", out WhereClause);if (!found || string.IsNullOrEmpty(WhereClause))throw new ArgumentNullException("WhereClause");double? BufferRadius;found = operationInput.TryGetAsDouble("BufferRadius", out BufferRadius);if (!found || !BufferRadius.HasValue)throw new ArgumentNullException("BufferRadius");List<IFeature> pList = GetQueryBufferGeometryList(this.m_FieldName, WhereClause, BufferRadius);return GetResultJson(pList);}private IGeometry GetQueryBufferGeometry(string sFieldName, IFeatureClass pfc,string sWhereClause, object sBufferRadius){IGeometry pGeo = null;IQueryFilter qf = new QueryFilterClass();//这里只测试字符串查询,其他类型不再进行逻辑检查和编写string sWhere=sFieldName+"='"+sWhereClause+"'";qf.WhereClause = sWhere;IFeatureCursor pCur= pfc.Search(qf, true);IFeature pFea = pCur.NextFeature();ITopologicalOperator pTO = null; while (pFea != null){pTO = pFea.ShapeCopy as ITopologicalOperator;pGeo = pTO.Buffer(Convert.ToDouble(sBufferRadius));pFea = pCur.NextFeature();}return pGeo;}private List<IFeature> GetQueryBufferGeometryList(string sFieldName, string sWhereClause, object sBufferRadius){List<IFeature> pFeatureList = new List<IFeature>();IQueryFilter qf = new QueryFilterClass();//这里只测试字符串查询,其他类型不再进行逻辑检查和编写string sWhere = sFieldName + "='" + sWhereClause + "'";qf.WhereClause = sWhere;IFeatureCursor pCur = this.m_FeatureClass.Search(qf, false);IFeature pFea = pCur.NextFeature();ITopologicalOperator pTO = null;IGeometry pBufferGeo = null;while (pFea != null){pTO = pFea.ShapeCopy as ITopologicalOperator;pBufferGeo = pTO.Buffer(Convert.ToDouble(sBufferRadius));pFea = pCur.NextFeature();}ISpatialFilter sf = new SpatialFilterClass();sf.Geometry = pBufferGeo;sf.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;sf.GeometryField = this.m_FeatureClass.ShapeFieldName;ISpatialReference sr=(this.m_FeatureClass as IGeoDataset).SpatialReference;sf.set_OutputSpatialReference(this.m_FeatureClass.ShapeFieldName, sr);IFeatureCursor pFCur = this.m_FeatureClass.Search(sf, false);while ((pFea = pFCur.NextFeature()) != null){pFeatureList.Add(pFea);}return pFeatureList;}private byte[] GetResultJson(List<IFeature> pList){List<JsonObject> pJoList = null;if (pList!=null){IFeature pfea = null;pJoList = new List<JsonObject>();for (int i = 1; i < pList.Count; i++){pfea = pList[i];pJoList.Add(Conversion.ToJsonObject(pfea.ShapeCopy));}}JsonObject resultJson = new JsonObject();resultJson.AddArray("geometries", pJoList.ToArray());byte[] result = Encoding.UTF8.GetBytes(resultJson.ToJson());return result;}}
}

 

         很久不写Engine代码了,连很简单的东西都忘记的差不多了。我们可以通过前面介绍的调试方法,测试是否可以获得正确的结果?

 

 

ArcGIS for JS 调用SOE服务

 

关于ArcGIS for JS调用SOE 服务主要使用了如下代码:


 

var WhereClause = dom.byId("WhereClause").value;var BufferRadius = dom.byId("BufferRadius").value;var content = {'WhereClause': WhereClause,'BufferRadius': BufferRadius,'f': "json"};var Request = esriRequest({url: soeUrl,content: content,handleAs: "json",callbackParamName: "callback"});Request.then(function (responses) {...........});

 

使用esriRequest,传入soe的REST,然后将属性参数传入(content),然后对请求进行枚举查询,由于我们SOE获得的结果是查询的IGeometry的Array,那么执行对返回结果进行循环获得,然后将相关结果作为一个graphic添加到map即可。

 

 

 

ArcGIS for JS调用SOE 源代码如下

<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" /><title>Simple Map</title><link rel="stylesheet" type="text/css" href="http://localhost/arcgis_js_v39_api/arcgis_js_api/library/3.9/3.9/js/dojo/dijit/themes/tundra/tundra.css" /><link rel="stylesheet" type="text/css" href="http://localhost/arcgis_js_v39_api/arcgis_js_api/library/3.9/3.9/js/esri/css/esri.css" /><script type="text/javascript" src="http://localhost/arcgis_js_v39_api/arcgis_js_api/library/3.9/3.9"> </script><script type="text/javascript" src="jsapi_vsdoc_v32_2012.js"></script><style>html, body, #mapDiv {padding: 0;margin: 0;height: 100%;}#messages {background-color: #fff;box-shadow: 0 0 5px #888;font-size: 1.1em;max-width: 15em;padding: 0.5em;position: absolute;right: 20px;top: 300px;z-index: 40;}</style><script>var map;require(["esri/map", "esri/layers/FeatureLayer","esri/layers/ArcGISDynamicMapServiceLayer","esri/request","esri/graphic", "esri/symbols/SimpleMarkerSymbol","esri/geometry/Point","esri/SpatialReference","esri/config", "esri/Color", "dojo/_base/array", "dojo/on", "dojo/dom", "dojo/domReady!"], function (Map, FeatureLayer, ArcGISDynamicMapServiceLayer,esriRequest,Graphic, SimpleMarkerSymbol,Point,SpatialReference,esriConfig, Color,arrayUtils,on, dom) {// use a proxy page if a URL generated by this page is greater than 2000 characters//// this should not be needed as nearly all query & select functions are performed on the clientesriConfig.defaults.io.proxyUrl = "/proxy";map = new Map("mapDiv", {});var mapUrl = "http://192.168.220.125:6080/arcgis/rest/services/JS/MapServer";var soeUrl = "http://192.168.220.125:6080/arcgis/rest/services/JS/MapServer/exts/RestSOE1/QueryBuffer";//Takes a URL to a non cached map service.var dynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer(mapUrl);map.addLayer(dynamicMapServiceLayer);on(dom.byId("execute"), "click", function () {var WhereClause = dom.byId("WhereClause").value;var BufferRadius = dom.byId("BufferRadius").value;var content = {'WhereClause': WhereClause,'BufferRadius': BufferRadius,'f': "json"};var Request = esriRequest({url: soeUrl,content: content,handleAs: "json",callbackParamName: "callback"});Request.then(function (responses) {map.graphics.clear();var markerSymbol = new SimpleMarkerSymbol();markerSymbol.setPath("M16,4.938c-7.732,0-14,4.701-14,10.5c0,1.981,0.741,3.833,2.016,5.414L2,25.272l5.613-1.44c2.339,1.316,5.237,2.106,8.387,2.106c7.732,0,14-4.701,14-10.5S23.732,4.938,16,4.938zM16.868,21.375h-1.969v-1.889h1.969V21.375zM16.772,18.094h-1.777l-0.176-8.083h2.113L16.772,18.094z");markerSymbol.setColor(new Color("#00FFFF"));markerSymbol.setSize(30);markerSymbol.setOffset(20, 10);var wgs = new SpatialReference({"wkid": 102100});for (var i = 0; i < responses.geometries.length; i++) {var pt = new Point(responses.geometries[i].x, responses.geometries[i].y, wgs);var graphic = new Graphic(pt, markerSymbol);map.graphics.add(graphic);}});});});</script></head><body>查询条件<input type="text" id="WhereClause" value="北京站">缓冲区半径<input type="text" id="BufferRadius" value="1500"><input id="execute" type="button" value="执行查询"><div id="mapDiv"></div></body></html>

 

获得的查询页面和结果如下

 

欢迎关注微信公众号“GIS带我奔跑”获取更多技术文章。

 

 

 

 

 

 

 

原文链接:https://blog.csdn.net/linghe301/article/details/38434469

这篇关于深入解析ArcGIS Server二次开发之SOE开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/353431

相关文章

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

Window Server创建2台服务器的故障转移群集的图文教程

《WindowServer创建2台服务器的故障转移群集的图文教程》本文主要介绍了在WindowsServer系统上创建一个包含两台成员服务器的故障转移群集,文中通过图文示例介绍的非常详细,对大家的... 目录一、 准备条件二、在ServerB安装故障转移群集三、在ServerC安装故障转移群集,操作与Ser

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

深入理解Redis大key的危害及解决方案

《深入理解Redis大key的危害及解决方案》本文主要介绍了深入理解Redis大key的危害及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、背景二、什么是大key三、大key评价标准四、大key 产生的原因与场景五、大key影响与危

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加