Skip to Content
Technical Articles

SAP Event Mesh 在SAP业务技术平台中国(上海)区域的入门级动手教程

本博客文章翻译自此篇英文版,是关于SAP Event Mesh在SAP业务技术平台在中国(上海)区域(也即SAP Business Technology Platform on Alibaba Cloud)的应用教程,包括一个入门级的端到端的简单动手实验。所有的代码部分都可以在这个代码仓库中找到,而理论部分主要可以参考这篇帮助文档、这项教程、这个视频系列以及这篇博客文章

SAP Event Mesh在中国(上海)区域的的产品重命名还在进行中(原产品名为SAP Enterprise Messaging)。本文章将会随着此过程的进度做相应更新。

💻 您需要准备:

    • 在SAP BTP中国(上海)区域的上的全局账户和子账户;
    • SAP Event Mesh和SAP Business Application Studio的资源权利。

 

创建服务实例和租用多租户运用程序

首先,我们前往SAP BTP主控室,进行服务、资源和安全等配置。

 

权利配置

确保您的全局账户中有SAP Event Mesh 的如下资源权利,并将其分配到对应的子账户中:

服务 技术名称 服务计划
Event Mesh enterprise-messaging default
Enterprise Messaging enterprise-messaging-hub standard

第一个服务用于创建消息客户端服务的实例,而第二个是可供租用的多租户业务应用程序,以便用户通过Web用户洁面来管理消息传递客户端和事件目录等。

服务实例

进入您CF的组织和空间中,选择 Event Mesh 服务,default计划,创建服务实例。

在弹出的向导中,您需要填入JSON格式的服务描述符(遵循语法 Syntax for Service Descriptor),你可以复制粘贴如下文本,然后修改相应参数:

{
    "emname": "<message-client-name>", // fill in your message client name
    "namespace": "<your-namespace>", // fill in your namespace
    "version": "1.1.0",
    "options": {
        "management": true,
        "messagingrest": true,
        "messaging": true
    },
    "rules": {
        "queueRules": {
            "publishFilter": [
                "${namespace}/*"
            ],
            "subscribeFilter": [
                "${namespace}/*"
            ]
        },
        "topicRules": {
            "publishFilter": [
                "${namespace}/*"
            ],
            "subscribeFilter": [
                "${namespace}/*"
            ]
        }
    }
}

🔖 除了使用主控室,您还可以使用CF CLI命令行来完成以上操作。

 

服务秘钥

为了创建服务秘钥,您需要前往主控室中,选择刚才创建好的服务实例 👉 为其创建服务秘钥 👉 输入秘钥名称 👉 点击创建。

您不需要输入秘钥的内容参数,系统会自动为您创建好。现在,查看自动创建的JSON格式的内容,找到如下内容:

  • namespace 命名空间,
  • management API URI和三个 messaging API URI (尤其注意 HTTP REST协议的URI),
  • client id 客户端标识,,client secret 客户端秘钥以及token endpoint令牌端点。

稍后您将会用到它们。

 

多租户应用程序以及角色和用户分配

在主控室的“租用“页面,选择服务 Enterprise Messaging (技术名: enterprise-messaging-hub),服务计划 standard

将相应角色添加到角色集合中,并将用户(在此教程中是您自己的SAP账号)添加到角色集合中。

现在,您可以在“Event Mesh”的磁贴中,通过“转到应用程序”链接来打开 Event Mesh 业务应用程序的用户界面(Event Mesh Dashboard。您可以浏览该界面上的一些功能,比如,您可以打开您刚才创建的消息客户端,查看规则、队列等信息。

 

创建队列并且测试发布或者使用消息(通过用户界面)

创建

🎬 场景:您想要看央视春晚,尤其是里面的小品节目,但是比较忙,没办法全程守在电视机前看直播。于是希望CCTV给您发送消息,告诉您什么时候是什么节目正在上演,这样至少您稍后可以通过查看消息来查找您想看的节目。

您需要首先创建一个名为comedy的队列。在用户界面上,选择 Message Clients 页面 👉 选择消息客户端磁铁 mymessageclient 👉 选择Queues 👉 选择Create Queue 👉 在弹出窗口中,填入参数:queue name = comedy,其他参数置为默认值。

点击 Create,您将会看到队列 myorg/mymessageclient/001/category 已经被创建了,但是还没有消息在队列中。

🔖 您无需再队列名前面加上命名空间作为前缀,因为系统将会自动为您加上。

 

测试

进入测试页面,在左边,选择队列与消息客户端,在 Message Data 中填入参数,点击 Publish Message。您将会看到有通知提醒您消息已经发送,并且队列中消息的数量变为1。

📊 Message Data样例

  • Content-Type: application/json
  • Body: {“time”: “20210124 21:00:00”, “category”: “music”}

在右边,选择队列与消息客户端,点击Consume Message。您会看到刚才发送的消息的内容,并且队列中消息的数量变为0。

 

通过API创建队列与发布和使用消息(通过Postman桌面应用程序)

🎬 场景:您的女儿也想要看春晚。她只关心她的偶像们何时出场,所以她希望CCTV能为她推送关于节目的演员的消息。

Event Mesh同时也提供了可以管理队列、队列租用的API——REST APIs for Management,以及用于发送和接收消息的API——REST APIs for Messaging

我们使用Postman的桌面应用程序来发送HTTP 请求。现在您可以回想一下您创建完服务秘钥时查看的那些URI和标识符等。

 

获取访问令牌

在与Event Mesh的服务使用API通信之前,我们需要从XSUAA处获取访问令牌(access_token)。这篇帮助文档将会指导您如何使用客户端标识和客户端秘钥,从令牌端点处获取访问令牌。

您需要在Postman里填写以下信息:

页面
Bar Method 选择GET
Bar URL <tokenendpoint>?grant_type=client_credentials&response_type=token
Authorization Type 选择Basic Auth
Authorization Username <clientid>
Authorization Password <clientsecret>

发送请求,您将会收到 200 OK 带有访问令牌的回复,您需要在后续的请求头中带入该访问令牌:AuthorizationBearer {{access_token}}

 

创建队列

在上面给出的关于API的文档中,您可以找到用来创建队列的API  PUT /hub/rest/api/v1/management/messaging/queues/{queue}

在URL中的参数 {queue} 是经过网址编码的,并且加有命名空间作为前缀的队列全称,比如 myorg/mymessageclient/001/artist 经过编码后变为 myorg%2Fmymessageclient%2F001%2Fartist

您需要在Postman里填写以下信息:

页面
Bar Method 选择PUT
Bar URL <management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue}
Authorization Type 选择No Auth
Headers Authorization Bearer <access_token>

请求体是可选的,如果您不提供请求体,系统将会使用QueueP模式中的默认值。

发送请求,您将会收到201 Created带有已创建队列的信息的回复。

如果您想要获取某个队列的信息,您可以通过API GET /hub/rest/api/v1/management/messaging/queues。除了Method 和Path的值不同以外,其他的参数都与创建队列的参数相同。

 

发送与接收消息

为了能用API来向一个队列发送消息,我们可以从messaging API中找到API POST /messagingrest/v1/queues/{queue-name}/messages。 在URL中的参数{queue-name} 同样应该是经过网址编码的带有命名空间作为前缀的队列全称。

页面
Bar Method 选择POST
Bar URL <messaging[protocol=httprest].uri>/messagingrest/v1/queues/{queue-name}/messages
Authorization Type 选择No Auth
Headers x-qos 样例0
Headers Authorization Bearer <access_token>
Body raw – JSON 样例{"time": "20210124 21:00:00", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}]}

在请求头中,x-qos的意思是服务质量(quality of service,QoS), 0 表示服务将尝试传递消息,并且无论消息是否已传递,都将返回代码为 204 的 HTTP 响应。1 表示的是服务以 HTTP 响应代码 204 进行响应。如果未收到 204 响应代码,则客户端负责重新尝试,直到收到响应代码 204 为止。

在请求体中,您可以选择 raw 的类型,并且输入任何内容。如果您想要传输Cloud Event,您则需采用JSON的格式。

发送请求,您将会收到204 No Content的回复,并且消息的ID会被附在回复头中。

若要从队列中接收消息,您需要使用API POST /messagingrest/v1/queues/{queue-name}/messages/consumption。您可以使用与发送消息相同的请求头,并且将请求体置空。

在代码库里的文件夹 ./apis中,您将可以找到本动手实验在Postman中使用的请求的配置文件。

 

创建队列租用并向话题发送消息

🎬 场景:如果现在央视只发送一种关于节目的消息,同时含有节目类别和演员表的信息,您和您的女儿都对这一种消息感兴趣,但不幸的是,一条消息只能被一个人消费,如果您的女儿接收到了某条消息,那么您就接收不到了。此时,您需要让央视将消息发送到一个主题中,并且您和您的女儿各创建一个队列,来订阅这个话题,这样,您和您的女儿都能收到来自央视的消息,并且两人的消费行为互不影响。

 

通过用户界面为消息 artist 创建主题

您可以前往网页端的用户界面来创建主题,也即队列租用。请注意,您填入的主题的名称应该遵循您在服务描述(service descriptor)中的规则相一致,也即,名称的前缀命名空间应该与队列的相一致。

 

向主题发送消息

您可以在messaging API中找到用来发送给主题 performance 的API POST /messagingrest/v1/topics/{topic-name}/messages

页面
Bar Method 选择POST
Bar URL 网址编码过的 <messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages
Authorization Type 选择No Auth
Headers x-qos 样例0
Headers Authorization Bearer <access_token>
Body raw – JSON 样例{"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"}

发送请求后,您将会在用户界面中看到,队列artist 的消息数量增加了1。

 

通过API为队列 category 创建主题

我们使用management API PUT /hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic}.

页面
Bar Method 选择PUT
Bar URL 网址编码过的 <management[0].uri>/hub/rest/api/v1/management/messaging/queues/{queue}/subscriptions/{topic}
Authorization Type 选择No Auth
Headers Authorization Bearer <access_token>

若主题被成功创建,您将会收到201 Created带有队列和主题信息的回复。

现在的体系结构为:

图片改编自 SAP Help Portal

 

通过API发布消息到主题并从队列消费消息

发布消息到主题,您需要在Postman中创建请求,并填入如下信息:

页面
Bar Method 选择POST
Bar URL 网址编码<messaging[protocol=httprest].uri>/messagingrest/v1/topics/{topic-name}/messages
Authorization Type 选择No Auth
Headers x-qos 样例0
Headers Authorization Bearer <access_token>
Body raw – JSON 样例{"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"}

发送消息后,您可以看到,两个队列均可接收到消息。

现在让我们来从两个队列中获取消息。

 

[选做] 在SAP BTP上开发消息生产者与消息使用者的应用程序(通过Node.js或者JAVA)

在此篇教程 Tutorial: Develop a Messaging App on SAP BTP 中,您可以学到如何开发运行在BTP上的Node.js或者JAVA消息生产者和使用者应用程序。

SAP为您提供了一系列的开发工具,例如 Node.js 包, Java 类库等等,使您能够开发可以传递消息和通信的XS-Advanced应用程序(XS Advanced 即SAP HANA Extended Application Services advanced model,能使您的应用程序运行在由SAP改良的Cloud Foundry PaaS平台上)。

 

JavaScript

想要使用JavaScript开发,您可以参考 Standard Node.js Packages for XS Advanced

  • @sap/xb-msg: 此开发包提供了消息代理以及相关通信功能,可以支持RabbitMQ的消息代理,支持以下协议:AMQP v091, AMQP v100, MQTT v311;
  • @sap/xb-msg-env: 此开发包提供了建立Cloud Foundry 或者XS Advanced环境下的消息客户端的相关函数;
  • @sap/xsenv: 此包可用于简单地创建和获取XS Advance的环境变量和服务。

 

Java

想要使用Java来进行开发,您可以参考 SAP Cloud Application Programming Model(使用到的类库为com.sap.cloud.servicesdk.xbem.*),这个类库符合Java消息服务的一些标准 Java Message Service (JMS) 2.0 specification, :

  • MessagingService,
  • MessagingServiceJmsConnectionFactory,

 

SAP Cloud SDK中的与Event Mesh有关的特性已经在计划之中,其进度依赖于CAP。

 

创建Webhook (nodejs),部署到CF,并租用到队列

🎬 场景:现在,您不想要时不时地查看您的队列是否有收到节目消息,并判断该节目是否是小品,您想要创建一个webhook,来主动从队列中获取消息,并为您记录只与小品有关的节目信息。

如果我们为消息系统添加一个webhook,那么就不是消息消。在此教程中,我们只为队列 comedy创建一个webhook。

此图片改编自 SAP Help Portal

我们接下来会采用的样例改编自这个视频系列的第一部分Youtube: Diving into messaging on SAP Cloud Platform (1-8)

 

创建和部署

前往SAP Business Application Studio 👉 创建 Full Stack Cloud Application(全堆栈云应用程序) 类型的开发空间,命名为 emtester,进入开发空间 👉 使用向导创建项目 👉 选择模板和工作区 Basic Multitarget Application 👉 Start 👉 输入项目名称 webhook,完成。

您会看到系统有自动生成一些文档,请删除它们。创建一个名为 manifest.yml 的文档,复制粘贴如下内容到文档中:

---
applications:
- name: webhook
  routes:
  - route: <host-name>.<domain>
  path: .
  memory: 128M

替换应用程序名称(name)和路径(route)为您自己的值,比如,路径应为您为应用程序取的主机名(hostname)和域名(domain)的连接 webhook.exercise.sap-samples.cn40.apps.platform.sapcloud.cn.

如果您不确定,您可以使用哪个域名,您可以在Business Application Studio 中打开Terminal  👉 cf login 👉 选择目标组织和空间 👉 使用 cf domains命令列出您组织下的所有域名 👉 选择可用域名。

在Terminal 中,前往当前项目的根目录,运行 npm init 然后一直敲击回车键,使用默认值,直到最后输入OK。您将会看到,文件package.json 已被创建,并且它需要一个主页文件 index.js

用命令 npm install express body-parser来安装所需的两个 Node.js 包,express和body-parser。 

🔖 这两个包是做什么的?

express 用于为单网页应用程序、网站以及公共HTTP API提供轻巧而简装的HTTP服务器工具。

body-parser 用于在中间件中解析请求体。

在文件package.json中,我们通过在 scripts添加键值对 start 来指定初始脚本,并删除 test 最终,我们得到的文件 package.json 长这样:

{
    "name": "webhook",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "start": "node index.js"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
      "body-parser": "^1.19.0",
      "express": "^4.17.1"
    }
}

现在,让我们来写 index.js文件,请复制粘贴如下代码:

const express = require("express")
const bodyParser = require("body-parser")

const app = express()
const PORT = process.env.PORT || 8080

app.use(bodyParser.json())

app.get('/', (req, res) => {
    res.status(401).send('Hey, this is a webhook - we only receive POST!')
})

app.post('/', (req, res) => {
    if(req.body.category == "comedy") {
        console.log(' ', req.body)
        res.status(200).send(' ' + req.body.name).end()
    }
    else {
        console.log(' ', req.body)
        res.status(200).end()
    }
})

app.listen(PORT, () => console.log(`  Server running on port ${PORT}`))

[可选] 如果您想要再您的本地终端中先测试一下您的应用程序,您可以在项目根目录下,运行 npm start,然后开一个新的标签页使用cURL来向localhost发送如下请求:

curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:00:00", "name": "Go, Amigo and Hi, Motherland Mash Up", "category": "music", "artists": [{"name": "TFBOYS"}, {"name": "Ye Zhang"}], "status": "START"}' http://localhost:8080/

curl -H 'Content-Type: application/json' -d'{"time": "20210124 21:05:00", "name": "A Funny Comedy", "category": "comedy", "artists": [{"name": "Ling Jia"}], "status": "START"}' http://localhost:8080/

第一条指令将会使您的应用程序在控制台打印出哭脸,二第二条指令将会打印出笑脸。

接下来将您的应用程序部署到BTP上。在Terminal中,运行命令 cf push

如果要测试 webhook,使用Postman来向Webhook发送请求。

所有的关于webhook的代码可以在这个文件夹中找到 ./webhook/

 

创造webhook租用

前往网页端用户界面 👉 前往消息客户端 👉 选择webhooks 页面 👉 篡改建webhook 租用 👉 在弹出窗口中,填入队列名称,webhook的URL地址,和其他参数 👉 点击create.

激活的过程将会在消息客户端和webhook应用程序间的第一次握手,也就是第一次通信时产生。

 

发送消息到主题 performance并从webhook的日志中读取消息

再次发布两则消息到主题 performance ,消息内容参考我们在测试主题的时候发送的消息,您会发现,队列 artist 的消息数量发生了增加,然而队列 category 的消息数量仍然为零。这说明了发送给队列 category 的消息已经被webhook消费了。

前往 cf logs webhook 查看日志,您会发现,刚才发送的两则消息被webhook消费后,分别留下了两条log,一条被标记为interested,另一条则是not interested。

如果您有将您的应用程序绑定一个SAP Apppication Logging Service 的服务实例(在这篇文档您可以了解如何实现绑定),您还可以从BTP的主控室中的日志一页查看您应用程序的日志。

至此,您已经走完了SAP Event Mesh在中国(上海)区域的第一个端到端的场景。

 

参考资料

Be the first to leave a comment
You must be Logged on to comment or reply to a post.