azure服务器_如何使用Azure Functions和SendGrid构建无服务器报表服务器

azure服务器

It’s 2018 and I just wrote a title that contains the words “Serverless server”. Life has no meaning.

那是2018年,我刚刚写了一个标题,其中包含“无服务器服务器”一词。 生活没有意义。

Despite that utterly contradictory headline, in this article we’re going to explore a pretty nifty way to exploit SendGrid’s template functionality using Timer Triggers in Azure Functions to send out scheduled tabular reports. We are doing this because that’s what everyone wants in their inbox. A report. With numbers in it. And preferably some acronyms.

尽管标题完全矛盾,但在本文中,我们将探索一种非常漂亮的方法,即使用Azure Functions中的计时器触发器来利用SendGrid的模板功能来发送计划的表格报表。 我们这样做是因为每个人都希望在收件箱中。 一份报告。 里面有数字。 并且最好是一些缩写。

库存SKU报告 (The Inventory SKU Report)

First, let’s straw-man this project with a contrived application that looks sufficiently boring enough to warrant a report. I have just the thing. A site where we can adjust inventory levels. The word “inventory” is just begging for a report.

首先,让我们用一个人为设计的应用程序来研究这个项目,它看起来足够无聊,足以保证报告。 我有东西。 我们可以调整库存水平的站点。 “库存”一词只是乞求一份报告。

This application allows you to adjust the inventory quantity (last column). Let’s say that an executive somewhere has requested that we email them a report every night that contains a list of every SKU altered in the last 24 hours. Because of course, they would ask for that. In fact, I could swear I’ve built this report in real life in a past job. Or there’s a glitch in the matrix. Either way, we’re doing this.

此应用程序允许您调整库存数量(最后一列)。 假设某位高管要求我们每晚向他们发送一份报告,其中包含过去24小时内更改的每个SKU的列表。 当然,他们会要求这样做。 实际上,我可以保证我在过去的工作中已经在现实生活中构建了此报告。 或矩阵中出现故障。 无论哪种方式,我们都在这样做。

Here is what we’re going to be building…

这就是我们将要建造的……

Normally the way you would build this is with some sort of report server. Something like SQL Server Reporting Services or Business Objects or whatever other report servers are out there. Honestly, I don’t want to know. But if you don’t have a report server, this gets kind of tedious.

通常,构建此报表的方式是使用某种报表服务器。 诸如SQL Server报表服务或业务对象之类的东西或其他任何报表服务器都在那儿。 老实说,我不想知道。 但是,如果您没有报表服务器,这将变得很乏味。

Let’s go over what you have to do to make this happen…

让我们回顾一下实现此目标所需要做的工作……

  1. Run a job on some sort of timer (cron job)

    在某种计时器上运行作业(定时作业)
  2. Query a database

    查询数据库
  3. Iterate over records and format them for output to the screen

    遍历记录并将其格式化以输出到屏幕
  4. Email said report

    电子邮件说报告
  5. Update your resume and contact recruiters

    更新您的简历并联系招聘人员

This is the kind of thing that nobody wants to do. But I think this project can be a lot of fun, and we can use some interesting technology to pull it off. Starting with Serverless.

这是没人愿意做的事情。 但是我认为这个项目可能会很有趣,我们可以使用一些有趣的技术来实现它。 从无服务器开始。

无服务器计时器功能 (Serverless timer functions)

Serverless is a really good use case for one-off requests like this. In this case, we can use Azure Functions to create a Timer Trigger function.

对于这样的一次性请求,无服务器是一个非常好的用例。 在这种情况下,我们可以使用Azure Functions创建一个Timer Trigger函数。

To do that, I’m going to use the Azure Functions extension for VS Code. I’m going to use it for everything in fact. Why? Because I don’t know you, but I do know it’s highly likely that you are using VS Code. VS Code is great because it’s like a movie that all developer’s can universally agree is completely awesome. Sort of the opposite of “Children of Men”. That movie was terrible and you know it.

为此,我将对VS Code使用Azure Functions扩展。 实际上,我将用它来做所有事情。 为什么? 因为我不认识您,但我确实知道您很有可能正在使用VS Code。 VS Code很棒,因为它就像一部电影,所有开发人员都可以普遍认为这是一部很棒的电影。 有点像“男人的孩子”。 那部电影太可怕了,你知道的。

Make sure you install the Azure Functions extension.

确保安装Azure Functions扩展。

Azure Functions - Visual Studio MarketplaceExtension for Visual Studio Code - An Azure Functions extension for Visual Studio Code.marketplace.visualstudio.com

Azure功能 -Visual Studio代码的 Visual Studio市场 扩展-Visual Studio代码的Azure函数扩展。 marketplace.visualstudio.com

Now create a new Function App from within VS Code.

现在,从VS Code中创建一个新的Function App。

Then create a new Timer Trigger function. Timer Trigger functions are scheduled using standard Cron Expressions. You have likely not ever seen before because I had not seen one until a few months ago. And I’ve been in this industry for a LONG time. I am old, father William.

然后创建一个新的计时器触发功能。 计时器触发功能是使用标准Cron表达式安排的。 您可能以前从未见过,因为几个月前我才见过。 我在这个行业工作了很长时间。 我老了,父亲威廉。

Cron expressions look kind of scary cause they have asterisks in them. In the case below, I’m saying that when minutes is 0 and seconds is 0 and hours is evenly divisible by 24, fire the function. This would be midnight.

Cron表达式看起来有点吓人,因为它们中带有星号。 在以下情况下,我要说的是,当分钟为0且秒为0且小时可以被24整除时,触发该函数。 这将是午夜。

Now we can run this locally (F5). We’ll see in the embedded terminal the schedule on which our Function will be called; the next 5 occurrences.

现在我们可以在本地运行它(F5)。 我们将在嵌入式终端中看到将调用我们的Function的时间表; 接下来的5次。

It feels good, man.

感觉很好,伙计。

OK, now we need to get some data. I’m not going to drag you into the specifics of me querying SQL Server from this function because that’s not what this article is about, but here’s the code anyway.

好的,现在我们需要获取一些数据。 我不会把您拖到从该函数查询SQL Server的细节中,因为这与本文无关,但无论如何这里都是代码。

const { Connection, Request } = require('tedious');const options = {weekday: 'long',year: 'numeric',month: 'long',day: 'numeric'
};const config = {userName: process.env.SQL_USERNAME,password: process.env.SQL_PASSWORD,server: process.env.SQL_SERVER,options: {encrypt: true,database: process.env.SQL_DATABASE}
};module.exports = function(context, myTimer) {getChangedSkus().then(data => {if (data.length > 0) {sendEmail(context, data);} else {context.done();}}).catch(err => {context.log(`ERROR: ${err}`);});
};/*** Executes a query against the database for SKU's changed in the last 24 hours* @returns {Promise} Promise object contains result of query*/
function getChangedSkus() {return new Promise((resolve, reject) => {const connection = new Connection(config);const query = `SELECT Sku, Quantity, CONVERT(varchar, Modified, 0) as ModifiedFROM InventoryWHERE Modified >= dateadd(day, -1, getdate())`;connection.on('connect', err => {if (err) reject(err);let request = new Request(query, err => {if (err) {reject(err);}});const results = [];request.on('row', columns => {let result = {};columns.forEach(column => {result[column.metadata.colName] = column.value;});results.push(result);});request.on('doneProc', (rowCount, more) => {resolve(results);});connection.execSql(request);});});
}

I’m connecting to the database, doing a simple query and….wait a minute…did not I say I wasn’t going to get into specifics? You had me there for a minute, but I’m onto your game!

我正在连接到数据库,进行简单的查询,然后……等一下……不是我说我打算讲细节吗? 你在那儿呆了我一分钟,但是我正在玩你的游戏!

So this pulls in data and we get it in a JavaScript object that we can pass as JSON. If we were to JSON.stringify this, we will see the data set that we need to send in the report.

因此,这会提取数据,并将其获取到我们可以作为JSON传递JavaScript对象中。 如果要使用JSON.stringify ,我们将在报告中看到需要发送的数据集。

[{ "Sku": "1", "Quantity": 65, "Modified": "Nov  6 2018 10:14PM" },{ "Sku": "10", "Quantity": 89, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "11", "Quantity": 39, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "12", "Quantity": 2, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "13", "Quantity": 75, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "14", "Quantity": 85, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "15", "Quantity": 58, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "16", "Quantity": 2, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "17", "Quantity": 48, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "18", "Quantity": 68, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "19", "Quantity": 67, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "2", "Quantity": 5, "Modified": "Nov  6 2018 11:18PM" },{ "Sku": "20", "Quantity": 37, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "21", "Quantity": 54, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "22", "Quantity": 21, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "23", "Quantity": 46, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "24", "Quantity": 55, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "25", "Quantity": 21, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "26", "Quantity": 42, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "27", "Quantity": 65, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "28", "Quantity": 74, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "29", "Quantity": 33, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "3", "Quantity": 51, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "4", "Quantity": 96, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "5", "Quantity": 27, "Modified": "Nov  6 2018 11:18PM" },{ "Sku": "6", "Quantity": 13, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "7", "Quantity": 54, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "8", "Quantity": 89, "Modified": "Nov  2 2018  8:18PM" },{ "Sku": "9", "Quantity": 56, "Modified": "Nov  2 2018  8:18PM" }
]

OK! We’ve got data, now we just need to make it pretty and email it to someone we don’t like. How are we going to do that? With SendGrid!

好! 我们有数据,现在只需要使其漂亮,然后通过电子邮件将其发送给我们不喜欢的人即可。 我们该怎么做? 使用SendGrid!

SendGrid设置 (SendGrid setup)

SendGrid is a nifty service with a really nice dashboard. You will like it. Or you won’t. Either way, you have to use it to get through this blog post.

SendGrid是一个很棒的服务,具有非常好的仪表板。 你会喜欢它。 否则你不会。 无论哪种方式,您都必须使用它来浏览此博客文章。

You can create a free account if you don’t already have one. That’s plenty for what we’re doing here today.

如果您还没有免费帐户,则可以创建一个免费帐户。 对于我们今天在这里所做的事情来说,这已经足够了。

Once you create a report, SendGrid is going to drop you into your “dashboard”. From this dashboard, you need to create a new API Application and get the key.

创建报告后,SendGrid将使您进入“仪表板”。 从此仪表板,您需要创建一个新的API应用程序并获取密钥。

Make sure you copy your API key when it gives it to you. You can’t ever get back to it and you’ll have to do this all over again. Let’s face it: it was kinda boring the first time around.

确保将API密钥提供给您时将其复制。 您再也无法恢复原状,您将不得不重新做一遍。 让我们面对现实:这是第一次很无聊。

Copy that key into your Azure Functions project. Put it in the local.settings.json file so you can access it as a Node.js environment variable later.

将该密钥复制到您的Azure Functions项目中。 将其放在local.settings.json文件中,以便以后可以将其作为Node.js环境变量进行访问。

{"IsEncrypted": false,"Values": {"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=reporttimerstorage;AccountKey=OJVYCHI0GhtIm5XZdsDzGZFraJD/v/rfPwMSu4B72Kf5/O7oCrOQKNAFkQ==","FUNCTIONS_WORKER_RUNTIME": "node","SENDGRID_API_KEY": "SG.rlpDOy3EQNOTChnzpa1COPYg.G4MYlEYhwHk0RyvuGcY_xKEYbhQoFTtPB9A9-5ZaYQ"}
}

Now we are going to create a template in SendGrid. That’s what we will use to design our report. SendGrid has something called “Transactional Templates”. I have no idea why they are called that, but we are going to be needing one.

现在,我们将在SendGrid中创建一个模板。 这就是我们将用来设计报告的内容。 SendGrid有一个称为“事务模板”的东西。 我不知道为什么要这样称呼他们,但我们将需要一个。

Once you create a new one, you have to create a new “version”. I had a hilariously hard time figuring this out. But then again, my brain is tad on the smallish side of little.

创建新版本后,您必须创建一个新的“版本”。 我很难解决这个问题。 但是话又说回来,我的大脑在小小的一面。

Choose to design your template with the Code Editor. You don’t need no freakin’ Designer Editor!

选择使用代码编辑器设计模板。 您不需要任何freakin'Designer编辑器!

SendGrid support handlebars, which is a template syntax that’s so easy, even I can do it. In the Code Editor, you can paste the JSON data into the “Test Data” tab…

SendGrid支持把手,这是一个模板语法,非常简单,即使我也可以做到。 在代码编辑器中,您可以将JSON数据粘贴到“测试数据”标签中…

Now iterate over the data using its key name from the JSON…

现在,使用来自JSON的键名遍历数据…

It’s BEAUTIFUL! I’m crying. Ship it.

真漂亮! 我在哭 装运它。

ALRIGHT. Fine. We’ll make it a little nicer on the old eyeballs. Here is a style that I shamelessly ripped off of the gorgeous Bulma CSS framework.

好的。 精细。 我们将在旧的眼球上使它更好一点。 这是我从华丽的Bulma CSS框架中毫不客气地撕下的样式 。

<style>table {border-collapse: collapse;border-spacing: 0;background-color: white;color: #363636;}.table td,.table th {border: 1px solid #dbdbdb;border-width: 0 0 1px;padding: 0.5em 0.75em;vertical-align: top;}.table th {color: #363636;text-align: left;}.table thead td,.table thead th {border-width: 0 0 2px;color: #363636;}.table tbody tr:last-child td,.table tbody tr:last-child th {border-bottom-width: 0;}.table.is-bordered td,.table.is-bordered th {border-width: 1px;}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th {border-bottom-width: 1px;}.table.is-fullwidth {width: 100%;}.container {margin: 0 auto;position: relative;max-width: 960px;padding-top: 20px;font-family: helvetica, sans-serif;}
</style><div class="container"><h1>Modified SKUs</h1><p>The following SKU's were modified in the last 24 hours</p><table class="table is-fullwidth"><thead><tr><th>Sku</th><th>Quantity</th><th>Last Modified</th></tr></thead><tbody>{{#each Skus}}<tr><td>{{Sku}}</td><td>{{Quantity}}</td><td>{{Modified}}</td></tr>{{/each}}</tbody></table>
</div>

It’s ok at this point for you to be audibly impressed.

此时,可以给您留下深刻的印象。

Now you might have noticed that the Subject of the email is missing. How do we fill that in? Well, after another embarrassing period of failure followed by introspection, I figured out that it’s behind the “Settings” icon on the left. You just have to pass a value in your JSON for “Subject”.

现在您可能已经注意到电子邮件的主题丢失。 我们如何填写呢? 好吧,在经历了令人尴尬的失败和自省之后,我发现它位于左侧的“设置”图标后面。 您只需要在JSON中为“主题”传递一个值。

Now we need to get the template ID and add it to our Azure Functions project. Save this template and select the ID from the main template screen.

现在,我们需要获取模板ID,并将其添加到我们的Azure Functions项目中。 保存此模板,然后从主模板屏幕中选择ID。

Drop it in the trusty local.settings.json file right underneath your SendGrid API key.

将其放置在SendGrid API密钥下方的可信任的local.settings.json文件中。

{"IsEncrypted": false,"Values": {"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=reporttimerstorage;AccountKey=OJVYCHI0GhtIm5XZdsDzGZFraJD/v/rfPwMSu4B72Kf5/O7oCrOQKNAFkQ==","FUNCTIONS_WORKER_RUNTIME": "node","SENDGRID_API_KEY": "SG.rlpDOy3EQNOTChnzpa1COPYg.G4MYlEYhwHk0RyvuGcY_xKEYbhQoFTtPB9A9-5ZaYQ""SENDGRID_TEMPLATE_ID": "d-3e33c1453cf7457fb06e6d30519bd422"}
}

Now we are ready to pass our data from our Azure Function to SendGrid and send out this incredible work of business art.

现在,我们准备将数据从Azure功能传递到SendGrid,并发送这种令人难以置信的商业艺术品。

Azure函数的SendGrid绑定 (SendGrid bindings for Azure Functions)

Azure Functions provides a binding for SendGrid. If you create a function through the Azure Portal, it will create this binding for you when you select the “SendGrid” template. If you are doing it locally like I am, you have to add it yourself.

Azure Functions为SendGrid提供了绑定。 如果通过Azure门户创建函数,则在选择“ SendGrid”模板时将为您创建此绑定。 如果您像我一样在本地进行操作,则必须自己添加。

First you need to open the function.json file for the CreateReport function and add in the SendGrid binding.

首先,您需要打开CreateReport函数的function.json文件,并添加SendGrid绑定。

{"type": "sendGrid","name": "message","apiKey": "SENDGRID_API_KEY","to": "youremail@company.com","from": "hahabusiness@businesstime.com","direction": "out"
}

The SendGrid binding comes as an extension for Azure Functions. Run the following command in the terminal to install it.

SendGrid绑定是Azure功能的扩展。 在终端中运行以下命令进行安装。

Microsoft.Azure.WebJobs.Extensions.SendGrid -Version 3.0.0

When you run this command, VS Code will ask you to restore some dependencies. You can click restore. Nothing bad will happen…OR WILL IT?!

当您运行此命令时,VS Code将要求您还原一些依赖项。 您可以单击还原。 不会发生任何坏事...或者会吗?

One other thing you need to do is tweak your extensions.csproj file to reference the latest SendGrid library. This is required to use dynamic templates.

您需要做的另一件事是调整extensions.csproj文件以引用最新的SendGrid库。 这是使用动态模板所必需的。

<PackageReference Include="Sendgrid" Version="9.10.0" />

When you add that, VS Code will prompt you to restore again and yes, you definitely need to do it this time. VS Code needs to build these binaries and the restore does that.

添加后,VS Code会提示您再次还原,是的,您这次肯定需要这样做。 VS Code需要构建这些二进制文件,然后还原即可完成。

OK! Now we’re ready to send an email via our SendGrid template. Here is the code to do it. It’s depressingly simple. I know after all this you were hoping for enough code to choke a cat (what? you’ve never heard that metaphor before?), but this is all it takes.

好! 现在,我们准备通过我们的SendGrid模板发送电子邮件。 这是执行此操作的代码。 令人沮丧的简单。 我知道所有这些之后,您希望有足够的代码来扼杀猫(这是什么?您以前从未听说过这种隐喻吗?),但这就是全部。

function sendEmail(context, data) {context.done(null, {message: {/* you can override the to/from settings from function.json here if you would liketo: 'someone@someplace.com',from: 'someone@anotherplace.com'*/personalizations: [{dynamic_template_data: {Subject: `Tailwind SKU Report For ${new Date().toLocaleDateString('en-US',options)}`,Skus: data}}],template_id: process.env.SENDGRID_TEMPLATE_ID}});
}

The items of note are me passing in a Subject as part of the JSON. As well as the fact that you can override to/from addresses specified in the function.json file here.

注意事项是我传入了Subject作为JSON的一部分。 以及您可以覆盖此处/来自function.json文件中指定的地址的事实。

Now you can run your function and wait 24 hours to test it!

现在,您可以运行您的函数并等待24小时进行测试!

No but seriously — how do you manually test a Timer Trigger without constantly modifying the damn Cron Job?

不,但是很认真-您如何在不不断修改该死的Cron Job的情况下手动测试计时器触发器?

I’ll show you how I do it and then you can figure out a better way.

我将向您展示如何做到这一点,然后您可以找出一种更好的方法。

使用http触发器测试计时器触发器 (Testing timer triggers with http triggers)

I create an Http Trigger in the same project and call it “RunCreateReport”. In that function, I just import and call the timer function.

我在同一项目中创建一个Http触发器,并将其称为“ RunCreateReport”。 在该函数中,我只是导入并调用timer函数。

const index = require('../CreateReport/index');module.exports = function(context, req) {// This is a tester function that manually executes the CreateReport timer functionindex(context);
};

The only drawback to this is that you have to repeat your SendGrid binding settings from function.json in the “CreateReport” over in the “RunCreateReport” function.json. But other than that, this works just fine. Now you can run this thing, fire up a browser and hit the URL which will call the timer function immediately. You can test without having to touch that icky old Cron expression.

这样做的唯一缺点是,必须在“ RunCreateReport” function.json的“ CreateReport”中重复执行function.json中的SendGrid绑定设置。 除此之外,这还行得通。 现在您可以运行该程序,启动浏览器并单击URL,该URL将立即调用timer函数。 您可以进行测试,而无需触碰那个令人讨厌的Cron旧表达式。

哈哈业务 (HAHA business)

Now go check your email and bask in the glory of the report. Note that you don’t have to own an email address to send from SendGrid. You can literally send from any address. Seriously. Go ahead and try. JUST THINK OF WHAT YOU CAN DO WITH THIS POWER.

现在,请检查您的电子邮件,并仔细阅读报告的内容。 请注意,您不必拥有要从SendGrid发送的电子邮件地址。 您可以从任何地址直接发送。 说真的 继续尝试。 只需考虑一下您可以使用此功能做什么。

Here’s what my inbox looks like. Heads up, it does go to junk. Probably because I don’t own the sender email address.

这是我的收件箱的样子。 抬起头,它确实会变成垃圾。 可能是因为我没有发件人的电子邮件地址。

WHAT? There’s a “Business Resilience Conference”? OMG so much business. I bet those people get a LOT of reports.

什么? 有“业务弹性会议”吗? OMG生意这么好。 我敢打赌那些人会得到很多报道。

You can get this project from Github.

您可以从Github获得该项目。

burkeholland/serverless-sendgrid-reportContribute to burkeholland/serverless-sendgrid-report development by creating an account on GitHub.github.com

burkeholland / serverless- sendgrid-report通过在GitHub上创建一个帐户来为burkeholland / serverless-sendgrid-report开发做出贡献。 github.com

Here are a few other Azure Functions resources to keep you busy.

这是其他一些Azure Functions资源,可让您保持忙碌。

  • Deploy to Azure using Azure Functions

    使用Azure Functions部署到Azure

  • Azure Functions JavaScript developer guide

    Azure Functions JavaScript开发人员指南

  • Migrating a Mongo DB API to Azure Functions

    将Mongo DB API迁移到Azure函数

翻译自: https://www.freecodecamp.org/news/how-to-build-a-serverless-report-server-with-azure-functions-and-sendgrid-3c063a51f963/

azure服务器

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

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

相关文章

【GoWeb开发实战】Cookie

cookie Web开发中一个很重要的议题就是如何做好用户的整个浏览过程的控制&#xff0c;因为HTTP协议是无状态的&#xff0c;所以用户的每一次请求都是无状态的&#xff0c;我们不知道在整个Web操作过程中哪些连接与该用户有关&#xff0c;我们应该如何来解决这个问题呢&#xff…

PhotoKit 照片库的管理-获取图像

PHAsset部分属性解析 1、HDR 和全景照片 mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了 HDR&#xff0c;拍摄时是否使用了相机应用的全景模式。 2、收藏和隐藏资源 要验证一个资源是否被用户标记为收藏或被隐藏&#xff0c;只要检查 PHAsset 实例的 favorite 和 hid…

cmail服务器安装后无法登录的解决办法

安装cmailserver 5.4.6软件安装、注册都非常顺利&#xff0c;webmail页面也都正常打开&#xff0c;但是一点“登录”就提示错误&#xff1a; Microsoft VBScript 运行时错误 错误 800a01ad ActiveX 部件不能创建对象: CMailCOM.POP3.1 /mail/login.asp&#xff0c;行 42 点“…

matlab对人工智能,MATLAB与人工智能深度学习和机器学习.PDF

MATLAB与人工智能深度学习和机器学习MATLAB 与人工智能&#xff1a;深度学习有多远&#xff1f;© 2017 The MathWorks, Inc.1机器学习8机器学习无处不在▪ 图像识别 [TBD]▪ 语音识别▪ 股票预测▪ 医疗诊断▪ 数据分析▪ 机器人▪ 更多……9什么是机器学习&#xff1f;机…

leetcode1471. 数组中的 k 个最强值(排序)

给你一个整数数组 arr 和一个整数 k 。 设 m 为数组的中位数&#xff0c;只要满足下述两个前提之一&#xff0c;就可以判定 arr[i] 的值比 arr[j] 的值更强&#xff1a; |arr[i] - m| > |arr[j] - m| |arr[i] - m| |arr[j] - m|&#xff0c;且 arr[i] > arr[j] 请返回…

Spring中WebApplicationInitializer的理解

现在JavaConfig配置方式在逐步取代xml配置方式。而WebApplicationInitializer可以看做是Web.xml的替代&#xff0c;它是一个接口。通过实现WebApplicationInitializer&#xff0c;在其中可以添加servlet&#xff0c;listener等&#xff0c;在加载Web项目的时候会加载这个接口实…

使用fetch封装请求_关于如何使用Fetch API执行HTTP请求的实用ES6指南

使用fetch封装请求In this guide, I’ll show you how to use the Fetch API (ES6) to perform HTTP requests to an REST API with some practical examples you’ll most likely encounter.在本指南中&#xff0c;我将向您展示如何使用Fetch API(ES6 )来执行对REST API的 HTT…

hadoop集群中客户端修改、删除文件失败

这是因为hadoop集群在启动时自动进入安全模式 查看安全模式状态&#xff1a;hadoop fs –safemode get 进入安全模式状态&#xff1a;hadoop fs –safemode enter 退出安全模式状态&#xff1a;hadoop fs –safemode leave转载于:https://www.cnblogs.com/lishengnan/p/a123.ht…

OpenStack nova-network 支持多vlan技术实现片段代码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748

Rest API

什么是接口测试 接口测试又称 API 测试 Application Programming Interface 接口测试是测试系统组件间接口的一种测试。重点关注数据传递。 接口测试一般会用于多系统间交互开发&#xff0c;或者拥有多个子系统的应用系统开发的测试。 为什么要做接口测试 很多系统关联都是基于…

php循环checkbox,php循环删除checkbox | 学步园

一、首先要了解sql语句$SQLdelete from user where id in (1,2,4);表单大概是&#xff1a;form action methodpost input nameID_Dele[] typecheckbox idID_Dele[] value1input nameID_Dele[] typecheckbox idID_Dele[] value2input nameID_Dele[] type首先要了解sql语句$SQL&q…

leetcode1451. 重新排列句子中的单词(排序)

「句子」是一个用空格分隔单词的字符串。给你一个满足下述格式的句子 text : 句子的首字母大写 text 中的每个单词都用单个空格分隔。 请你重新排列 text 中的单词&#xff0c;使所有单词按其长度的升序排列。如果两个单词的长度相同&#xff0c;则保留其在原句子中的相对顺序…

Java+Oracle实现事务——JDBC事务

J2EE支持JDBC事务、JTA事务和容器事务事务&#xff0c;这里说一下怎样实现JDBC事务。 JDBC事务是由Connection对象所控制的&#xff0c;它提供了两种事务模式&#xff1a;自己主动提交和手动提交&#xff0c;默认是自己主动提交。 自己主动提交就是&#xff1a;在JDBC中。在一个…

开源项目贡献者_我如何从一名贡献者转变为一个开源项目维护者

开源项目贡献者by Dhanraj Acharya通过Dhanraj Acharya 我如何从一名贡献者转变为一个开源项目维护者 (How I went from being a contributor to an Open Source project maintainer) I was a lone software developer. When I was in college, I attended the KDE conference…

网络摄像头CVE

CVE-2018-9995 rtsp未授权访问 rtsp后缀整理&#xff1a; Axis&#xff08;安讯士&#xff09; rtsp:// 192.168.200.202/axis-media/media.amp?videocodech264&resolution1280x720 rtsp://IP地址/mpeg4/media.amp rtsp://IP地址/安迅士/AXIS-media/media.amp123D-Link …

Centos中不从skel目录里向其中复制任何文件错误的解决方法

[rootlocalhost www]# useradd -d /webserver/www/ ithovcom useradd&#xff1a;警告&#xff1a;此主目录已经存在。 不从 skel 目录里向其中复制任何文件。 [rootlocalhost www]# ls -a .&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp; .. 发现没…

leetcode91. 解码方法

一条包含字母 A-Z 的消息通过以下方式进行了编码&#xff1a; ‘A’ -> 1 ‘B’ -> 2 … ‘Z’ -> 26 给定一个只包含数字的非空字符串&#xff0c;请计算解码方法的总数。 示例 1: 输入: “12” 输出: 2 解释: 它可以解码为 “AB”&#xff08;1 2&#xff09;或者…

php 系统平均负载,Linux_解析Linux系统的平均负载概念,一、什么是系统平均负载(Load a - phpStudy...

解析Linux系统的平均负载概念一、什么是系统平均负载(Load average)&#xff1f;在Linux系统中&#xff0c;uptime、w、top等命令都会有系统平均负载load average的输出&#xff0c;那么什么是系统平均负载呢&#xff1f;系统平均负载被定义为在特定时间间隔内运行队列中的平均…

Elastic-job使用及原理

一、原理 elastic-job有lite版和cloud版&#xff0c;最大的区别是有无调度中心&#xff0c;笔者采用的是lite版本&#xff0c;无中心化。 tips: 第一台服务器上线触发主服务器选举。主服务器一旦下线&#xff0c;则重新触发选举&#xff0c;选举过程中阻塞&#xff0c;只有主服…

构建持续交付_如何使交付成为您的重点将如何帮助您构建高质量的应用程序

构建持续交付by Simon Schwartz西蒙施瓦茨(Simon Schwartz) 如何使交付成为您的重点将如何帮助您构建高质量的应用程序 (How making delivery your focus will help you build quality applications) I was recently asked by our company’s executive team why our team was…