websockets_如何将WebSockets与AWS API Gateway和Lambda一起使用来构建实时应用程序
websockets
by Janitha Tennakoon
通过詹妮莎·特纳库恩
如何将WebSockets与AWS API Gateway和Lambda一起使用来构建实时应用程序 (How to build real-time applications using WebSockets with AWS API Gateway and Lambda)
Recently AWS has announced the launch of a widely-requested feature: WebSockets for Amazon API Gateway. With WebSockets, we are able to create a two-way communication line which can be used in many scenarios like real-time applications. This brings up the question: what are real-time applications? So let’s first answer that question.
最近,AWS宣布推出了一项广受欢迎的功能:用于Amazon API Gateway的WebSockets。 借助WebSocket,我们能够创建双向通信线路,该线路可用于许多场景,例如实时应用程序。 这就提出了一个问题:什么是实时应用程序? 因此,让我们首先回答这个问题。
Most of the applications that are currently operational use client-server architecture. In client-server architecture, the client sends the requests over the Internet using network communication and then the server processes that request and sends the response back to the client.
当前可运行的大多数应用程序都使用客户端-服务器体系结构。 在客户端-服务器体系结构中,客户端使用网络通信通过Internet发送请求,然后服务器处理该请求并将响应发送回客户端。
Here you can see that it is the client that starts off the communication with the server. So first the client initiates the communication and the server responds to the request sent by the server. So what if the server wants to start off the communication and push responses without the client requesting them first? That is where real-time applications come into the play.
在这里,您可以看到是客户端开始与服务器的通信。 因此,首先客户端启动通信,然后服务器响应服务器发送的请求。 那么,如果服务器要开始通信并推送响应而客户端不首先请求响应该怎么办? 这就是实时应用程序发挥作用的地方。
Real-time applications are applications where the server gets the ability to push to the clients without the client requesting data first. Assume we have a chat application where two chat clients can communicate via a server. In this situation, it is a waste if all the chat clients request data from the server like every second. What is more efficient is if the server sends data to client chat applications when a chat is received. This functionality can be done through real-time applications.
实时应用程序是服务器无需客户端先请求数据就可以推送到客户端的应用程序。 假设我们有一个聊天应用程序,其中两个聊天客户端可以通过服务器进行通信。 在这种情况下,如果所有聊天客户端都每秒都向服务器请求数据,那将是一种浪费。 更有效率的是,如果服务器在接收到聊天时将数据发送到客户端聊天应用程序。 此功能可以通过实时应用程序完成。
Amazon announced that they are going to support WebSockets in API Gateway at AWS re:Invent 2018. Later in December, they launched it in the API Gateway. So now using AWS infrastructure we are able to create real-time applications using API Gateway.
亚马逊宣布将在AWS re:Invent 2018上支持API Gateway中的WebSockets。12月下旬,他们在API Gateway中启动了WebSockets。 因此,现在使用AWS基础设施,我们可以使用API Gateway创建实时应用程序。
In this post, we are going to create a simple chat application using API Gateway WebSockets. Before we start implementing our chat application, there are some concepts that we need to understand regarding real-time applications and API Gateway.
在本文中,我们将使用API Gateway WebSockets创建一个简单的聊天应用程序。 在开始实现聊天应用程序之前,我们需要了解一些有关实时应用程序和API网关的概念。
WebSocket API概念 (WebSocket API Concepts)
A WebSocket API is composed of one or more routes. A route selection expression is there to determine which route a particular inbound request should use, which will be provided in the inbound request. The expression is evaluated against an inbound request to produce a value that corresponds to one of your route’s routeKey values. For example, if our JSON messages contain a property call action, and you want to perform different actions based on this property, your route selection expression might be ${request.body.action}
.
WebSocket API由一个或多个路由组成。 路由选择表达式用于确定特定入站请求应使用的路由,该选择将在入站请求中提供。 根据入站请求对表达式进行求值,以生成与您的路线的routeKey值之一相对应的值。 例如,如果我们的JSON消息包含一个属性调用操作,并且您想基于此属性执行其他操作,则您的路线选择表达式可能是${request.body.action}
。
For example: if your JSON message looks like {“action” : “onMessage” , “message” : “Hello everyone”}, then the onMessage route will be chosen for this request.
例如:如果您的JSON消息看起来像{“ action”:“ onMessage”,“ message”:“大家好”},那么将为此请求选择onMessage路由。
By default, there are three routes which are already defined in the WebSocket API. In addition to the below-mentioned routes, we can add custom routes for our needs.
默认情况下,WebSocket API中已经定义了三种路由。 除了以下提到的路线外,我们还可以根据需要添加自定义路线。
$default — Used when the route selection expression produces a value that does not match any of the other route keys in your API routes. This can be used, for example, to implement a generic error handling mechanism.
$ default —当路由选择表达式产生的值与API路由中的任何其他路由键都不匹配时使用。 例如,这可用于实现通用错误处理机制。
$connect — The associated route is used when a client first connects to your WebSocket API.
$ connect —客户端第一次连接到WebSocket API时使用关联的路由。
$disconnect — The associated route is used when a client disconnects from your API.
$ disconnect —当客户端从您的API断开连接时,将使用关联的路由。
Once a device is successfully connected through WebSocket API, the device will be allocated with a unique connection id. This connection id will be persisted throughout the lifetime if the connection. To send messages back to the device we need to use the following POST request using the connection id.
通过WebSocket API成功连接设备后,将为该设备分配唯一的连接ID。 如果建立连接,则该连接ID将在整个生命周期中保持不变。 要将消息发送回设备,我们需要使用以下带有连接ID的POST请求。
POST https://{api-id}.execute-api.us-east 1.amazonaws.com/{stage}/@connections/{connection_id}
实施聊天应用 (Implementing chat application)
After learning the basic concepts of the WebSocket API, let us look at how we can create a real-time application using WebSocket API. In this post, we are going to implement a simple chat application using WebSocket API, AWS LAmbda and DynamoDB. The following diagram shows the architecture of our real-time application.
在学习了WebSocket API的基本概念之后,让我们看一下如何使用WebSocket API创建实时应用程序。 在本文中,我们将使用WebSocket API,AWS LAmbda和DynamoDB实现一个简单的聊天应用程序。 下图显示了我们实时应用程序的体系结构。
In our application, devices will be connected to the API Gateway. When a device gets connected, a lambda function will save the connection id in a DynamoDB table. In an instance where we want to send a message back to the device, another lambda function will retrieve the connection id and POST data back to the device using a callback URL.
在我们的应用程序中,设备将连接到API网关。 连接设备后,lambda函数会将连接ID保存在DynamoDB表中。 在我们要将消息发送回设备的实例中,另一个lambda函数将使用回调URL检索连接ID和POST数据回到设备。
创建WebSocket API (Creating WebSocket API)
In order to create the WebSocket API, we need first go to Amazon API Gateway service using the console. In there choose to create new API. Click on WebSocket to create a WebSocket API, give an API name and our Route Selection Expression. In our case add $request.body.action as our selection expression and hit Create API.
为了创建WebSocket API,我们首先需要使用控制台进入Amazon API Gateway服务。 在其中选择创建新的API。 单击WebSocket创建一个WebSocket API,提供一个API名称和我们的路由选择表达式。 在本例中,将$ request.body.action添加为选择表达式,然后点击Create API。
After creating the API we will be redirected to the routes page. Here we can see already predefined three routes: $connect, $disconnect and $default. We will also create a custom route $onMessage. In our architecture, $connect and $disconnect routes achieve the following tasks:
创建API后,我们将被重定向到路由页面。 在这里,我们可以看到已经预定义的三个路由:$ connect,$ disconnect和$ default。 我们还将创建一个自定义路由$ onMessage。 在我们的体系结构中,$ connect和$ disconnect路由完成以下任务:
- $connect — when this route is called, a Lambda function will add the connection id of the connected device to DynamoDB.$ connect —调用此路由时,Lambda函数会将已连接设备的连接ID添加到DynamoDB。
- $disconnect — when this route is called, a Lambda function will delete the connection id of the disconnected device from DynamoDB.$ disconnect —调用此路由时,Lambda函数将从DynamoDB中删除断开连接的设备的连接ID。
- onMessage — when this route is called, the message body will be sent to all the devices that are connected at the time.onMessage —调用此路由时,消息正文将发送到当时连接的所有设备。
Before adding the route according to the above, we need to do four tasks:
在根据上述步骤添加路由之前,我们需要完成以下四个任务:
- Create a DynamoDB table创建一个DynamoDB表
- Create connect lambda function创建连接lambda函数
- Create disconnect lambda function创建断开连接lambda函数
- Create onMessage lambda function创建onMessage lambda函数
First, let us create the DynamoDB table. Go to DynamoDB service and create a new table called Chat. Add primary key as ‘connectionid’.
首先,让我们创建DynamoDB表。 转到DynamoDB服务并创建一个名为Chat的新表。 将主键添加为“ connectionid”。
Next, let’s create the connect Lambda function. To create the Lambda function, go to Lambda services and click create function. Select Author from scratch and give the name as ‘ChatRoomConnectFunction’ and a role with necessary permissions. (The role should have the permission to get, put and delete items from DynamoDB, call API calls in API gateway.)
接下来,让我们创建connect Lambda函数。 要创建Lambda函数,请转到Lambda服务,然后单击创建函数。 从头开始选择“作者”,并将其命名为“ ChatRoomConnectFunction”,并指定一个具有必要权限的角色。 (该角色应具有从DynamoDB获取,放置和删除项目,在API网关中调用API调用的权限。)
In the code of the lambda function add the following code. This code will add the connection id of the connected device to the DynamoDB table that we have created.
在lambda函数的代码中添加以下代码。 此代码会将已连接设备的连接ID添加到我们创建的DynamoDB表中。
exports.handler = (event, context, callback) => { const connectionId = event.requestContext.connectionId; addConnectionId(connectionId).then(() => { callback(null, { statusCode: 200, }) });}
function addConnectionId(connectionId) { return ddb.put({ TableName: 'Chat', Item: { connectionid : connectionId }, }).promise();}
Next, let us create the disconnect lambda function as well. Using the same steps create a new lambda function named ‘ChatRoomDonnectFunction’. Add the following code to the function. This code will remove the connection id from the DynamoDB table when a device gets disconnected.
接下来,让我们也创建断开连接lambda函数。 使用相同的步骤创建一个名为“ ChatRoomDonnectFunction”的新lambda函数。 将以下代码添加到函数中。 当设备断开连接时,此代码将从DynamoDB表中删除连接ID。
const AWS = require('aws-sdk');const ddb = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => { const connectionId = event.requestContext.connectionId; addConnectionId(connectionId).then(() => { callback(null, { statusCode: 200, }) });}
function addConnectionId(connectionId) { return ddb.delete({ TableName: 'Chat', Key: { connectionid : connectionId, }, }).promise();}
Now we have created the DynamoDB table and two lambda functions. Before creating the third lambda function, let us go back again to API Gateway and configure the routes using our created lambda functions. First, click on $connect route. As integration type, select Lambda function and select the ChatRoomConnectionFunction.
现在,我们已经创建了DynamoDB表和两个lambda函数。 在创建第三个lambda函数之前,让我们再次回到API网关,并使用创建的lambda函数配置路由。 首先,单击$ connect路由。 作为集成类型,选择Lambda函数,然后选择ChatRoomConnectionFunction。
We can do the same on $disconnect route as well where the lambda function will be ChatRoomDisconnectionFunction:
我们也可以在$ disconnect路由上执行相同的操作,其中lambda函数将是ChatRoomDisconnectionFunction:
Now that we have configured our $connect and $disconnect routes, we can actually test whether out WebSocket API is working. To do that we must first to deploy the API. In the Actions button, click on Deploy API to deploy. Give a stage name such as Test since we are only deploying the API for testing.
现在,我们已经配置了$ connect和$ disconnect路由,我们实际上可以测试WebSocket API是否有效。 为此,我们必须首先部署API。 在“操作”按钮中,单击“部署API”以进行部署。 由于我们仅部署API进行测试,因此请提供一个阶段名称(例如Test)。
After deploying, we will be presented with two URLs. The first URL is called WebSocket URL and the second is called Connection URL.
部署后,我们将看到两个URL。 第一个URL称为WebSocket URL,第二个称为Connection URL。
The WebSocket URL is the URL that is used to connect through WebSockets to our API by devices. And the second URL, which is Connection URL, is the URL which we will use to call back to the devices which are connected. Since we have not yet configured call back to devices, let’s first only test the $connect and $disconnect routes.
WebSocket URL是用于设备通过WebSocket连接到我们的API的URL。 第二个URL,即连接URL,是我们将用于回调已连接设备的URL。 由于尚未配置回叫设备,因此我们首先仅测试$ connect和$ disconnect路由。
To call through WebSockets we can use the wscat tool. To install it, we need to just issue the npm install -g wscat
command in the command line. After installing, we can use the tool using wscat command. To connect to our WebSocket API, issue the following command. Make sure to replace the WebSocket URL with the correct URL provided to you.
要通过WebSocket调用,我们可以使用wscat工具。 要安装它,我们只需要在命令行中发出npm install -g wscat
命令即可。 安装后,我们可以使用wscat命令使用该工具。 要连接到我们的WebSocket API,请发出以下命令。 确保使用提供给您的正确URL替换WebSocket URL。
wscat -c wss://bh5a9s7j1e.execute-api.us-east-1.amazonaws.com/Test
When the connection is successful, a connected message will be displayed on the terminal. To check whether our lambda function is working, we can go to DynamoDB and look in the table for the connection id of the connected terminal.
连接成功后,连接的消息将显示在终端上。 要检查我们的lambda函数是否正常工作,我们可以转到DynamoDB并在表中查找已连接终端的连接ID。
As above, we can test the disconnect as well by pressing CTRL + C which will simulate a disconnection.
如上所述,我们也可以通过按CTRL + C来测试断开连接,这将模拟断开连接。
Now that we have tested our two routes, let us look into the custom route onMessage. What this custom route will do is it will get a message from the device and send the message to all the devices that are connected to the WebSocket API. To achieve this we are going to need another lambda function which will query our DynamoDB table, get all the connection ids, and send the message to them.
现在我们已经测试了两条路由,让我们研究自定义路由onMessage。 该自定义路由将要执行的操作是,它将从设备获取消息,并将该消息发送到连接到WebSocket API的所有设备。 为此,我们将需要另一个lambda函数,该函数将查询我们的DynamoDB表,获取所有连接ID,并将消息发送给它们。
Let’s first create the lambda function in the same way we created other two lambda functions. Name the lambda function ChatRoomOnMessageFunction and copy the following code to the function code.
首先,以创建其他两个lambda函数的相同方式创建lambda函数。 将lambda函数命名为ChatRoomOnMessageFunction,然后将以下代码复制到该函数代码中。
const AWS = require('aws-sdk');const ddb = new AWS.DynamoDB.DocumentClient();require('./patch.js');
let send = undefined;function init(event) { console.log(event) const apigwManagementApi = new AWS.ApiGatewayManagementApi({ apiVersion: '2018-11-29', endpoint: event.requestContext.domainName + '/' + event.requestContext.stage }); send = async (connectionId, data) => { await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: `Echo: ${data}` }).promise(); }}
exports.handler = (event, context, callback) => { init(event); let message = JSON.parse(event.body).message getConnections().then((data) => { console.log(data.Items); data.Items.forEach(function(connection) { console.log("Connection " +connection.connectionid) send(connection.connectionid, message); }); }); return {}};
function getConnections(){ return ddb.scan({ TableName: 'Chat', }).promise();}
The above code will scan the DynamoDB to get all the available records in the table. For each record, it will POST a message using the Connection URL provided to us in the API. In the code, we expect that the devices will send the message in the attribute named ‘message’ which the lambda function will parse and send to others.
上面的代码将扫描DynamoDB以获取表中所有可用的记录。 对于每条记录,它将使用API中提供给我们的连接URL发布消息。 在代码中,我们期望设备将在名为“ message”的属性中发送消息,lambda函数将解析该消息并将其发送给其他人。
Since WebSockets API is still new there are some things we need to do manually. Create a new file named patch.js and add the following code inside it.
由于WebSockets API仍然是新的,因此我们需要手动执行一些操作。 创建一个名为patch.js的新文件,并在其中添加以下代码。
require('aws-sdk/lib/node_loader');var AWS = require('aws-sdk/lib/core');var Service = AWS.Service;var apiLoader = AWS.apiLoader;
apiLoader.services['apigatewaymanagementapi'] = {};AWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29']);Object.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', { get: function get() { var model = { "metadata": { "apiVersion": "2018-11-29", "endpointPrefix": "execute-api", "signingName": "execute-api", "serviceFullName": "AmazonApiGatewayManagementApi", "serviceId": "ApiGatewayManagementApi", "protocol": "rest-json", "jsonVersion": "1.1", "uid": "apigatewaymanagementapi-2018-11-29", "signatureVersion": "v4" }, "operations": { "PostToConnection": { "http": { "requestUri": "/@connections/{connectionId}", "responseCode": 200 }, "input": { "type": "structure", "members": { "Data": { "type": "blob" }, "ConnectionId": { "location": "uri", "locationName": "connectionId" } }, "required": [ "ConnectionId", "Data" ], "payload": "Data" } } }, "shapes": {} } model.paginators = { "pagination": {} } return model; }, enumerable: true, configurable: true});
module.exports = AWS.ApiGatewayManagementApi;
I took the above code from this article. The functionality of this code is to automatically create the Callback URL for our API and send the POST request.
我从本文中获取了以上代码。 此代码的功能是自动为我们的API创建回调URL并发送POST请求。
Now that we have created the lambda function we can go ahead and create our custom route in API Gateway. In the New Route Key, add ‘OnMessage’ as a route and add the custom route. As configurations were done for other routes, add our lambda function to this custom route and deploy the API.
现在我们已经创建了lambda函数,我们可以继续在API Gateway中创建自定义路由。 在“新路由键”中,添加“ OnMessage”作为路由并添加自定义路由。 完成其他路由的配置后,将lambda函数添加到此自定义路由并部署API。
Now we have completed our WebSocket API and we can fully test the application. To test that sending messages works for multiple devices, we can open and connect using multiple terminals.
现在,我们已经完成了WebSocket API,并且可以完全测试该应用程序。 为了测试发送消息是否适用于多个设备,我们可以使用多个终端打开并连接。
After connecting, issue the following JSON to send messages:
连接后,发出以下JSON发送消息:
{"action" : "onMessage" , "message" : "Hello everyone"}
Here, the action is the custom route we defined and the message is the data that need to be sent to other devices.
在这里,操作是我们定义的自定义路由,消息是需要发送到其他设备的数据。
That is it for our simple chat application using AWS WebSocket API. We have not actually configured the $defalut route which is called on every occasion where there no route is found. I will leave the implementation of that route to you. Thank you and see you in another post. :)
就是使用AWS WebSocket API的简单聊天应用程序。 我们实际上并未配置$ defalut路由,该路由在每次找不到路由的情况下都会被调用。 我将把这条路线的实施留给您。 谢谢,再见。 :)
翻译自: https://www.freecodecamp.org/news/real-time-applications-using-websockets-with-aws-api-gateway-and-lambda-a5bb493e9452/
websockets
相关文章:

JS对象转URL参数
代码: /*** param 将要转为URL参数字符串的对象* key URL参数字符串的前缀* encode true/false 是否进行URL编码,默认为true* idx ,循环第几次,用&拼接* return URL参数字符串*/ var urlEncode (param,idx, key, encode)> {console.log(idx,idx…

Windows下Redis如何永久更改密码
公司使用的是Spring-session-redis 需要给Redis配置一个密码 本来我配置密码的方法是 先打开Redis服务 在采用 命令 CONFIG SET requirepass "密码" AUTH 密码 但是这样配置完密码之后再重启Redis服务密码会重置 也就是说每次打开Redis服务都要重新再配置一下密码 …

CEGUI-----动画
Animation XML files. <AnimationDefinition> <Affector name‘要被改变的属性名’ interpolator‘关键帧之间平滑过度的数值’> //specifies the name of a property that will be affected (have its value changed) as part of the animation <KeyFrame>…

react hooks使用_如何使用Hooks将React类组件转换为功能组件
react hooks使用by Balaganesh Damodaran通过Balaganesh Damodaran 如何使用Hooks将React类组件转换为功能组件 (How to convert React class components to function components using Hooks) Over the course of the past month, I’ve spent a lot of time working with Re…

[精]Odoo 8.0深入浅出开发教程-模块开发基础
參考资料点击这里.构建Odoo模块模块组成业务对象业务对象声明为Python类, 由Odoo自己主动加载.数据文件XML或CSV文件格式, 在当中声明了元数据(视图或工作流)、配置数据(模块參数)、演示数据等.Web控制器处理Web浏览器发来的requests.静态web数据Web用到的图像, CSS或JavaScrip…

Java基础知识强化之IO流笔记41:字符流缓冲流之复制文本文件案例02(使用 [ newLine() / readLine() ] )(重要)...
1. 使用字符流缓冲流的特殊功能 [ newLine() / readLine() ] 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中 数据源: a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader 目的地:…

Ant Design Pro 跳转路由 传参数,接收参数
umi/link 通过声明的方式做路由跳转。 例子: import Link from umi/link;export default () => {<div>/* 普通使用 */<Link to="/list">Go to list page</Link>/* 带参数 */<Link to="/list?a=b">Go to list page</Lin…

编写react组件_React组件的“黄金法则”如何帮助您编写更好的代码
编写react组件以及钩子如何发挥作用 (And how hooks come into play) Recently I’ve adopted a new philosophy that changes the way I make components. It’s not necessarily a new idea but rather a subtle new way of thinking.最近,我采用了一种新的理念&a…

js验证函数摘录
/**本文摘自:http://www.cnblogs.com/rob0121/articles/1776298.html* js各种表单数据验证*/ /**************************************************************************************/ /*************************************数字的验证*********************…

React for循环渲染组件
通常你需要在一个组件中渲染列表。或者循环遍历渲染相同的多个组件,下面看看怎么实现: render() {const options = this.state.data.map(d => <Option key={d.value}>{d.text}</Option>);return (<SelectshowSearchvalue={this.state.value}placeholder={t…

让电脑的灵魂跟你走
想必我这个题目一出来,大家就知道我想写的是电脑远程控制了。 电脑远程控制是为了方便人们随时随地访问自己的电脑,从而进行更加灵活高效的工作。最常见的远程控制是我们利用客户端直接进入后台操作命令行界面。也就是终端shell。 电影里面,黑…

您尝试打开的文件_您是否尝试过重新打开软件团队的身份?
您尝试打开的文件by Victoriya Kalmanovich由Victoriya Kalmanovich 您是否尝试过重新打开软件团队的身份? (Have you tried turning your software team’s identity off and on again?) This series portrays my experience as an R&D group leader of a gr…

vijos 1006 晴天小猪历险记之Hill——数字三角形的终极变化
题目链接:https://vijos.org/p/1006 数字三角形原题看这里:http://www.cnblogs.com/huashanqingzhu/p/7326837.html 背景 在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳、勇敢…

电磁学讲义6:高斯定理计算电场
高斯定理是电场力平方反比定律和线性叠加原理的直接结果。也可以由高斯定理作为基本规律导出库仑定律。这说明高斯定理和库仑定律是不同形式的表示电荷和电场关系的同一规律。库仑定律可以使我们从电荷分布求出电场分布,高斯定理可以使我们从电场分布求出电荷分布。…

ant table表格整行点击事件并获取当前行的数据
实现效果:点击表格中某一行,或者点击表格中某一行的一个字段,获取当前行的 item 下标数据,并用 Link 标签传参,下一个页面接收的实现。 如果使用 router 跳转路由传参,需要导入 import router from umi/router; 如果用 Link 跳转路由传参,需要导入 import Link from u…

以太坊公链私链_如何使用以太坊构建汽车制造供应链系统
以太坊公链私链by Marcelo Russi Mergulho由Marcelo RussiMergulho 如何使用以太坊构建汽车制造供应链系统 (How to build a car manufacturing supply chain system using Ethereum) Here at Daitan we are always looking for new technologies that can help our clients s…

微信一次性订阅消息
微信一次性订阅消息官方文档:消息管理>发送一次性订阅消息 开发者可以通过一次性订阅消息授权让微信用户授权第三方移动应用(接入说明)或公众号,获得发送一次订阅消息给到授权微信用户的机会。授权微信用户可以不需要关注公众号…

react控制组件的显示或隐藏, 根据state判断元素显示隐藏 , setState不实时生效解决方法
代码实现功能:根据 state 中的值判断子组件显示或隐藏,因为 setState 不是及时生效的,所以不做显示隐藏判断会报错。 render() {// 客户经理循环组件function CommentSpan(props){const numbers props.managers;if(!numbers) return;const l…

关于R语言plyr包的安装问题
平时安装R包都是从Rstudio中进行的,今天在装plyr包的时候,Rstudio一直报错,示例如下: 是不是很无语啊,搞了半天不知所以然,然后突发奇想从Rgui中安装试下,没想到轻轻松松就成功了,示…

regexp 好汉字符串_如何在JavaScript中使用RegExp确认字符串的结尾
regexp 好汉字符串by Catherine Vassant (aka Codingk8)由凯瑟琳瓦森(Catherine Vassant)(又名Codingk8) 如何在JavaScript中使用RegExp确认字符串的结尾 (How to use a RegExp to confirm the ending of a String in JavaScript) Using the Regexp ?️ constructor使用Regex…

【转】浅谈分布式锁
前言 随着互联网技术的不断发展,数据量的不断增加,业务逻辑日趋复杂,在这种背景下,传统的集中式系统已经无法满足我们的业务需求,分布式系统被应用在更多的场景,而在分布式系统中访问共享资源就需要一种互斥…

php中的抽象类(abstract class)和接口(interface)
一、 抽象类abstract class 1 .抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类。 2 .抽象类不能被直接实例化。抽象类中只定义(或部分实现࿰…

React 父组件给子组件传值,子组件接收
父组件传值代码: render() {return (<div>{this.state.list?(<GeomLine list{this.state.list}/>):null}</div>);} 子组件接收代码: class GeomLine extends Component {// 在组件接收到一个新的 prop (更新后)时被调用。这个方法在…

unity 灯笼_如何创建将自己拼成文字的漂亮灯笼
unity 灯笼In this tutorial, we will go through how to create a group of festival lanterns that arrange themselves into the words you choose. An online demo can be found here.在本教程中,我们将介绍如何创建一组节日灯笼,这些灯笼将自己布置…

Android PackageManager packages.xml文件格式
packages.xml文件存放在/data/system目录下 该文件记录了系统中所有应用程序的包管理相关信息 PmS根据该文件进行包管理的各种操作 标签名称所包含的值举例last-platform-versioninternal"17" external"17"<permission-trees />暂时不使用<…

tplink wr886n v5.0 ttl 接线方法
我的倒是有ttl信息,但是全是乱码,换过RX和TX,也换过串口速率都没用,附上TTL接线图.2016-11-02今天晚上终于搞定了ttl了,步骤如下:1.先将串口波特率改为117500(推荐使用Putty).如果可以了就不用第二步了2.将usb转ttl转接板上的rx和tx的指示灯干掉,可以留下电源指示灯详细教程见s…

React子组件给父组件传值, 父组件引用子组件并给子组件传值
本博客代码是 React 父组件和子组件相互传值的 demo;实现封装一个折线图,折线图选择下拉框,获取下拉框点击的值并且传给父组件根据下拉框筛选的条件更新视图;效果图如下: 父组件代码: 代码解析:父组件 Parent 引用子组件 Sub ,传递了 list 组件给子组件,并且接收子组件…

我如何使用深度学习通过Fast.ai对医学图像进行分类
by James Dietle詹姆斯迪特尔(James Dietle) Convolutional Neural Networks (CNNs) have rapidly advanced the last two years helping with medical image classification. How can we, even as hobbyists, take these recent advances and apply them to new datasets? W…

Java——基础
1.数据类型 int,short,byte,long double,float char,String 2.变量 int var; var 12; int var1 12;final int v1 0; //常量 C/C变量的声明和定义是分开的,JAVA不区分。 //c/c extern int a; //声明 …

Gradle系列教程之依赖管理
这一章我将介绍Gradle对依赖管理的强大支持,学习依赖分组和定位不同类型仓库。依赖管理看起来很容易,但是当出现依赖解析冲突时就会很棘手,复杂的依赖关系可能导致构建中依赖一个库的多个版本。Gradle通过分析依赖树得到依赖报告,…