构建一个混合的费用跟踪应用程序

KatiaZimmer 8年前
   <p>在构建 REST 应用程序时,如果使用某个工具来实现 API 组成和数据连接,可以提高您的工作效率。通过这种方式,您可以将更多的精力集中在应用程序的业务逻辑和用户体验上。</p>    <p>在本教程中,您将构建一个工作应用程序来了解如何使用来自 StrongLoop(IBM®的一家子公司)的 API 开发工具。借助开源 <a href="/misc/goto?guid=4959670595767862208" rel="nofollow,noindex">LoopBack</a> 框架(该框架构建于 Node.js 之上),您可以轻松地以可视方式开发可扩展的 REST API 并连接到该应用程序所需的数据。 <a href="/misc/goto?guid=4959670595848886774" rel="nofollow,noindex">StrongLoop Arc</a> 对 StrongLoop <a href="/misc/goto?guid=4959670595939257510" rel="nofollow,noindex">slc</a> 命令行工具进行了补充,包括用于构建、分析和监测 Node.js 应用程序的工具。</p>    <p>您的练习是构建一个简单的混合费用跟踪应用程序,该应用程序使用了您用 StrongLoop 开发的 REST API。该 REST API 使用了 Bluemix 中的 <a href="/misc/goto?guid=4959670596021416035" rel="nofollow,noindex">Cloudant NoSQL DB</a> 服务来实现数据集成。您将在本地创建一个服务器应用程序来公开 REST API。为了开发混合应用程序的客户端,可以使用 LoopBack Angular JavaScript SDK(LoopBack 包含的几个软件开发工具中的一个)和 <a href="/misc/goto?guid=4958821868446522552" rel="nofollow,noindex">Ionic</a> 框架。作为最后一步,我们会将应用程序的服务器端代码部署到 Bluemix。</p>    <p>如果费用超出了规定的限制,您还可以使用 LoopBack 框架扩展 ExpenseTracker 来发送推送通知 —这方面的练习超出了本教程的讨论范围。</p>    <p>借助 ExpenseTracker 应用程序,用户可以按照类别记录自己的日常开销。客户端会生成一个费用报告,并以图表的形式提供该报告。您可以扩展 API,以便客户端可以根据特定类别或月份来显示图表。</p>    <h2>构建您的应用程序需要做的准备工作</h2>    <ul>     <li>一个 IBM ID 和一个 Bluemix 帐户(注册获得您的免费试用版帐户,如果您已经有一个帐户,请 <a href="/misc/goto?guid=4959670596134495344" rel="nofollow,noindex">登录到 Bluemix</a> )。</li>     <li>一个已安装了以下工具的本地开发环境:      <ul>       <li><a href="/misc/goto?guid=4959647272151345617" rel="nofollow,noindex">Node.js</a></li>       <li><a href="/misc/goto?guid=4959670596247713644" rel="nofollow,noindex">StrongLoop</a></li>       <li><a href="/misc/goto?guid=4959670596319001021" rel="nofollow,noindex">Cloud Foundry 命令行接口 (CLI)</a></li>       <li><a href="/misc/goto?guid=4959670596409525682" rel="nofollow,noindex">Ionic</a> 框架</li>      </ul> </li>     <li>可选:Mac OS X 和 <a href="/misc/goto?guid=4959670596510352301" rel="nofollow,noindex">Apple Xcode IDE</a></li>     <li>基本熟悉 Node.js 和一个 Node.js 开发环境</li>     <li>基本熟悉 AngularJS 框架</li>     <li>最好还了解 Ionic 框架</li>    </ul>    <p><a href="/misc/goto?guid=4959670596579420822" rel="nofollow,noindex">运行服务器应用程序</a></p>    <p><a href="/misc/goto?guid=4959670596667043097" rel="nofollow,noindex">获取代码</a></p>    <p>“ 借助开源 LoopBack 框架,您可以轻松地以可视方式开发可扩展的 REST API 并连接到该应用程序所需的数据。 ”</p>    <h2>第 1 步 . 创建 Bluemix 应用程序</h2>    <ol>     <li>登录到 Bluemix。</li>     <li>单击 <strong>CREATE APP</strong> 。</li>     <li>选择 <strong>WEB</strong> 作为应用程序类型。</li>     <li>选择 <strong>SDK for Node.js</strong> : <img src="https://simg.open-open.com/show/f96c04e11447d8737d29d5fd0d6c5d89.jpg"></li>     <li>单击 <strong>CONTINUE</strong> 。</li>     <li>输入带有附加的唯一标识符(比如您的用户名或日期)的 ExpenseTracker 。(如果您尝试使用的名称是不可用的,Bluemix 会告诉您。)</li>     <li>单击 <strong>FINISH</strong> 。</li>    </ol>    <h3>将 Cloudant NoSQL DB 服务绑定到您的应用程序</h3>    <ol>     <li>在载入您的应用程序后,返回到 Bluemix 仪表板并单击应用程序名称转到应用程序的概述页面。</li>     <li>单击 <strong>ADD A SERVICE OR API</strong> 按钮。</li>     <li>在目录的 Data and Analytics 部分,选择 <strong>Cloudant NoSQL DB</strong> 。</li>     <li>单击 <strong>CREATE</strong> 将 Cloudant 服务添加到应用程序。</li>     <li>在提示时重新载入应用程序。</li>     <li>返回到应用程序的概述页面,确认 Cloudant NoSQL DB 服务现在已绑定到应用程序。</li>    </ol>    <h3>为 ExpenseTracker 应用程序创建数据库</h3>    <ol>     <li>在应用程序的概述页面上,单击 Cloudant NoSQL DB 服务来显示相关细节。</li>     <li>单击 <strong>LAUNCH</strong> 按钮来启动 Cloudant NoSQL Database 仪表板。</li>     <li>单击右上方的 <strong>Create Database</strong> 链接。在提示您输入一个数据库名称时,输入 expense-tracker 并单击 <strong>Create</strong> 。</li>    </ol>    <h2>第 2 步 . 在本地开发环境中实现服务器端</h2>    <p>在这一步中,将实现一个服务器端应用程序,该应用程序使用 LoopBack 框架来公开 REST API,以便添加费用信息。</p>    <h3>创建一个新的服务器端应用程序</h3>    <ol>     <li>在 OS 命令行下,在您想要放置新应用程序的目录中,键入 slc loopback 并按下 Enter。</li>     <li>键入 ExpenseTracker 作为应用程序名称并按下 Enter。</li>     <li>按下 Enter 接受项目目录的默认名称 (ExpenseTracker)。</li>    </ol>    <p>服务器端代码是在 ExpenseTracker/server 文件夹中生成的。</p>    <p>阅读: <a href="/misc/goto?guid=4959670596744142558" rel="nofollow,noindex">项目布局引用</a></p>    <p>阅读: <a href="/misc/goto?guid=4959670596823709891" rel="nofollow,noindex">StrongLoop API 文档</a></p>    <h3>将 Cloudant 连接器添加到应用程序</h3>    <p>ExpenseTracker 应用程序使用 Cloudant NoSQL DB 来实现数据存储。因为 Cloudant 是 CouchDB 的衍生物,所以您可以将 LoopBack CouchDB 连接器用于应用程序:</p>    <ol>     <li>在您的 OS 命令行下,转到 ExpenseTracker 目录。</li>     <li> <p>运行以下命令来安装 LoopBack Couch 连接器:</p> <p>npm install loopback-connector-couch</p> </li>    </ol>    <p>阅读: <a href="/misc/goto?guid=4959670596906571286" rel="nofollow,noindex">loopback-connector-couch</a></p>    <h3>添加 Cloudant 作为应用程序的数据库</h3>    <p>配置 ExpenseTracker 应用程序,以便连接到您在第 1 步中在 Bluemix 中创建的 Cloudant NoSQL DB 服务:</p>    <ol>     <li>在 Bluemix 中的您的费用跟踪应用程序的概述页面中,单击 Cloudant NoSQL DB 服务中的 <strong>Show Credentials</strong> : <img src="https://simg.open-open.com/show/404ca9e1202b73e8e2ff5d53d7efb980.jpg"></li>     <li> <p>还可以通过 StrongLoop 命令行工具或 <a href="/misc/goto?guid=4959670596996379384" rel="nofollow,noindex">Arc Composer</a> 添加您的 Cloudant 凭证。</p> 在文本编辑器中,打开本地项目的 server/datasources.json 文件并添加 Cloudant 数据库的详细信息: <pre>  <code class="language-json">"cloudant": {     "host": "yourhost-bluemix.cloudant.com",     "port": 443,     "url": "https://yourhost-bluemix.cloudant.com",     "name": "cloudant",     "connector": "couch",     "db": "expense-tracker",     "protocol": "https",     "auth": {       "admin": {         "username": "cloudant-admin-username",         "password": "cloudant-admin-password"      },       "reader": {         "username": "cloudant-reader-username",         "password": "cloudant-reader-password"      },       "writer": {         "username": "cloudant-writer-username",         "password": "cloudant-writer-password"      }     }    }</code></pre> </li>    </ol>    <h3>设置应用程序数据模型</h3>    <p>ExpenseTracker 应用程序使用了一个简单的数据模型。LoopBack 框架中的数据模型配置还可以公开 REST API:</p>    <ol>     <li> <p>在您的 OS 命令行下,转换到 ExpenseTracker 目录并输入:</p> <p>slc loopback:model</p> </li>     <li>提供以下详细信息来响应提示:      <ul>       <li>模型名称: expense</li>       <li>要附加的数据源: cloudant</li>       <li>模型基类: PersistedModel</li>       <li>公开为 REST API: Yes</li>       <li>复数形式: expenses</li>      </ul> </li>     <li>按下 Enter 键退出模型创建过程。</li>    </ol>    <p>现在,设置模型属性( category 、 item 、 price 和 expensedate ):</p>    <ol>     <li>对于每个属性,运行 slc loopback:property 命令并在提示时提供该属性的详细信息:      <table cellspacing="0">       <thead>        <tr>         <th><strong><em>属性</em> </strong></th>         <th><strong><em>模型</em> </strong></th>         <th><strong><em>属性名称</em> </strong></th>         <th><strong><em>属性类型</em> </strong></th>         <th><strong><em>是否是必需的</em> </strong></th>        </tr>       </thead>       <tbody>        <tr>         <td><strong>category</strong></td>         <td>expense</td>         <td>category</td>         <td>string</td>         <td>yes</td>        </tr>        <tr>         <td><strong>item</strong></td>         <td>expense</td>         <td>item</td>         <td>string</td>         <td>yes</td>        </tr>        <tr>         <td><strong>price</strong></td>         <td>expense</td>         <td>price</td>         <td>number</td>         <td>yes</td>        </tr>        <tr>         <td><strong>expensedate</strong></td>         <td>expense</td>         <td>expensedate</td>         <td>date</td>         <td>yes</td>        </tr>       </tbody>      </table> </li>    </ol>    <p>另外,您还可以使用 Arc Composer 添加属性。</p>    <h3>与数据进行交互</h3>    <p>LoopBack 框架会自动为您的数据模型的所有对象生成 REST 端点。它还会相应地生成 <a href="/misc/goto?guid=4958966062191945523" rel="nofollow,noindex">Swagger</a> API 文档,为您提供连接到您的数据的便捷接口。</p>    <ol>     <li>在您的 OS 命令行下,转换到 ExpenseTracker 目录。</li>     <li>运行 node 命令来启动 ExpenseTracker 应用程序。</li>     <li>在浏览器中,访问 http://localhost:3000/explorer,在 StrongLoop API Explorer 中打开 ExpenseTracker 应用程序的 Swagger API 文档: <img src="https://simg.open-open.com/show/21a4925c71947143cd0afa61fa075fce.jpg"> <p><img src="https://simg.open-open.com/show/141f398e569fc88cfc3f769038880ae6.jpg" alt="构建一个混合的费用跟踪应用程序" width="550" height="153"></p> </li>     <li>单击 <strong>List Operations</strong> 显示所有可能的操作,这些操作被公开为 REST 方法。通过使用 API Explorer,您可以与模型进行交互并测试服务。</li>    </ol>    <h3>扩展模型交互</h3>    <p>您可以通过修改应用程序的 common/models 文件夹中的 expense.js 文件来扩展模型实现。默认文件内容包括:</p>    <pre>  <code class="language-javascript"><em>module.exports = function(Expense) {};</em></code></pre>    <p>为了使得 ExpenseTracker 根据类别或月份来检索费用成为可能,可以通过添加一个方法并将该模型模型公开为要使用的客户端的 REST API 来定制模型。在文本编辑器中,打开 common/models/expense.js 文件,并使用下面的代码替换其内容:</p>    <pre>  <code class="language-javascript">module.exports = function(Expense) {    //Method to get the category based expenses for the month.    Expense.getMonthlyCategoryBasedAnalysis = function(cb)    {       ONE_MONTH = 30 * 24 * 60 * 60 * 1000;  // Month in milliseconds       var lastDate = new Date(Date.now() - ONE_MONTH);       var result = "";       var jsonArr = [];       Expense.find( { expensedate: {gt: lastDate} },       function (err, instance)       {           var tempArr = [0, 0, 0, 0];           for (var i=0;i<instance.length;i++)           {               if(instance[i].expensedate > lastDate)               {                   if(instance[i].category == "Food")                       tempArr[0] = tempArr[0] + instance[i].price;                   else if (instance[i].category == "Travel")                       tempArr[1] = tempArr[1] + instance[i].price;                   else if (instance[i].category == "Education")                       tempArr[2] = tempArr[2] + instance[i].price;                   else if (instance[i].category == "Miscellaneous")                       tempArr[3] = tempArr[3] + instance[i].price;               }           }           for (var i = 0; i < tempArr.length; i++) {               var cat = "";               if(i == 0) cat = "Food";               if(i == 1) cat = "Travel";               if(i == 2) cat = "Education";               if(i == 3) cat = "Miscellaneous";               //create the JSON for the client to consume               jsonArr.push({                   "category": cat,                         "period": "LastMonth",                   "price": tempArr[i]               });           }           console.log("out is "+jsonArr);           response = jsonArr ;           cb(null, response);       });    }    //Expose the method as a REST API    Expense.remoteMethod ('getMonthlyCategoryBasedAnalysis',{         http: {path: '/getMonthlyCategoryBasedAnalysis', verb: 'get'},         //accepts: {arg: 'categoryName', type: 'string', http: { source: 'query' } },         returns: {arg: 'data', type: 'string'}       }    );    };</code></pre>    <p>上面的代码使用 find 方法来检索上一个月的基于类别的费用,然后按类别组织数据。 getMonthlyCategoryBasedAnalysis 被公开为客户端的一个远程方法。</p>    <p>阅读: <a href="/misc/goto?guid=4959670597099997656" rel="nofollow,noindex">远程方法</a></p>    <h2>第 3 步 . 在您的本地开发环境实现客户端</h2>    <p>您正在构建的混合应用程序对前端使用了 Ionic 框架和 LoopBack 框架的 AngularJS SDK。</p>    <p>阅读: <a href="/misc/goto?guid=4959670597176650562" rel="nofollow,noindex">Ionic 概述</a></p>    <h3>创建 Ionic 应用程序</h3>    <p>将客户端应用程序创建为一个 Ionic 应用程序:</p>    <ol>     <li> <p>在您的 OS 命令行下,转到 ExpenseTracker 目录,并运行以下命令来下载应用程序模板(您必须处于联网状态):</p> <p>ionic start client tabs</p> </li>     <li>在系统询问您是否覆盖该文件夹时,选择 yes。</li>    </ol>    <p>阅读: <a href="/misc/goto?guid=4959670597260520147" rel="nofollow,noindex">Ionic 项目结构</a></p>    <h3>生成 Angular 服务</h3>    <p>阅读: <a href="/misc/goto?guid=4959670597349967944" rel="nofollow,noindex">AngularJS SDK 简介</a></p>    <p>LoopBack 框架支持 AngularJS SDK。Ionic 框架使用 Angular 客户端库来调用 REST API。要为您的 LoopBack 应用程序生成 Angular 客户端库,可以使用 LoopBack Angular 命令行工具:</p>    <ol>     <li>转换到 ExpenseTracker/client 目录。</li>     <li> <p>运行以下命令:</p> <p>lb-ng ../server/server.js www/js/lb-services.js</p> 在上面的命令中, ../server/server.js 是主要 LoopBack 服务器脚本的相对路径,而 www/js/lb-services.js <p>是该工具生成的文件的名称和路径。</p> </li>     <li>打开 client/www/js/lb-services.js 文件来查看该工具生成的代码。修改现有的 urlBase 变量,以便可以调用客户端实现(此更改仅适用于本地测试): <pre>  <code class="language-javascript">var urlBase = "http://localhost:3000/api";</code></pre> </li>    </ol>    <h3>将 ng-resource 模块添加到应用程序</h3>    <p>将 ng-resource 模块添加到客户端应用程序,以便应用程序可以调用 REST API:</p>    <ol>     <li> <p>在应用程序的客户端目录中,运行以下命令:</p> <p>bower install angular-resource</p> 如果被询问,请选择最新的版本。该命令会将所需的库添加到 client/www/lib 文件夹。(此外,您可以从某个 <a href="/misc/goto?guid=4958962108019926031" rel="nofollow,noindex">AngularJS 版本</a> <p>下载该库。</p> </li>     <li>在 <head> 部分,将与 angular-resource <p>相关的 JavaScript 添加到 client/www/index.html 文件:</p> <p>&lt;script src=&quot;lib/angular-resource/angular-resource.js&quot;&gt;&lt;/script&gt;</p> </li>    </ol>    <h3>实现费用输入</h3>    <p>应用程序需要基于表单的输入来调用 REST API,让用户可以输入费用。在 controller.js、app.js 和 index.html 模板中执行以下更改:</p>    <ol>     <li>修改 client/www/js/app.js 中的模块声明,使之包含 lbservices.js 文件,通过将以下代码行 <pre>  <code class="language-javascript">angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])</code></pre> 更改为: <pre>  <code class="language-javascript">angular.module('starter', ['lbServices','ionic', 'starter.controllers'])</code></pre> </li>     <li>在 client/www/js/app.js 中,将以 .config(function($stateProvider, $urlRouterProvider) 开头的数据块更改为: <pre>  <code class="language-javascript">.config(function($stateProvider, $urlRouterProvider) {     $stateProvider       .state('tab', {       url: '/tab',       abstract: true,       templateUrl: 'templates/tabs.html'    })     .state('tab.addexpense', {       url: '/addexpense',       views: {         'tab-addexpense': {           templateUrl: 'templates/tab-addexpense.html',           controller: 'ExpenseController'        }       }     })    //This is required for the below step to display charts     .state('tab.charts', {       url: '/charts',       views: {         'tab-charts': {           templateUrl: 'templates/tab-charts.html',           controller: 'ExpenseController'        }         }     });       // if none of the above states are matched, use this as the fallback     $urlRouterProvider.otherwise('/tab/addexpense');    });</code></pre> </li>     <li>打开 client/www/templates/tabs.html 文件,并将 Dashboard 选项卡的 <ion-tab> 修改为: <pre>  <code class="language-javascript"><!-- Add Expense Tab--><ion-tab title="Add Expense" icon-off="ion-ios-plus-outline"    icon-on="ion-ios-plus" href="#/tab/addexpense">    <ion-nav-view name="tab-addexpense"></ion-nav-view> </ion-tab></code></pre> </li>     <li>将 client/www/templates/tab-dash.html 文件的名称更改为 tab-addexpense.html。使用以下代码替换文件内容: <pre>  <code class="language-javascript"><ion-view view-title="Add Expense">     <ion-content padding="true" class="has-header" scroll="false" overflow-scroll="false">       <div>         <br>         <form name="expensesForm" ng-submit="addExpense()">         <div class="list">           <label class="item item-input">             <span class="input-label">Category</span>             <select class="form-control focus"                 name="category" required ng-model="newExpense.category">                 <option name="Food" id="Food">Food</option>                 <option name="Travel" id="Travel">Travel</option>                 <option name="Miscellaneous" id="Cosmetics">Miscellaneous</option>                 <option name="Education" id="Education">Education</option>               </select>           </label>           <label class="item item-input">             <span class="input-label">Item</span>                 <input type="text" class="form-control" name="item" placeholder="Expense Item Name"                     autocomplete="off" required ng-model="newExpense.item">           </label>           <label class="item item-input">             <span class="input-label">Price</span>                 <input type="text" class="form-control" name="price" placeholder="Expense Price"                     autocomplete="off" required ng-model="newExpense.price">                  <input type="hidden" class="form-control" name="date" placeholder="Date"                      autocomplete="off" required ng-model="newExpense.expensedate">          </label>        </div>              <br>          <button class="btn btn-default" ng-disabled="expensesForm.$invalid">Add Expense</button>        </form>      </div>    </ion-content>    </ion-view></code></pre> </li>     <li>将 Add Expense REST API 调用添加到 client/www/js/controllers.js 文件。此外,将 ExpenseController 添加到控制器: <pre>  <code class="language-javascript">.controller('ExpenseController',            [ '$scope','$rootScope', 'Expense', function($scope, $rootScope, Expense) {       $scope.newExpense = {};       $scope.newExpense.category = 'Food';       $scope.newExpense.expensedate = new Date();       //Method call to create the expense record       $scope.addExpense = function()       {           Expense.create($scope.newExpense).$promise.then(function(expense)           {               $scope.newExpense = {};               $scope.newExpense.category = 'Food';             });       };    }])</code></pre> </li>    </ol>    <h3>将定制的 REST API 添加到 lb-services.js</h3>    <p>对于要使用您在第 2 步中添加的定制 REST API 的应用程序,必须修改 lb-services.js 文件:</p>    <ol>     <li>打开 client/www/js/lb-services.js。</li>     <li>搜索 findOne 方法声明,该声明位于 Expense 模型声明之下。</li>     <li>在紧接着 findOne 方法的后面,为第 2 步中在 expense.js 文件中声明的定制方法添加以下代码: <pre>  <code class="language-javascript">"getMonthlyCategoryBasedAnalysis": {        url: urlBase + "/expenses/getMonthlyCategoryBasedAnalysis",        method: "GET"     },</code></pre> </li>    </ol>    <h3>将 angular-chart 模块添加到应用程序</h3>    <p>要在应用程序中显示基于类别的每月费用图表,可添加 angular-chart 模块:</p>    <ol>     <li>在您的 OS 命令行下,转到客户端目录。</li>     <li> <p>要在 client/www/lib 文件夹中包含所需的库,可以运行以下命令:</p> <p>bower install angular-chart.js</p> 此外,您还可以从 <a href="/misc/goto?guid=4959670597456612515" rel="nofollow,noindex">项目站点</a> <p>下载该库。</p> </li>     <li>在 <head> 部分,将 Angular SDK 添加到 client/www/index.html 文件: <pre>  <code class="language-javascript"><script src="js/lb-services.js"></script></code></pre> </li>     <li>在 <head> 部分,将与 angular-chart 相关的 JavaScript 添加到 client/www/index.html 文件: <pre>  <code class="language-javascript"><script src="lib/Chart.js/Chart.min.js"></script>    <script src="lib/angular-chart.js/dist/angular-chart.js"></script></code></pre> </li>     <li>在 <head> 部分,将与 angular-chart 相关的 CSS 代码添加到 index.html 文件: <pre>  <code class="language-javascript"><link rel="stylesheet" href="lib/angular-chart.js/dist/angular-chart.css"></code></pre> </li>     <li>通过将 chart.js 添加到模块声明,将 chart 模块添加到应用程序: <pre>  <code class="language-javascript">angular.module('starter', ['lbServices','ionic', 'chart.js','starter.controllers'])</code></pre> </li>     <li>将 chart.js 添加到 controllers.js 的第一行: <pre>  <code class="language-javascript">angular.module('starter.controllers', ['chart.js'])</code></pre> </li>    </ol>    <h3>添加一个基于类别的每月费用表</h3>    <p>要检索基于类别的每月费用,必须调用 getMonthlyCategoryBasedAnalysis 方法:</p>    <ol>     <li>打开 client/www/templates/tabs.html 文件并将 Chats 选项卡的 <ion-tab> 更改为: <pre>  <code class="language-javascript"><!-- Charts Tab -->    <ion-tab title="Charts" icon-off="ion-load-d" icon-on="ion-load-b" href="#/tab/charts">       <ion-nav-view name="tab-charts"></ion-nav-view>    </ion-tab></code></pre> </li>     <li>删除或注释掉 client/www/templates/tabs.html 文件中的 Account 选项卡。</li>     <li>将 client/www/templates/tab-chats.html 重命名为 tab-charts.html。</li>     <li>将以下代码添加到 tab-charts.html 文件: <pre>  <code class="language-javascript"><ion-view view-title="Charts" ng-init="drawCategoryMonthlyChart()">     <ion-content>           <canvas id="bar" class="chart chart-bar" chart-data="data" chart-series="series"               chart-labels="labels" responsive="false" height="100" chart-legend="true"               chart-options="{datasetFill: false, scaleBeginAtZero : false}">           </canvas>     </ion-content>    </ion-view></code></pre> </li>     <li>将以下代码添加到 client/www/js/controllers.js 文件,作为 ExpenseController 控制器的一部分: <pre>  <code class="language-javascript">//Method call to draw the chart. Calls the REST API & forms the angular chart based variables.     $scope.drawCategoryMonthlyChart = function()       {           Expense.getMonthlyCategoryBasedAnalysis().$promise.then(function(results)           {                     expenseData = results.data;               var foodPrice = 0, travelPrice = 0, eduPrice = 0, miscPrice = 0;               for(i=0;i<4;i++)               {                    if(expenseData[i].category == "Food")                        foodPrice = expenseData[i].price;                                if(expenseData[i].category == "Travel")                       travelPrice = expenseData[i].price;                                if(expenseData[i].category == "Education")                       eduPrice = expenseData[i].price;                               if(expenseData[i].category == "Miscellaneous")                       miscPrice = expenseData[i].price;               }               $rootScope.labels = ['Food','Travel','Education','Miscellaneous'];           $rootScope.series = ['ThisMonth'];              $rootScope.data = [                 [foodPrice, travelPrice, eduPrice, miscPrice]                  ];             })       };</code></pre> </li>    </ol>    <h2>第 4 步 . 将应用程序推送到 Bluemix</h2>    <p>将服务器应用程序推送到 Bluemix,以便客户端可以调用 REST API:</p>    <ol>     <li>可选:为了减少您上传到 Bluemix 的代码量,请将客户端文件夹移动到不同的地方,并(在您进行到第 5 步时)从新的位置运行客户端应用程序。</li>     <li> <p>在您的 OS 命令行下,转到 ExpenseTracker 目录并运行以下代码:</p> <p>cf push ExpenseTracker -c &quot;node server/server.js&quot;</p> </li>     <li>转到 http:// <em>app-name</em> .mybluemix.net/explorer(其中的 <em>app-name</em> 是您在第 1 步中在 Bluemix 中创建的 Node.js expense-tracker 应用程序的名称)来检查正在运行的 REST API。</li>    </ol>    <h2>第 5 步 . 运行客户端混合应用程序</h2>    <p>因为客户端应用程序是一个混合应用程序,所以它可以在一个浏览器、模拟器或移动设备中运行。这一节将介绍如何在一个浏览器或 iOS 设备中运行它。</p>    <h3>在浏览器中测试应用程序</h3>    <ol>     <li>在 client/www/js/lb-services.js 文件中,更改 urlBase ,使之指向 Bluemix 路由: http://<em>app-name</em>.mybluemix.net/api 。</li>     <li> <p>在您的 OS 命令行下,更改到 ExpenseTracker/client 目录并运行以下代码:</p> <p>ionic serve</p> </li>     <li>在您的浏览器中,转换到 http://localhost:8100/。单击 <strong>Add Expense</strong> 来测试用于添加费用的表单: <img src="https://simg.open-open.com/show/bdd06acf88be63d6f026b64f58c73c5b.jpg"></li>     <li>单击 <strong>Charts</strong> 来查看费用报告: <img src="https://simg.open-open.com/show/086ab2342b5e488428e33705a75cef6f.jpg"></li>    </ol>    <h3>在 iOS 设备中测试应用程序(可选)</h3>    <ol>     <li> <p>在您的 OS 命令行下,转换到应用程序的客户端文件夹并运行以下代码:</p> <p>ionic platform add ios</p> 此命令将向客户端应用程序添加 iOS 平台支持。 (类似地, ionic platform add android <p>将向客户端应用程序添加 Android 平台支持。)</p> </li>     <li>运行 ionic build ios 来构建针对 iOS 设备的项目。</li>     <li>上面的命令创建了一个名为 client/platforms/ios 的文件夹,该文件夹包含一个 Xcode 项目。在您的 Xcode 工具中打开该项目。通过 USB 连接您的设备,并选择要运行该项目的设备: <img src="https://simg.open-open.com/show/31bdee0aa85cb9ca1e9d672818def1dc.jpg"></li>     <li>测试用于添加费用和查看费用图表的应用程序界面: <img src="https://simg.open-open.com/show/09918eb3a7c5a025f5c6c5c46a347378.jpg"> <img src="https://simg.open-open.com/show/b00768ec0c5dd02da4535ada6a456e62.jpg"></li>    </ol>    <p>阅读: <a href="/misc/goto?guid=4959670597536807022" rel="nofollow,noindex">测试您的 Ionic 应用程序</a></p>    <p>备注:您的应用程序需要能够访问 HTTP 传输,因为它要调用 REST API。您可能会得到消息 App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure 。您可以通过添加以下代码,通过应用程序的 client/platforms/ios/client/Info.plist 文件处理临时异常:</p>    <pre>  <code class="language-javascript"><key>NSAppTransportSecurity</key>     <dict>       <key>NSAllowsArbitraryLoads</key>       <true/>  </dict></code></pre>    <p>阅读: <a href="/misc/goto?guid=4959670597616836499" rel="nofollow,noindex">NSAppTransportSecurity</a></p>    <h2>结束语</h2>    <p>通过使用 StrongLoop LoopBack 框架和 Ionic 框架来开发示例应用程序,您现在知道了(使用正确的工具)公开 REST API 并在混合应用程序使用它们是多么容易。您可以扩展在本教程中学到的知识,通过定义模型之间的关系,创建生产就绪的、企业级的应用程序。</p>    <p>BLUEMIX SERVICE USED IN THIS TUTORIAL: Cloudant NoSQL DB 提供了对始终打开的完全托管 NoSQL JSON 数据层的访问。</p>    <p>相关主题: <a href="/misc/goto?guid=4959670597701660959" rel="nofollow,noindex">移动开发</a> <a href="/misc/goto?guid=4959670597785020778" rel="nofollow,noindex">Node.js</a></p>    <p>来自: <a href="/misc/goto?guid=4959670597856500926" rel="nofollow">http://www.ibm.com/developerworks/cn/mobile/mo-build-a-hybrid-app-strongloop-bluemix-trs/index.html?ca=drs-</a></p>