【转】在无人值守程序(服务)中调用Microsoft Graph

什么是无人值守程序(服务)

我在此前用了几篇文章分别介绍了在桌面应用程序(控制台),Web应用程序(ASP.NET MVC),以及PowerSehll脚本中如何访问Microsoft Graph,今天这一篇要继续讲一个场景:在无人值守程序中访问Microsoft Graph。那么什么是无人值守程序呢?通常我们将此类程序定义为不需要(不允许)用户进行干预,一般用来在后台自动化运行的程序。在英文文档中,我们将其称之为daemon application,广义上说,也包括了服务这种特殊的应用程序。

无人值守程序与Microsoft Graph的集成,要遵守一般的流程,但也有自己的一些特点,总结起来有如下的步骤

  1. 注册应用程序
  2. 配置应用程序权限
  3. 获得管理员同意
  4. 获得访问令牌
  5. 使用令牌访问资源

关于这个话题,官方有一个英文的文档,请参考 https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service

注册应用程序

针对Azure AD的不同版本,注册应用程序的过程我此前已经有专门的文章介绍了,请参考

  1. 注册Azure AD 2.0应用程序(支持国际版,支持Office 365账号以及个人账号登录,功能可能有所缺失,但这个是以后的方向),文章链接
  2. 注册Azure AD 1.0应用程序(支持国际版和中国版,仅支持Office 365账号登录,功能最全),文章链接1,文章链接2

本文先演示注册Azure AD 2.0应用,具体的步骤就不做截图了,唯一要提醒的是

  1. 应用程序类型设置为Web
  2. ReplyUrl可以设置为一个通用的地址,我喜欢设置为 https://developer.microsoft.com/en-us/graph/

配置应用程序权限

这是无人值守应用程序注册的时候,要特别注意的。由于该程序是没有用户参与的,所以它无法使用某个特定用户的身份做什么事情,而是使用一个统一的身份,该身份我们称为Application Identity,而相应的,我们要为程序申请的权限也是所谓的“Application Permissions”,而不是“Delegated Permissions”。

本例中,我想为应用程序申请两个权限:一个是用来获取所有用户信息的,另外一个是用来代替任何用户发送邮件。

获得管理员同意

由于无人值守的程序其实是自动化运行的,无需用户进行参与进行授权,而它进行的操作,却又有可能要代表用户的行为。所以通常这些权限都需要得到真正的Office 365 Tenant管理员同意才能真正生效。

其实细心的朋友在上图中也应该可以看出来,几乎所有Application Permission都是需要管理员同意的(Admin Consent)

要获得管理员同意,你可以将下面的这个链接发送给用户的Office 365 Tenant管理员

https://login.microsoftonline.com/common/adminconsent?client_id=dff48006-b010-4859-b5d5-68acdb821322&state=12345&redirect_uri=https://developer.microsoft.com/en-us/graph/

管理员需要在下面这样的界面中对应用程序所申请的权限进行确认

正常情况下,完成授权后页面会被导航到下面的地址,请确认admin_consent的值为true,并记录下来tenant的值。这个表示用户的Office 365 Tenant的编号,后面我们需要用到。

https://developer.microsoft.com/en-us/graph/?admin_consent=True&tenant=59723f6b-2d14-49fe-827a-8d04f9fe7a68&state=12345

获取访问令牌

无人值守应用程序,不需要用户参与进行授权,所以它获取令牌的方式也略有不同。你可以在应用程序里面使用下面的方式发起一个POST请求来获得访问令牌(Access Token)。

POST https://login.windows.net/59723f6b-2d14-49fe-827a-8d04f9fe7a68/oauth2/token
Content-Type: application/x-www-form-urlencoded
Host: login.windows.netclient_id=338c8e70-d0da-444e-b877-9f427a16eb17&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=8V59e4aBfNr6x4lN8EAMTisk3J7WRH+glZbvgMwdDQY=&grant_type=client_credentials

正常情况下,这个请求将返回如下的结果

请复制得到的这个access_token的值。请注意,默认情况下,这个access_token会在1个小时后过期。至于怎么刷新token,我会在后续文章中介绍。

使用令牌访问资源

有了这个access_token,应用程序就可以尽情地访问Microsoft Graph的资源了。例如,通过下面的请求可以获取到对应的Office 365 Tenant中的所有用户信息。

使用一个控制台程序来实现代码逻辑

上面演示的时候,我用了Fiddler这个小工具来模拟发起请求,并且快速地查看到结果。下面用一个简单的应用程序,来实现代码逻辑,给大家参考。

这个程序使用了最简单的代码实现,并添加了Newtonsoft.Json这个Package

using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;namespace daemonapplication
{class Program{static void Main(string[] args){//准备环境var clientId = "dff48006-b010-4859-b5d5-68acdb821322";var client_secret = "uxO3frQOekCfdOfX2Oom4Vc";var tenantId = "59723f6b-2d14-49fe-827a-8d04f9fe7a68";var client = new HttpClient();//获得令牌var request = new HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token");var body = new StringContent($"grant_type=client_credentials&client_id={clientId}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={client_secret}");body.Headers.ContentType.MediaType = "application/x-www-form-urlencoded";request.Content = body;var access_token = JObject.Parse(client.SendAsync(request).Result.Content.ReadAsStringAsync().Result)["access_token"].ToString();//访问资源request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/users");request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", access_token);var users = JObject.Parse(client.SendAsync(request).Result.Content.ReadAsStringAsync().Result)["value"];foreach (var item in users){Console.WriteLine($"displayName:{item["displayName"]},email:{item["email"]}");}Console.Read();}}
}

使用Azure AD 1.0

上面的例子很简单易懂,但如果我们使用的是Azure AD 1.0(国际版同时支持1.0和2.0,中国版则只支持1.0),则注册应用程序和使用Microsoft Graph的方式会略有不同。

注册Azure 1.0 应用程序(中国版)

请参考之前的两篇文章了解如何在Azure 1.0的环境中注册应用程序

  1. 国际版 链接
  2. 中国版 链接

和上面提到的一样,有两点需要注意

  1. 应用程序类型设置为Web
  2. ReplyUrl可以设置为一个通用的地址,我喜欢设置为 https://developer.microsoft.com/en-us/graph/

配置Azure 1.0 应用程序权限(中国版)

和上面提到的一样,这里需要申请Application permission,而不是delegation permission

这里需要注意修改Manifest文件(先下载,然后编辑,最后上传),允许隐式授权 

获得管理员同意 (中国版)

和Azure AD 2.0明显不同的是,在1.0中,获取管理员同意,需要使用如下的链接

https://login.chinacloudapi.cn/12c0cdab-3c40-4e86-80b9-3e6f98d2d344/oauth2/authorize?prompt=admin_consent&response_type=token&redirect_uri=https://developer.microsoft.com/en-us/graph/&resource=https://microsoftgraph.chinacloudapi.cn&client_id=3f56a5d5-7882-4290-9fd8-3908d734b3fe

此处的关键在于有一个prompt=admin_consent的参数,正常情况下,管理员进行授权确认后会跳转到下面这样的地址,里面已经包含了一个access_token

https://developer.microsoft.com/en-us/graph/#access_token=eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA&token_type=Bearer&expires_in=3599&session_state=022f05fb-4b3f-4f86-b593-cbda90232a7a&admin_consent=True

获取访问令牌(中国版)

这一步可以跳过,因为上面这一步已经获得了access_token

使用令牌访问资源(中国版)

using System;
using System.Net.Http;
using System.Threading.Tasks;namespace ConsoleApp6
{class Program{static void Main(string[] args){var result = GetUsers().Result;Console.WriteLine(result);Console.Read();}static async Task<string> GetUsers(){var token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA";HttpClient client = new HttpClient();client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);HttpResponseMessage response = await client.GetAsync("https://microsoftgraph.chinacloudapi.cn/v1.0/users/");string retResp = await response.Content.ReadAsStringAsync();return retResp;}}
}

如果我们将代码再演化一下,使用Microsoft.Graph进行访问的话,会更加轻松惬意,因为可以完全基于强类型的方式进行操作

using Microsoft.Graph;
using System;
using System.Threading.Tasks;
using System.Linq;namespace ConsoleApp6
{class Program{static void Main(string[] args){var result = GetUsers().Result;foreach (var item in result){Console.WriteLine(item.DisplayName);}Console.Read();}static async Task<IGraphServiceUsersCollectionPage> GetUsers(){var token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFDckhLdnJ4N0cyU2FaYlpoLXREbnA3Z1BvSDFZc2w5MWlxU0x4Qmdqc1ZXODhmMDR5Vm11Tm1pZGlWZGFJclY5MEhLTl9aUXlXMENERlowcWdwRnBfOWw4Wkhpb21LdkNSM19LQURMdWZ3R1NBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIiwia2lkIjoiWTFjenBtLXhpY2FRVFZYQzlPU2JXN3pHeHRRIn0.eyJhdWQiOiJodHRwczovL21pY3Jvc29mdGdyYXBoLmNoaW5hY2xvdWRhcGkuY24iLCJpc3MiOiJodHRwczovL3N0cy5jaGluYWNsb3VkYXBpLmNuLzEyYzBjZGFiLTNjNDAtNGU4Ni04MGI5LTNlNmY5OGQyZDM0NC8iLCJpYXQiOjE0OTYyNDI0MjQsIm5iZiI6MTQ5NjI0MjQyNCwiZXhwIjoxNDk2MjQ2MzI0LCJhY3IiOiIxIiwiYWlvIjoiQVNRQTIvOEFBQUFBd2E2S3Y1YmVVRGtSVTliY2pBTzBKbFVJb0xaYzk3bEtkYW5hbzRzMFJTVT0iLCJhbXIiOlsicHdkIl0sImFwcF9kaXNwbGF5bmFtZSI6ImRlYW1vbiIsImFwcGlkIjoiM2Y1NmE1ZDUtNzg4Mi00MjkwLTlmZDgtMzkwOGQ3MzRiM2ZlIiwiYXBwaWRhY3IiOiIwIiwiZmFtaWx5X25hbWUiOiLpmYgiLCJnaXZlbl9uYW1lIjoi5biM56ugIiwiaXBhZGRyIjoiMTgwLjE1Mi4yMi41MiIsIm5hbWUiOiLpmYgg5biM56ugIiwib2lkIjoiZjU1MjRmMTAtYTNlYy00Njg3LTllMzktNWFkNmU1ZTY3MDVhIiwicGxhdGYiOiIzIiwicHVpZCI6IjIwMDM3RkZFODExNjMyMDUiLCJzY3AiOiJNYWlsLlNlbmQgVXNlci5SZWFkLkFsbCIsInN1YiI6InhpckVWTFBtVG1BRFpJTW1sZTdBajZwS0NQU2JHMlNGU3EzN3JQaV9rWkUiLCJ0aWQiOiIxMmMwY2RhYi0zYzQwLTRlODYtODBiOS0zZTZmOThkMmQzNDQiLCJ1bmlxdWVfbmFtZSI6ImFyZXNAbW9kdHNwLnBhcnRuZXIub25tc2NoaW5hLmNuIiwidXBuIjoiYXJlc0Btb2R0c3AucGFydG5lci5vbm1zY2hpbmEuY24iLCJ1dGkiOiJRSEswVy0xdXcwbTlxWW9TekNvRUFBIiwidmVyIjoiMS4wIn0.EZhZhKFXzS1hVkz5HNEFSG9lcL6CSRyjqRNEMTYpM0Q4wp7UICf1_61PQFCe_5opnZlEMl-e7sHJ2W4Ni1hqjASUxOamFoQ5pBVNQ-WgEfhX_QPJXLBbyMdFguRPdrXy1AqzYGqFQ_mtmjqFa0w7nXf4LI7vgx7MRPMm5YDljnK4vk4oXC9M7fb4EcU7g26XrBUnTz6Es_IGT9SUqAXYLDjfI3dC06GqtjRrTwtd0AYwbbUPZ288j4XZ_fb8x1lj97ZpIFZh-STnIZUatIij0dFphMrFhUig0YbMtCxlfsrpZgPyuwlrrXbnj5fgWw1ABj3xKrEaWbVt5XCT4T9-aA";GraphServiceClient client = new GraphServiceClient(new DelegateAuthenticationProvider(async (request) =>{await Task.Run(() => { request.Headers.Add("Authorization", $"Bearer {token}"); });}));client.BaseUrl = "https://microsoftgraph.chinacloudapi.cn/v1.0";var result = client.Users.Request().GetAsync().Result;return result;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】使用PowerApps快速构建基于主题的轻业务应用 —— 入门篇

前言 在上一篇文章 基于Office 365的随需应变业务应用平台 中我提到&#xff0c;随着随需应变的业务需要&#xff0c;以及技术的发展&#xff0c;业务应用的开发的模式也有了深刻的变化。基于微软的平台&#xff0c;有服务于主干业务应用的Dynamic 365 业务应用平台&#xff0…

Spark内核源码学习(暂未学完)

1&#xff09; 回顾 1.1 Spark通用运行流程概述 在submit任务条件是需要指定executo个数&#xff0c;executor-CUP个数&#xff0c;可以提高并行度。 什么是并行&#xff0c;什么是并发&#xff1f; 并发&#xff1a;假如有多个任务task&#xff0c;并行是在一个cup中&#x…

【转】使用PowerApps快速构建基于主题的轻业务应用 —— 进阶篇

在上一篇 使用PowerApps快速构建基于主题的轻业务应用 —— 入门篇 中&#xff0c;我用了三个实际的例子演示了如何快速开始使用PowerApps构建轻业务应用&#xff0c;你可能已经发现&#xff0c;我都是使用默认生成的设置&#xff0c;没有做任何修改。当然&#xff0c;那样做出…

Spark一些组件的定义

Driver program: 运行应用程序的main函数并创建SparkContext的进程 除了RDD的最终执行所写的业务逻辑&#xff0c;剩下的都在Driver里生成&#xff0c;Driver端执行action算子才会到开始执行所创建的DAG-RDD图。 Cluster manager&#xff1a; 用于获取集群资源外部服务 Mas…

【转】D365 FO第三方集成(二)---访问认证(获取访问令牌)

D365 FO 在github上发布了第三方访问D365 FO的示例代码&#xff0c;里面包含了各种调用示例&#xff0c;代码很清晰。https://github.com/microsoft/Dynamics-AX-Integration 这篇blog简单分析一下代码中获取访问令牌的部分代码。 与获取访问令牌相关的代码有两个类ClientConfi…

【转】D365 FO第三方集成(三)---服务实现

D365 FO的Custom Service的实现比AX2012简单了很多。 AX2012服务方法要用属性SysEntryPointAttribute标记&#xff0c;添加到Services以后&#xff0c;还要发布服务并在系统管理入站端口添加操作&#xff0c;服务运行在CIL下&#xff0c;所以每次改动服务方法的代码都要增量生成…

PHP连接sql seaver数据库

我的PHP版本7.0 通过sqlsrv系列函数&#xff0c;需要下载安装Microsoft Drivers for PHP for SQL Server驱动&#xff1a; 地址&#xff1a;https://msdn.microsoft.com/library/dn865013.aspx。 根据自己需求下载安装&#xff0c;安装地址php下ext目录下&#xff0c;我的是4.0…

NoSql理解+传统关系型数据库ACID+Nosql的CAP+BASE的理解

1&#xff09;什么是Nosql NoSQL(NoSQL Not Only SQL )&#xff0c;意即“不仅仅是SQL”&#xff0c; 泛指非关系型的数据库。随着互联网web2.0网站的兴起&#xff0c;传统的关系数据库在应付web2.0网站&#xff0c;特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显…

ztree 点击重载 layui table

ztree 点击重载 layui table <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <HTML> <HEAD><TITLE> ztree_demo </TITLE><meta http…

数据结构与算法 - 稀疏数组(理解+代码实现案例)

举例 稀疏数组第一行是原数据几行几列和几个有效数据的个数 下面的行是各个有效数组的行列与具体值 稀疏数组实现 代码实现 package DataStructures.sparsearray;/*** 二维数组转稀疏数组 与 稀疏数组转成二维数组*/ public class SparseArray {public static void main(Stri…

数据结构 - 队列(非环形队列,以及优化成环形队列)

1&#xff09;队列的定义与实现形式-方式 2&#xff09;队列实现思路&#xff08;非环形&#xff0c;下面进行优化&#xff09; 3&#xff09;代码实现&#xff08;注意并不是环形&#xff09; package DataStructures.queue;import java.util.Scanner;/*** 使用数组模拟队列*…

爬取网易云音乐歌曲特色榜单信息

网易云音乐(iframe内的歌单) 刚开始学习做下记录 需要先下载好所需浏览器内核 我时谷歌&#xff0c;下载地址 http://chromedriver.storage.googleapis.com/index.html 然后没了&#xff0c;自己F12扒拉下就行了 运行&#xff1a; 左侧随便点击一个榜单后&#xff0c;复制ur…

数据结构 - 单链表(Linked List)实现在内存中实现数据以链表形式生成并根据序号排序

下面实现一个例子来进行学习 1&#xff09;介绍 单链表的逻辑结构 在内存中的实际结构 具体创建示意图&#xff1a; 2&#xff09;代码实现 例子 1。第一个程序在添加的时候并没有按照序号排序&#xff0c;如果在添加的时候把位置改变输出的时候序号会改变 package DataStr…

Mysql count() 语句

百万数据测试 select count(主键) from table 执行效率&#xff1a; select count(*) AS AGGREGATE from table 以上测试均再 navicat 工具进行 由于各种原因&#xff0c;sql执行时间可定存在一定误差&#xff0c;但最终结果不变。

phpStydy+wordpress 安装部署

1、先准备工具包 下载phpstudy&#xff0c;下载地址&#xff1a;https://www.xp.cn/ 下载wordpress &#xff0c;下载地址&#xff1a;https://cn.wordpress.org/download/ 2、安装phpStudy&#xff0c;下一步操作即可 3、安装完成后&#xff0c;检测环境配置&#xff0c;php、…

java数据结构 - 单链表(腾讯面试题实现单链表反转)

直接上实现代码 //单链表的反转public static void reverseList(HeroNode head){//如果当前链表为空&#xff0c;或只有一个节点&#xff0c;无需反转if (head.next null || head.next.next null){return ;}//定义一个辅助变量&#xff0c;帮助我们遍历HeroNode cur head.n…

数据结构 - 链表(双向链表学习)

程序里有几个注释的地方还是需要特别注意的&#xff0c;根据单链表自己的逻辑来写一遍双向链表&#xff0c;可能有几个细节处理的不到位。 package DataStructures.LinkedList;public class DoubleLinkedListDemo {public static void main(String []args){System.out.println…

【转】Mac下 如何配置虚拟机软件Parallel Desktop--超详细

Mac下 如何配置虚拟机软件Pparallel Desktop--超详细 Mac 的双系统解决方案有两种&#xff0c;一种是使用Boot Camp分区安装独立的Windows&#xff0c;一种是通过安装Parallels Desktop一类的虚拟机软件运行Windows。采用虚拟机的方式优势更明显&#xff0c;可以灵活的在两个系…

数据结构 - 链表(单向环形链表)(约瑟夫问题)

问题如下&#xff08;与分析&#xff09; 构建思路 输入一个数&#xff0c;数到这个数的小孩出圈&#xff0c;出圈顺序的思路 代码实现 根据图解&#xff0c;来一步一步实现 //根据用户输入&#xff0c;计算小孩出圈顺序/**** param startNo 表示从第几个小孩开始数数* param …

【转】什么是ERP、SCM、CRM?

ERP、SCM、CRM的区别 &#xff08;1&#xff09;从管理理念上来说&#xff0c;ERP的管理理念是提高企业内部资源的计划和控制能力&#xff0c;讲究的是在满足客户、及时交货的同时最大限度地降低各种成本&#xff0c;通过提高内部运转效率来提高对客户的服务质量&#xff0c;是…