本系列的第1部分介绍了五个一般用例,它们是使用IBM®Blueworks Live的代表性状态转移(REST)应用程序编程接口(API)的最佳方法。 您还学习了不同的实现方法。 第2部分,第3部分和第4部分介绍了使用本地API测试器,脚本或程序访问API的第一种方法。在第5部分中,您将学习如何实现第二种方法:通过Web访问Blueworks Live API。应用。
下图显示了这种Web应用程序与Blueworks Live API,浏览器和用户的交互。 它允许多个用户从他们的浏览器登录,与网页上的用户界面进行交互以及从Blueworks Live检索或发送信息,例如获得自定义报告。 该Web应用程序使用Blueworks Live REST API来获取所需的信息,然后处理该信息并将其呈现为指定格式的网页。
这种方法比本系列前面部分的实现更具挑战性。 它需要一个中央服务器,所有用户(您的Blueworks Live帐户的用户)都可以通过本地Web浏览器访问该服务器。 在服务器上,您还需要一个Web应用程序,该应用程序通过这些本地浏览器中的URL进行寻址。 然后,Web应用程序必须将网页传递回用户的浏览器。
本教程使用Node.js,因为它提供了一种轻量级的方法,仅用几行JavaScript代码即可实现Web服务器。 JavaScript代码在服务器端运行,并与HTML(以及可选CSS)和在客户端的浏览器中运行JavaScript结合在一起。 作为开发人员,您可以使用JavaScript来实现所有功能,并使用HTML和CSS来呈现特定的用户界面。
IBM Bluemix是一个云平台,具有许多现成可用的服务,包括Node.js样板。 使用Node.js服务,您可以为Web应用程序快速设置运行时环境,该环境在与Blueworks Live相同的数据中心中运行。 而且,借助Bluemix上的Node.js服务,您无需担心硬件,IP地址,安全证书以及那些种类的细节。 如果您的应用程序不仅仅需要一个简单的Web服务器(例如,您需要一个数据库,一种发送电子邮件的方法或监视功能),您还可以在Bluemix上找到这些服务并将它们轻松地组合到您的环境中。
下图概述了本文讨论的组件以及它们如何相互交互。
本文分为两个主要部分:准备步骤和构建Blueworks Live模板应用程序。 首先,您将学习准备为Blueworks Live开发Web应用程序的步骤。 然后,您学习构建一个简单的模板应用程序的步骤,该应用程序向用户提供有关Blueworks Live蓝图的简单报告。 准备步骤以及测试和理解模板是一次性步骤。 之后,您将拥有足够的洞察力和正在运行的模板,可以对其进行修改或扩展以适合您的需求。 您可以在第一个报告的顶部简单地构建自己的报告或其他用例功能。 可以从GitHub上的https://github.com/BwlTemplateApps下载该模板和所有中间步骤。
通过在本地开发计算机上使用Node.js设置本地开发环境并设置编辑器或开发程序,准备为Blueworks Live开发Web应用程序。 然后,您可以在Bluemix上设置并测试运行时环境。
您可以在nodejs.org上找到适用于各种操作系统的免费Node.js安装软件包,包括npm。
按照说明下载并安装Node.js。 成功安装后,您应该能够在命令行窗口中运行node
和npm
命令。 如果仅调用node
,则可以交互方式输入直接运行JavaScript命令。 以下屏幕截图显示了一个简短的示例。
通过输入CTRL-D或CTRL-C两次退出node
。 请注意,您的Web应用程序是作为Node.js运行的脚本提供的。
您可以使用软件包管理器npm
来安装Node.js的模块。 要获取有关如何使用命令的信息,请键入npm
。
要创建和修改JavaScript,HTML和其他文件,您至少需要一个文本编辑器。 使用可以根据内容类型设置文件格式和颜色的编辑器会很有帮助。 集成开发环境(IDE)提供了其他功能,例如语法检查和存储库插件。
如果您还没有标准的编辑环境,请考虑以下常见选择:
您可以在本地运行您的应用程序并将其部署在Bluemix数据中心上,以便其他用户可以随时访问它。 对于每种服务,请参阅Bluemix目录中的定价信息。 某些服务在一定程度上是免费的。 例如,其他一些则根据事务数或内存使用量来产生费用。 有关详细信息,请参见在Bluemix登记console.bluemix.net/registration并在Bluemix目录console.bluemix.net/catalog 。
在注册并登录到Bluemix之后,请确保您选择了想要服务的正确区域(数据中心)。 您的帐户名称显示在浏览器页面的右上角。 您可以单击帐户名称,然后选择所需的区域。
在“应用程序”下,您的Bluemix仪表板显示您还没有任何应用程序。 在您的Bluemix仪表板上,单击Create app或直接单击目录的链接。 Bluemix目录向您显示了所有可用的服务。 向下滚动或在搜索过滤器中键入“ node”,直到找到适用于Node.js的SDK 。
单击SDK for Node.js ,然后将打开一个窗口,您可以在其中命名服务。 它还显示了价格计划。 填写适当的应用名称 。 该名称也用作主机名,除非您决定覆盖它。
点击创建 。 将打开您刚刚创建的服务的入门页面。 等待直到看到状态为正在运行的状态旁边的绿色图标,这意味着一切都已设置完毕,并且已部署了启动程序应用程序。
运行旁边的链接是您的服务的URL。 (您可以与其他人共享此链接。)如果单击URL,则会看到正在运行的应用程序。 现在是“ Hello World!” 入门应用程序。
用于Node.js的SDK的入门页面包含有关如何开始在Bluemix中使用该应用程序的最新信息。 现在,只需下载并解压入门应用程序即可。 已经以在本地和Bluemix服务器上运行的方式配置了该启动程序应用程序。
打开命令窗口(例如,在Windows上为cmd
或在Linux上为Shell),然后切换到解压缩的入门应用程序的目录。
您可以通过为node
主JavaScript app.js
作为参数来启动应用程序:
node app.js
但是,这种方法会导致错误,因为您没有所有必需的Node.js模块。
现在,npm软件包管理器将派上用场。 如果您在该目录中启动它,它将获取package.json
的设置。 在编辑器中打开文件,看看它如何告诉npm如何启动该项目以及它所依赖的模块。 以下屏幕截图显示了使用Notepad ++的package.json
文件内容。
首先使用npm安装所有必需的模块:
npm install
以下屏幕截图显示了该命令的示例输出:
如果需要更多模块,请将它们添加到package.json
的依赖项列表中,然后重复命令。 运行该命令后,所有必需的模块在node_modules
子目录中都可用,如以下屏幕截图所示:
安装模块后,可以通过告诉节点如前所示的脚本名称或键入以下命令来启动应用程序: npm start
。
以下屏幕截图显示了使用node
命令启动应用程序的外观:
以下屏幕截图显示了使用npm
命令启动应用程序的外观。 结果是一样的:
从日志输出中找到包括正确端口号在内的URL,然后在浏览器中进行尝试(例如http://localhost:6002
)。 您应该得到一个Hello World! 网页。 这是您在Bluemix上已经看到的网页,但是这次Web服务器在您的本地机器上运行。 您可以通过在命令窗口中键入CTRL-C两次来终止服务。
要了解Node.js的工作原理(以及专门针对此应用程序),请查看app.js
Node.js应用程序可能需要使用JavaScript编写的模块,并提供其他功能。 使用Express模块时,此应用程序仅需要几行代码即可用作Web服务器。 如果直接在URL中引用,则显示/public
子目录中的Web文件。 如果您未在URL中提供详细的路径,它将选择index.html
文件并显示。
如果您在/public
子目录中添加自己的mypage.html
文件,则也可以在浏览器中显示它。 要尝试这种方法,请使用以下地址,但使用端口号,如您的特定日志输出中所给出的: http://localhost:6002/mypage.html
提示:如果稍后扩展应用程序,Node.js日志命令可能会有助于显示正在发生的情况。 例如,您可以在其中一个脚本中添加以下JavaScript行,以在启动Node.js应用程序的命令窗口中包括消息输出:
console.log("my log message: ...");
入门应用程序中使用的另一个模块称为cfenv 。 它有助于简化本地和在Bluemix上运行应用程序的过程。 请注意,URL的基本路径(包括端口号)是使用cfenv自动导出的 。 在其他仅使用express模块的Node.js教程中,您可能会注意到它们的示例显示了端口号的显式设置。
考虑安全性。 将Bluemix用作运行时环境的一个优点是,您会自动获得一个安全的连接,而不必为手动为http或https提供证书和其他设置而烦恼。 Bluemix会处理它。 部署到Bluemix后,只需使用http进行本地测试,然后使用https。 这种方法很重要,因为例如您将用户凭据作为REST请求中的发布数据发送,并且这些凭据应该被加密。 只要通过https访问已部署的Web应用程序,一切都是安全的。 但是,由于用户可以通过http或https自由使用入门应用程序,因此请考虑强制将部分或全部http请求重定向到https。 有关更多信息,请参阅IBM Bluemix上的使用Node.js&Express将HTTP重定向到HTTPS 。
考虑在Bluemix上进行部署。 您可以根据需要在本地进行工作和测试的时间。 如果您认为重新编写的应用程序已准备就绪,并且应该可供Bluemix上的多个用户使用,请进行部署。 请参阅Bluemix上的“入门”页面,以了解部署的工作方式。 它可能会随着时间而改变。 使用2017年提供的命令行工具,您只需几个简单的步骤。
本教程的其余部分描述了如何扩展和修改Bluemix Node.js入门应用程序以派生简单的Blueworks Live模板应用程序。 每个步骤都将研究您所需的特定功能的实现。
Blueworks Live模板应用程序不仅像启动程序应用程序那样提供静态的欢迎页面。 您可以在修改后的欢迎页面上使用Blueworks Live密码登录,然后以交互方式检索一个或多个报告。 作为一个简单的用例,您在本教程中创建的Blueworks Live模板显示了可用流程蓝图的列表。 应用程序的用户可以选择一个流程,并获取特定流程蓝图的详细报告。
有两个选项可以显示流程详细信息:
无论如何,您的应用程序都必须处理来自您自己的网页的各种请求,并且必须返回原始数据或已经呈现了网页。 接下来几节中的以下步骤显示了如何构建模板应用程序,并讨论了如何使用它:
以下各节讨论了每个步骤的重要修改。 解决方案文件可从GitHub上的github.com/BwlTemplateApps获得 。 对于每个步骤,您都可以在BwlTemplateApp_step number
存储库中找到一个示例项目。 修改完成后,每个项目都会反映状态。 项目目录不包含必需的Node.js模块,因此必须首先安装这些模块,然后调用该应用程序。 在每个目录中使用以下命令:
npm install
npm start
根据您的喜好,您可以通读说明,查看每个步骤的样本文件,或同时查看两者。 如果您想尝试以更好地了解每个步骤,请采用该方法。
在此步骤中,了解使用路由器模块来处理使用Web应用程序时URL中给定的各种路径。 例如,当在浏览器中访问http://localhost:6002/welcome
URL时, /welcome
是路由器作为请求处理的路径。
在本地计算机上运行时,端口号可能会有所不同。 检查控制台输出中的正确数字。
app.js
)中将路由器作为必需模块。 包含示例路由器模块JavaScript文件称为index.js
,您可以在/routes
子目录中找到它。 告诉快速应用程序将其用于根路径/
下的所有路径。 无需在package.json
安装或声明模块,因为该模块是应用程序的一部分。 var routes = require('./routes/index');
…
app.use('/', routes);
app.use(express.static(__dirname + '/public'));
index.js
路由器模块创建一个routes
子目录。 index.js
文件。 它包含用于将每个传入请求的信息写入控制台的代码,以便您可以查看正在发生的情况。 如果不需要它,请删除或注释掉以下代码行: router.use(loginfo);
步骤1的示例index.js
文件处理两个路径: /
和/welcome
,如以下代码示例所示:
router.get('/', function(req, res, next) {
res.redirect('/welcome');
});
router.get('/welcome', function(req, res, next) {
res.send('Hello');
});
根路径转发到/welcome
因此,如果您在浏览器中尝试使用http://localhost:6002
,则会在地址字段中看到它最终称为http://localhost:6002/welcome
。
对于/welcome
,您的路由定义了一个在收到请求时运行的功能。 调用该函数时,将向JavaScript对象传递有关请求(变量req
)和响应(变量res
)的信息。 例如,发回文本“ Hello”。 结果显示在以下屏幕截图中:
尽管您尚未处理任何其他URL参数,但是可以尝试在浏览器的地址字段中输入以下文本:
http://localhost:6002/welcome?name=hans&gender=male&age=20
再次返回“ Hello”,因为忽略了参数。 但是,控制台中的loginfo
(如果未注释掉)会告诉您参数。 此信息从req
变量中的req.query
派生:
INFO(GET) query: {"name":"hans","gender":"male","age":"20"}
在这一步中,您可以添加将REST调用发送到Blueworks Live的功能。
bwlapi.js
模块脚本添加到路由。 bwlapi.js
模块定义了一个用于执行BlueworksLive API调用的函数: function callAPI(req,res,handleResponse){
…
req
和res
属于对您自己的Web服务器的请求。 不要将它们与您现在用于与Blueworks Live进行交互的请求和响应混淆。
查看该函数以查看所有必需的详细信息,包括服务主机,凭据和API资源,这些信息通过以下方式设置:
var host = 'www.blueworkslive.com';
var username = 'xxxx';
var password = 'yyyy';
var path = '/api/Auth';
在此示例中,资源被硬编码为/api/Auth
。 它检查给定的凭证是否已在Blueworks Live中注册,以及与之关联的帐户数量。
重要提示:在此示例中,凭据也被硬编码。 如果要为真正的Blueworks Live用户运行此样本,则必须使用自己的凭证并插入它们,而不是xxxx
和yyyy
。
callAPI()
函数向Blueworks Live发出https请求并收集响应。 完成此操作后,它将调用您作为handleResponse
传递的回调函数,如以下示例所示:
var bwlRequest = https.request(options, function(bwlResponse) {
…
bwlResponse.on('end', function() {
…
handleResponse(req, res, bwlResData);
});
});
您可能会注意到,此Node.js代码(通常是Node.js)经常使用回调函数。 该函数调用立即返回,并在以后的时间处理回调。 在分析或修改代码时,请始终牢记这一点。
bwlResData
中返回的数据包含状态代码,响应标头和BlueworksLive请求产生的响应数据。 请参见以下示例:
bwlResData.status = bwlResponse.statusCode;
bwlResData.headers = bwlResponse.headers;
…
bwlResData.data = Buffer.concat(bufferData);
对于生产版本,您应该检查状态码。 值200表示请求成功。 标头告诉您响应数据的数据格式。 注意,响应数据可以是文本或二进制数据。 对于此示例中的硬编码/api/Auth
资源,响应数据是用于成功调用的JSON文本数据( status code=200
)。 您可以使用JSON.parse()
JavaScript方法轻松地将此JSON文本数据转换为JavaScript对象。
index.js
路由器脚本中,并在其中一条路由中对其进行调用。 以下示例在index.js
引入了/login
页面: var bwlapi = require('./bwlapi');
…
router.get('/login', function(req, res, next) {
bwlapi.callAPI(req, res, function (req, res, resData) {
console.log("BWL response received for auth request");
var dataJson = JSON.parse(resData.data); // buffer to json
var dataText = JSON.stringify(dataJson); // json to text
res.send('Data from BlueworksLive request
(status='+resData.status+')
'+dataText);
});
});
以下屏幕截图显示了浏览器中的示例输出:
尽管此实现应按原样运行(应用现有凭据后),但将以下各项添加到最终模板中:
注意:如果你想运行在第3步实Blueworks Live用户的示例应用程序,您必须输入Blueworks直播的用户名和密码中的凭据bwlapi.js
。
到目前为止,您已将文本数据转储到浏览器。 但是,您真正需要的是一个渲染器,该渲染器采用Blueworks Live API响应数据(通常是JSON文本数据)并创建HTML。 如前所述,文本数据可以轻松转换为JavaScript数据对象。
使用Node.js将数据对象呈现为HTML的一种方法是使用handlebars模块。 该模块采用带有占位符的类似HTML的模板,并根据给定的数据替换它们,以呈现最终HTML页面。 该工作在服务器端自动完成,因此可以将HTML发送到客户端。 另一种方法是使用浏览器中运行JavaScript移交数据对象,以在客户端进行渲染。
package.json
文件中添加以下依赖项: "dependencies": {
"express": "4.13.x",
"cfenv": "1.0.x",
"express-handlebars": "^3.0.0"
},
现在,您可以使用以下命令在项目目录中下载模块文件:
npm install
在主要的app.js
脚本中,添加以下变量:
var hbs = require('express-handlebars');
var myhelpers = require('./views/myhelpers');
此代码将把手加载为hbs
和您创建的自写帮助程序模块。
然后将express配置为使用车把作为渲染器,如以下示例所示:
// create a new express server
var app = express();
// view engine setup
app.engine('hbs', hbs({
extname: 'hbs',
defaultLayout: 'layout',
layoutsDir: __dirname + '/views/layouts/',
helpers: myhelpers
}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
请考虑以下示例代码中用于把手和助手的元素:
/views/layouts/
目录包含您的网页的布局。 本教程的样本仅使用一种默认布局: layout.hbs
。 它看起来像一个完整HTML文件,但可以包含占位符。 有一个重要的{{{body}}}
占位符可替换为页面的特定内容。 布局是一个包装,由所有网页通用的部分组成,例如页眉,徽标或页脚消息。 /views
目录中定义为.hbs
文件。 它还可以包含占位符。 例如,占位符{{user.name}}
被替换为user.name
变量的值。 命令也是可能的。 它们可以具有参数,也可以框架HTML部件。 命令的开始用#
表示,结束用/
,如以下示例所示: {{#if user.registered}}
Hello {{user.name}}.
{{else}}
Please register!
{{/if}}
/views
目录的单独的myhelpers.js
文件中。 /login
路由中的send()
方法: res.render('accountinfo', {
title: 'BWL Account Information',
status: resData.status,
dat: dataJson
});
当您打开/login
在浏览器页面这个时候,你从BlueworksLive API调用响应数据创建与HTML页面accountinfo.hbs
查看文件(使用status
和dat
变量)。 此内容由layout.hbs
给定的布局包装(带有title
变量),如以下屏幕截图所示:
所有渲染都在服务器端完成。 浏览器看不到变量。 它仅获取HTML文本。
如果您想尝试并修改步骤3的示例,则在更改.hbs
文件后,无需重新启动本地应用程序。 只需在浏览器中重新加载页面即可。
在此步骤中,您将添加对用户输入做出React的功能,以使Web应用程序更具交互性。 您需要body-parser
模块,该模块有助于处理在发布请求期间从基于HTML表单的一个网页中检索到的数据。
您扩展了包文件和主要的app.js
脚本,类似于上一步中的操作。
此步骤为/welcome
网页引入了一个新视图。 在此欢迎页面上,您将为用户显示一个登录表单(请参阅./views/welcome.hbs
文件),要求输入用户名和密码。 单击该按钮登录后,将向服务器的/login
路径发出发布请求,并在请求的正文中发送登录信息。
查看./routes/index.js
中的示例以了解如何处理此发布请求。 /login
的路由器条目使用登录信息和其他信息填充数据对象,如以下示例所示:
router.post('/login', function(req, res, next) {
var reqData = {
'method': 'get',
'host': 'www.blueworkslive.com',
'path': '/api/Auth?version=20091212',
'login': req.body.login,
'password': req.body.password
}
bwlapi.callAPI(req, res, reqData, function (req, res, resData) {
注意, callAPI()
函数bwlapi.js
被修改,以通过这种信息来控制。 此功能不再包含或不需要任何硬编码凭据。
此外,通过handleBWLResponse(resData)
函数分析响应数据,并自动转换数据。 如果您以用户身份登录,则请求应该成功。 结果要么表明这是有效的用户名和密码组合,要么表明不是。 尽管您可能无法成功登录,但是从技术上来讲,请求在两种情况下都是成功的,并且返回状态码200。有关输入和输出的示例,请参见以下两个截屏:
但是,如果未输入用户名和密码,则请求将返回并包含一条文本消息,并返回错误。 呈现/login
的accountinfo.hbs
视图检查Blueworks Live响应的状态代码。 如果不是200 (= OK)
,则视图将显示返回的错误文本消息,如以下屏幕截图所示。
您可以扩展应用程序的范围,以允许用户选择帐户,获取流程列表,选择流程并显示详细信息。 每个交互都需要一个Blueworks Live调用来获取请求的信息,并需要一个视图来显示结果。
但是,当用户从一页移动到下一页时,您需要保留一些数据。 至少您必须保留用户的凭据。 Web服务器应用程序可以由多个用户使用,并且您需要为每个用户保留单独的数据集(以应用程序的形式:每个浏览器客户端)。 要标识特定用户,您可以在每个用户的浏览器上存储具有唯一ID的cookie,并通过该cookie为该用户标识正确的会话数据集。
为了简化本教程,所有用户的会话数据都存储在服务器端的内存中。 如果许多用户连接到服务器,则可能由于内存不足而导致性能问题。 永久存储(因此即使重新启动应用程序后会话数据仍然可用)需要数据库或其他文件存储来永久保留会话数据。 有关生产性应用程序的详细信息,请参见https://www.npmjs.com/package/express-session上的express-session
模块描述。
express-session
模块必须添加到包文件和主app.js
应用程序脚本中。 顺序很重要:会话对象必须在路由之前由应用程序使用。 从现在开始,您可以在任何路由器条目中使用以下简单代码:
app.get('/', function(req,res,next) {
var sessionData = req.session
…
您可以使用req.session
变量来存储和检索用户会话所需的任何类型的信息。
现在是时候定义模板应用程序的页面使用概念了。 请记住,用户可以随时在浏览器中输入应用程序的任何已知URL。 该应用程序使用以下方法将路径请求解析为适当的视图:
GET
任何路由路径:未经身份验证的用户将重定向到/welcome
。 GET /welcome
:显示欢迎视图,允许用户输入凭据并请求/login
。 POST /login
和POST /logout
:如果用户在注销后或未成功进行身份验证之后通过了身份验证或/welcome
,则这些不言自明的请求路径转发到/process
。 GET /
:根路径重定向到/process
。 GET /process
或/process?account=…
或/process?id=…
:
processlist
视图,它允许选择一个帐户(但它并不显示任何进程列表)。 processlist
视图。 processdetails
视图。 在本教程的简单模板应用程序中,除了用于登录的“欢迎”视图之外,您仅具有两个显示内容的视图。在其他情况下,您可能具有更多的内容视图,因此最好提供这些页面的页眉或页脚中有关当前用户的信息,包括注销功能。 始终如一地提供此信息的简单方法是将其包括在布局文件中。
另请注意:
myhelpers.js
需要更多帮助myhelpers.js
。 /api/Auth
之外的其他Blueworks Live请求都需要派生取决于该帐户的特定服务端点(例如, ams001 = Amsterdam
)。 因此,在发送此类请求之前,您需要调用determineEndpoint()
函数。 以下屏幕截图显示了尝试登录失败并将用户重定向到/welcome
后的错误消息:
用户成功登录后,可以在流程视图中从可用帐户中进行选择,如以下屏幕截图所示:
选择帐户后,该应用程序将显示已发布流程的列表,如以下屏幕截图所示。 请注意,帐户名称是在URL中传递的,因此您也可以在其中进行设置。 您可以存储链接,包括帐户设置。
当用户单击流程名称时,该链接将指向显示该流程详细信息的URL,如以下屏幕截图所示。
请注意,进程ID作为参数传递。 作为示例报告,使用了pdf数据(由/scr/api/PrintDiagram
API资源提供),显示了流程图。 在您自己的应用程序中,报告可以显示所需的其他信息。 在呈现最终结果页面之前,它甚至可能包括对Blueworks Live的多个API调用。
通过步骤5,您将拥有一个完整的模板来构建自己的Blueworks Live应用程序。 您可能想要修改流程详细信息页面或添加新页面。 For some ideas, see Part 1 of this series, which discusses various general use cases of applications.
See the following list of other aspects to consider when writing your own app:
In this tutorial you learned how to implement a multi-user web application that interacts with the Blueworks Live REST API. You used Node.js, an open-source, cross-platform JavaScript runtime environment for running JavaScript code on the server side.
The first section explained how you set up your development environment, introduced a starter app, and showed how to deploy it on IBM Bluemix. The second section discussed the implementation details of a Blueworks Live template app, based on a provided sample, and other aspects to consider.
Now try your own application implementation or check with IBM or other service providers for offerings to help you. We might add some more application samples to the Blueworks Live template project on GitHub ( github.com/BwlTemplateApps ) in the future, so check for updates. If you are interested in further enablement or consulting, feel free to get in touch with your local IBM sales contact or directly with Rolf Riedlinger, [email protected].
The author would like to thank Rolf Riedlinger from IBM Lab Services and Sam Weeks from IBM Technical Sales UK for their review and comments. Also a special thanks to Margaret Thorpe from the Blueworks Live product team for her support and constant willingness to discuss ideas from the field.
翻译自: https://www.ibm.com/developerworks/library/mw-1707-westphal-bluemix/1707-westphal.html