构建meteor应用程序_使用Meteor的即时Web应用程序

构建meteor应用程序

流星,一个用于Web应用程序开发的平台,正在获得广泛的国际采用。 Meteor不仅是JavaScript编码框架,还提供了一种创新的方式来构建可伸缩,丰富的交互式Web应用程序。 流星承诺通过简化编码模型并减少开发人员必须编写的代码量来加快开发周期。 使用Meteor,经验丰富的Web应用程序架构师和开发人员可以在几周甚至几天内从概念到完整部署。

有关安装和开始使用Meteor平台进行开发的分步指南,请遵循Meteor网站上的“ 快速入门”文档。 在本教程中,我将通过两个详细的应用程序示例深入介绍Meteor开发,并概述Meteor的Web应用程序开发方法。 有了这些知识,您就可以自行决定是否可以使用Meteor快速创建Web应用程序。

展望未来

流星使用的方法在某种意义上是革命性的,但它也有一些进化方面。 它与计算历史上最伟大的成就之一-电子表格软件沿着相同的IT路径继续发展。 图1显示了一个典型的电子表格示例:带有饼图的Sales by Region电子表格。

图1.按地区销售电子表格
一个典型的电子表格的屏幕截图,该电子表格显示了按地区划分的销售额以及总销售额的饼图

如果您在“按地区销售”电子表格中修改了任何区域销售数字,则饼图会立即重绘以反映切片的新相对比例。

这种电子表格功能不再是新颖的,而是可以想象它的影响可以追溯到1983年Lotus 1-2-3推出该功能时。 早期的PC用户从来没有做任何编程就可以做如此多的工作。 电子表格软件仍然是推动全球PC销售的杀手级应用程序之一。

快进的三十年

本教程的第一个Web应用程序示例-图2中所示的Sales Portal应用程序-演示了大约在2015年流星电子表格的隐喻如何随着Meteor演变而来。

图2. Sales Portal Web应用程序
“按地区划分的流星销售额”应用程序的屏幕截图,显示按地区划分的销售额和总销售额的饼图

销售门户网站显示最新的区域销售数字和相应的饼图。 全球销售总监可以使用该应用程序监视销售,每个区域销售团队可以在进行销售时更新其销售数据。

如果已安装Meteor,则可以下载 Sales Portal应用程序并进行动手操作。 转到下载的sales_nologin子目录,然后键入meteor 。 将浏览器实例指向http:// localhost:3000 /以显示区域销售数字和饼图。 (如果您无法安装Meteor,则可以运行IBM Bluemix托管版本 。)单击任何销售数据进行更改。 确认更改后,饼图将立即更新。 如果您将多个浏览器实例指向Sales Portal,则所有实例都会更新以显示最新的销售数据,并且您可以从任何一个浏览器实例中修改这些数据。

图3显示了美国中央团队选择和更新其销售数据。

图3.更新美国中部销售
在Meteor Sales Portal Web应用程序中选择和更新美国中部地区销售数据的用户的屏幕截图

图4显示了更新的美国中部销售数据和最新的饼图。 任何在更新时同时访问Sales Portal的用户都会立即看到更改。

图4.更新饼图比例以反映新的美国中部销售数字
反映了新的美国主要销售数据的更新饼图的屏幕截图

除了手动更新,您还可以想象一个后端,在该后端中,销售数据由在更新之前自动收集和合并的子聚合组成。 Sales Portal应用程序的视觉呈现与古老的电子表格的视觉呈现相同,但是Sales Portal现在还具有:

  • 通过无处不在的浏览器进行全球Internet访问
  • 多个用户同时访问
  • 可选的自动后端数据聚合和合并

使用标准企业技术(例如,基于Java™的工具链)来设计,编码和部署这样的系统将需要大量的精力。 如您将在随后的代码演练中看到的,Meteor极大地减少了这种工作。

积极思考

这种方法大大减少了您需要编写,调试和测试的基础结构代码的数量。

电子表格的主要功能是其React性。 在“按地区销售”示例中,当更新地区销售数据时,将即时重新计算依赖于该数据的所有其他值。 如果从属组件提供图形输出(例如饼图),则将使用更新的切片大小立即重绘该图表。 您无需编写用于管理依赖关系的代码(可能很复杂),也不需要编写用于更新组件(如饼图)的代码。 您要做的就是声明React性元素(销售数据)及其相关性(在这种情况下为饼图)。 电子表格会处理所有这一切。

现在想象一下今天使用Web应用程序做同样的事情,并且您对Meteor如何简化基于Web的系统创建有了很好的了解。

设计Meteor应用程序时,您需要确定React性元素,例如区域销售数据收集。 然后,使用标准HTML,CSS,客户端JavaScript库和组件(例如JQuery,JQuery UI或JQuery Mobile)和模板技术(例如, 空格键 )来布局表示层(概念与JavaServer Pages类似,但通常可以运行)在客户端)。 流星跟踪React性元素的所有依赖性,然后重新渲染视觉元素并重新计算依赖性以反映最新的更新值。

这种方法大大减少了您需要编写,调试和测试的基础结构代码的数量。 您不需要编写自定义后端Web服务来同步更新请求,也不需要编写用于更新数据库或数据存储的代码,也不需要编写将更改通知推送到其他连接的客户端的代码,也不需要编写用于获取更新的代码。值从后端发出通知。

深入研究Sales Portal代码

清单1显示了sales.js文件,其中包含Sales Portal应用程序背后的所有服务器和客户端逻辑。 这是我需要为该应用程序编写的唯一JavaScript代码。 (您可以在代码下载的sales_nologin目录中找到sales.js。)

清单1. Sales Portal的客户端和服务器端逻辑:sales.js
SalesData = new Meteor.Collection("regional_sales");
if (Meteor.isClient) {

    Template.salesdata.helpers({ 
        dataset : function () {
                    return SalesData.find({}, {sort: {row : 1}});
                  }
    });

    Template.datapoint.helpers({ 
        selected :  function () {
                        return Session.equals("selected_datapoint", this._id)
                           ? "selected" : '';
                    }
    });

    Template.title.helpers({
        thisyear:  new Date().getFullYear()
    });

Template.datapoint.events({
        'click': function (event, template) {
          Session.set("selected_datapoint", this._id);
        }
    });

    Template.piechart.helpers({
     'plotchart' : function() {
       plotit(this, SalesData.find({}));
     }
    });

    function plotit(inst,cur)  {

     if (cur.count() === 0)  // do not render pie if no data
           return;
         var data = [];
         cur.forEach( function(sale) {
           data.push( [sale.region, sale.total]);
         });
      window.$.jqplot('chart', [data], 
        { 
          seriesDefaults: {
            // Make this a pie chart.
            renderer: $.jqplot.PieRenderer, 
            rendererOptions: {
              // Put data labels on the pie slices.
              // By default, labels show the percentage of the slice.
              showDataLabels: true
            }
          }, 
          legend: { show:true, location: 'e' }
        }
      );   

    }

    Template.datapoint.onRendered(function()
    {
       this.$('.editable').editable( {
         autotext: 'never',
         type: 'text',
         width: 10,
         mode: 'inline',
         success:    
          if (newvalue != "") {
            var testint = Number(newvalue);
            if (Math.floor(testint) == newvalue) {
           SalesData.update(Session.get("selected_datapoint"), {$set: {total: parseInt(newvalue)}});
          } else {
           return ({newValue: $(this).text()}); 
          }
        } else {
          return ({newValue: $(this).text()});
        },
      display: function() {
       // dummy display function so 'text' is not set, Blaze will set it
      }
      });
});
} // if isClient

if (Meteor.isServer) {
  Meteor.startup(function () {
   if  ((process.env['CLEARDATA']) || (SalesData.find().count() == 0)) {
      var roworder = 0; 
      SalesData.remove({});
      SalesData.insert({region:"US East", total: 2032333, row: roworder++});
      SalesData.insert({region:"US Central", total: 150332, row: roworder++});
      SalesData.insert({region:"US West", total: 1202412, row: roworder++});
      SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});
  }  
                  
  });

}

Meteor.isClientMeteor.isServer变量周围的条件是Meteor核心提供的运行时上下文指示符,可在代码中的任何位置使用。 在这种情况下,它们允许在同一sales.js文件中组合客户端代码和服务器端代码。 条件之外的任何代码都可以在客户端和服务器上运行。

或者,您可以通过将服务于客户端的代码放在名为client的子目录中,并将服务器端代码放在名为server的子目录中,来分隔客户端和服务器源代码。 在这种情况下,您可以将提供给客户端的所有资产(例如图像)放在名为public的子目录中。 如果要将某些资源限制为仅用于服务器访问(而不是将其提供给客户端),请将它们放在名为private的子目录中。 (本教程稍后将使用的照片共享应用程序将使用该目录结构。)

识别React性数据

清单1中selected_datapoint会话变量是React性的。 (有关默认情况下是无功的元素的更多信息,请参见“ 流星无功默认值”侧边栏。)在这种情况下,该变量用于更改销售数字的行突出显示。 通过动态CSS样式的更改来执行行突出显示。 当用户单击一行时, selected_datapoint会话变量将更新。 由于Meteor每次更改此变量时都会重新渲染依赖关系,因此高亮会相应更新。 请注意, selected_datapoint仅存在于客户端。

Sales Portal应用程序的另一个数据响应源是对SalesData Meteor集合的查询。 与selected_datapoint不同, SalesData在客户端和服务器上都存在; 在服务器上,它是一个MongoDB集合。 您可以在清单1中看到SalesData的用法。

由于查询是React式的,因此查询结果集更改时,将重新计算或重新呈现其所有依赖项。 通过这种方式,可以更新所有浏览器实例中的销售数据和饼图。 清单2显示了相关HTML模板代码,这些代码位于代码download的sales_nologin目录中的sales.html文件中。

清单2.客户端HTML和模板:sales.html
<template name="salesdata">
  <div class="salesdata">
    {{#if Template.subscriptionsReady}}
      {{#each dataset}}
        {{> datapoint}}
      {{/each}}
    {{/if}}
  </div>
</template>

<template name="datapoint">
  <div class="datapoint {{selected}}">
    <div id="{{_id}}_region" class="region">{{region}}</div>
    <div id="{{_id}}_total" data-inputclass="inputclass" class="sales editable">{{total}}</div>
  </div>
</template>

清单2中HTML文件是一个空格键模板。 Spacebars是Meteor自己的模板引擎。 您可以在清单2中的双花括号{{ }}看到空格键表达式。 (通过其Blaze渲染系统,Meteor还可以与其他JavaScript模板引擎一起使用。)

通过清单2中显示的salesdata模板代码呈现销售图的行。 由于此模板取决于dataset帮助器功能(如清单1所示),因此每次所包含的React式查询发生更改时,都会重新渲染该模板。

在服务器上播种样本数据

Sales Portal的初始区域销售数据是由清单3中所示的服务器端代码(来自清单1 )提供的。

清单3.在MongoDB中植入数据的服务器端代码
SalesData.remove({});
 SalesData.insert({region:"US East", total: 2032333, row: roworder++});
 SalesData.insert({region:"US Central", total: 150332, row: roworder++});
 SalesData.insert({region:"US West", total: 1202412, row: roworder++});
 SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});

在Meteor服务器上,一个完整的MongoDB实例正在运行。 (此完整实例可以接受来自Meteor以外的其他客户端的查询和更新。)相同JavaScript MongoDB API也可以在客户端使用,以统一客户端和服务器的编码,并允许客户端和服务器上的代码重用。 客户端API由称为Minimongo的Mongo模拟器提供。 Minimongo使用延迟补偿来反映数据库更改。 因为Minimongo通常处理小的客户端数据集,所以它不支持索引。

异步发布/订阅模型用于控制在MongoDB服务器和Minimongo客户端之间同步的数据。 默认情况下,将发布所有服务器端Meteor集合。 流星使用分布式数据协议(DDP)在客户端和服务器之间移动数据。 (可以为其他数据库创建客户端仿真器和服务器端提供程序形式的DDP驱动程序; Meteor社区中正在进行的工作包括PostgreSQL驱动程序和RethinkDB驱动程序)。

集成jQuery插件

Sales Portal使用jqPlot jQuery插件呈现饼图。 饼图的呈现和重新呈现是由SalesData集合中的数据更改来被动地驱动的。 您之前已经看到,每次SalesData集合更改时,都会salesdata模板。 清单4显示了客户端功能(来自清单1 ),该功能在由salesdata模板的rendered事件触发时重绘饼图。

清单4.使用jqPlot插件呈现饼图的jQuery代码
window.$.jqplot('chart', [data], 
     { 
       seriesDefaults: {
         // Make this a pie chart.
         renderer: $.jqplot.PieRenderer, 
         rendererOptions: {
           // Put data labels on the pie slices.
           // By default, labels show the percentage of the slice.
           showDataLabels: true
         }
       }, 
        legend: { show:true, location: 'e' }
     }
   );

Sales Portal使用x可编辑的 jQuery插件来启用销售数据的就地编辑。 清单1Template.datapoint.onRendered()handler内部将显示处理编辑的代码。

改善销售门户访问安全性

Meteor支持的默认原型模式非常适合应用程序的初始快速发展。 在此阶段,您可能需要快速迭代来修改交互,UI甚至是应用程序逻辑-通常不涉及任何敏感数据。 您可以与合作的开发人员共享URL,并查看用户以收集反馈。 但是拥有销售门户URL的任何人都可以查看甚至更改销售数据。 对于生产用例,这种开放访问模型太宽松了。

自然而然的下一步是通过打开Meteor的安全功能来锁定应用程序。 下载门户的sales子目录中提供了更安全版本的Sales Portal的代码。 新增的安全功能是:

  • 用户认证系统,仅允许授权用户访问门户
  • 确保只有区域销售数据的正式所有者才能修改该数据的代码
  • 更好的源代码组织,以确保永远不会将潜在的机密服务器端代码提供给已部署的客户端

从现在开始,我对Sales Portal应用程序的所有引用都是对sales目录中的安全版本的引用。

删除客户端修改服务器数据的功能

锁定应用程序的一个好的开始是防止任何人修改数据。 在这种情况下,您需要做的就是使用以下命令删除insecure软件包:

meteor remove insecure

insecure程序包告诉服务器在读取或更改数据之前不要检查访问规则。 默认情况下已安装此软件包,允许所有访问。 删除后,没有客户端可以修改任何服务器数据。 如果您返回到其中一个浏览器实例并尝试修改任何销售数据,您会注意到该应用程序尝试更改数据但很快恢复,这反映了对服务器访问的拒绝。 (这是一个实际的延迟补偿示例。实际上,客户端中的数据会暂时更新,但是当权威服务器副本到达时,它将覆盖客户端的数据。)

删除insecure程序包之后,必须添加访问规则以明确允许(特定用户)访问特定数据。 但是您还没有用户。 接下来必须添加用户数据库和登录授权系统。

确保只有授权用户才能查看销售数据

在添加用户授权系统之前,请确保没有人可以看到销售数据。 (授权用户以后可以查看它。)现在,即使他们不能修改数据,任何人都可以通过转到Sales Portal URL来查看数据。

删除默认的autopublish程序包,以防止任何流星收集数据从服务器推送到客户端-服务器明确发布并由客户端预订的数据除外:

meteor remove autopublish

如果您现在访问销售门户URL,则看不到区域销售数据和饼图。

通过accounts包添加用户登录

流星有可用的软件包,使添加用户登录和授权系统变得简单。 accounts-uiaccounts-password包涵盖了端到端的工作流程; 它们包括所需的前端UI,后端数据库和客户端到服务器的API。 您可以使用以下命令将所有这些功能添加到Sales Portal:

meteor add accounts-password accounts-ui

account-password软件包支持用户创建和通过email-address-plus-password登录。 该实现使用安全远程密码协议,并且在客户端和服务器之间永远不会发送纯文本密码。

除了基于密码的登录之外,您还可以让用户通过Facebook,Twitter,微博,GitHub和Google进行登录-只需向您的应用程序添加一个或多个软件包即可。 (社交网络OAuth登录支持对于面向消费者的应用程序很有价值,但在企业Intranet环境中的适用性可能有限。)

登陆界面

accounts-ui软件包提供了一组预制CSS样式的UI小部件(并支持JavaScript代码),用于处理用户登录,新用户创建和密码丢失恢复。 要添加这些小部件,请包含{{>loginButtons}}空格键模板。 清单5显示了在sales / sales.html文件的一部分中添加到Sales Portal应用程序的登录名。

清单5.添加用户登录和授权系统
<body>
<div id="title">
   <div>
        {{> title }}
   </div>
   <div> 
       <div style="float: right">
       {{> loginButtons align="right"}} 
     </div>
   </div>
   </div>
  </div>

示例代码下载中的sales目录包含带有用户访问控制的完整的Sales Portal应用程序。 运行此版本(或Bluemix托管的版本 )以尝试登录。启动浏览器实例,并注意右上角的Sign in链接。 单击它,您应该看到如图5所示的对话框。

图5. accounts-ui程序包的“登录”对话框(显示在Firefox中)
登录对话框的浏览器(Firefox)屏幕截图

accounts-ui程序包使用Meteor集合和发布/订阅(也可以在您自己的代码中手动使用的相同工具)实现用户数据库。 在当前版本的Sales Portal中,我在数据库中创建了两组用户凭据(电子邮件地址/密码):joe@dwtestonly.com / abc123和sing@dwtestonly.com / abc123。 打开两个浏览器实例,然后分别使用一个凭据登录。

您可以通过单击“ 登录”对话框中的“ 创建帐户”链接来创建更多用户。 图6显示了“创建新用户”对话框,它是accounts-ui软件包的一部分。

图6.用于从accounts-ui程序包创建新用户帐户的对话框(在Chrome中显示)
用于创建新用户的对话框的浏览器屏幕截图(来自Chrome)

owner字段添加到区域销售数据

在当前版本的Sales Portal中,初始数据库内容已被修改。 我使用清单6中的服务器端代码来播种数据。

清单6.服务器端数据播种代码
SalesData.remove({});
SalesData.insert({region:"US East", total: 2032333, row: roworder++});
SalesData.insert({region:"US Central", total: 150332,  row: roworder++, owner: joeid});
SalesData.insert({region:"US West", total: 1202412, row: roworder++});
SalesData.insert({region:"Asia Pacific", total: 701223, row: roworder});

清单6代码中添加了一个新的owner字段。 在这种情况下, owner字段包含拥有美国中部地区数据的用户(joe@dwtestonly.com)的用户ID。 此字段用于将区域销售数据更新仅限制为joe@dwtestonly.com。 您可以通过查询Meteor.users集合来获取用户ID值。

细粒度选择性服务器数据发布

随着autopublish包装中取出,有必要从服务器明确的发布数据,并明确从客户端订阅。

对于销售门户网站,则服务器将发布的regional_sales使用清单7中的代码,这是销售/服务器/ sales.js文件的一部分集合。

清单7.从服务器选择性地发布数据
Meteor.publish("regional_sales", function () {
      if (this.userId) {  // only visible to logged in users
      // do not include the owner field for client access
      return SalesData.find({}, {fields: {"region": 1, "total":1 }}); 
      }
});

在清单7中,请注意this.userId的使用,以确保有效的用户登录到客户端会话。 当Meteor代表用户运行服务器代码时, this.userId始终包含当前登录用户的唯一ID。 如果当前浏览器实例没有登录用户,则this.userId为null,并且不会发布任何数据。 此外,在清单7中,不是区域销售数据文档的所有字段( 文档实质上是在MongoDB实例中具有可变字段数的记录)在发送给客户的集合中没有返回。 特别是,文档的owner字段对客户端是隐藏的。 这样,您可以使用查询仅将包含子集字段的集合子集仅发布给具有授权登录用户的客户端。 此技术对于确保客户端浏览器无法访问某些文档中的敏感数据字段很有用。

客户端数据订阅

Sales Portal客户端代码明确订阅了服务器发布的regional_sales集合,如清单8所示。Meteor支持基于每个模板实例的订阅。 使用每个模板的预订可确保仅推送模板实例呈现的数据,并在销毁模板实例时正确删除预订。

清单8.每个模板客户端订阅服务器中的集合
Template.piechart.onCreated(function() {
  this.subscribe("regional_sales");
});

Template.salesdata.onCreated(function() {
  this.subscribe("regional_sales");
});

添加访问规则以允许区域销售更新

删除insecure程序包后,将有效地拒绝所有用户更新销售数据。 假设不同的地区销售数字由不同的用户拥有,则可以添加访问规则,以允许通过joe@dwtestonly.com更新美国中央数据。 清单9在名为model.js的服务器端源文件中显示了此访问规则。

清单9.服务器端访问规则,允许所有者更新销售数据
SalesData.allow({
  update: function (userId, sales, fields, modifier) {
    if (userId !== sales.owner)
      return false; // not the owner

    var allowed = ["total"];
    if (_.difference(fields, allowed).length)
      return false; // tried to write to forbidden field

    return true;
  },

});

如果允许update ,则update操作的访问规则函数将返回true如果不允许更新,则将返回false 。 清单9中的代码检查以确保用户是所有者,并且仅对total字段进行了修改。

打开销售门户并以joe@dwtestonly.com登录。 尝试修改美国西部的数据,请注意您不能。 然后尝试修改美国中央数据。 由于joe@dwtestonly.com是此数据的所有者,因此可以更新它。

启动另一个浏览器实例,并以sing@dwtestonly.com登录。 尝试修改任何销售数据,请注意您不能。 由于sing@dwtestonly.com不是任何销售数据的所有者,因此服务器将拒绝该用户的所有修改请求。

如果用户未登录,则可以使用客户端的currentUser帮助程序来避免呈现模板。将清单10中的代码添加到HTML文件中。

清单10.消除呈现空模板的尝试
<div id="container">
    <div id="salestable">
      {{#if currentUser}}
          {{> salesdata}}
      {{/if}}
    </div>
   <div>
      {{#if currentUser}}
           {{> piechart}} 
       {{/if}}
        </div>
</div>

现在,启动一个新的Sales Portal浏览器实例。 请注意,没有数据可见。 以sing@dwtestonly.com身份登录,请注意,现在您可以看到数据和饼图。 现在尝试修改一个字段; 同样,您不能修改它,因为您不是所有者。

启动另一个浏览器实例,以joe@dwtestonly.com登录,并注意数据可见。 修改美国中央图,并注意饼图更新。 确认sing@dwtestonly.com会话中的饼图也已更改。 退出两个会话,然后注意数据现在消失了。

云中的应用程序部署

将Meteor应用程序部署到Bluemix很简单。 按照我的截屏视频中的说明进行操作:

您还可以使用内置的Meteor命令将应用程序部署到Meteor的云托管服务器上。 在撰写本文时,此服务是免费的。 您从应用程序目录发出以下命令:

meteor deploy applicationname.meteor.com

该应用程序名称必须唯一,因为它将以http:// applicationname .meteor.com(在Internet上全球可用)提供。 首次部署应用程序时,系统会提示您在meteor.com上创建一个帐户。

在撰写本文时,Meteor团队正在研究一种名为Galaxy的新产品:基于Docker容器的Kubernetes编排的可伸缩部署平台。

要将应用程序托管在自己的服务器基础结构上,您需要一台预装有Node.js和MongoDB功能的服务器。 您可以使用以下命令创建应用程序的可部署捆绑包:

meteor build  directory to place deployable bundle

由于服务器端可部署的是Node.js应用程序,因此您可以根据自己的互操作性或扩展要求自定义部署拓扑。

Meteor服务器端代码在Node.js 光纤上运行(请参阅Node.js光纤上的侧边栏),提供了一个虚拟环境,您可以在其中进行编码,就好像一个线程正在处理每个传入请求(无共享状态)。 这种方法可以简化服务器端JavaScript逻辑的编码。

Foto Share:移动照片共享服务

既然您已经了解了一些流星代码的设计和计划可以带给您什么,那么您可能已经在考虑一个或两个启动项目。 下一个示例将为您创建移动设备的Meteor应用程序时提供更多思路。

Foto Share是面向手机用户的基于概念验证的基于Web的照片共享服务。 用户可以在手机上浏览自己的照片集,并通过单击“ 共享”按钮与朋友分享照片。 图7显示了在Apple iPhone上运行的Foto Share。

图7. Apple iPhone上的Foto Share
Apple iPhone上的Foto Share的屏幕截图

就像在Sales Portal项目中一样,出于相同的安全原因, autopublishinsecure软件包已从Foto Share中删除。 为了实现基于密码的登录,Foto Share添加了accounts-uiaccounts-password程序包。 代码下载中的Foto Share应用程序具有与Sales Portal相同的两个用户。

要试用Foto Share,请首先从代码下载中的fotoshare目录运行该应用程序。 (如果未安装Meteor,则可以运行Bluemix托管的版本 。)如果您有两部手机,请将每个人的浏览器指向Foto Share。 否则,请继续使用PC浏览器。 一个使用sing@dwtestonly.com登录,另一个使用joe@dwtestonly.com登录(使用与Sales Portal相同的密码)。 您可以通过扫过Sing的照片来浏览它们,或触摸两边的覆盖物。 每张新照片都会滑入视图。 您会发现Sing的所有照片都是夏威夷的场景,而Joe的则是阿兹台克人和玛雅人的遗物。

准备测试共享功能时,请在Joe的收藏集中选择一张照片,然后触摸手机上的“ 共享”按钮。 在Sing的电话上,Meteor会动态更新已订阅的收藏集,现在可以在Sing的电话上查看Joe的共享图片。

Foto Share用户登录界面

能够放入可自定义的移动登录UI就像在Meteor Web应用程序中一样,将是很棒的选择,但是Meteor还没有移动友好的accounts-ui包。 对于Foto Share,我使用了accounts-ui Web UI。 图8显示了手机上显示的登录对话框。

图8. Foto Share登录屏幕
手机上的Foto Share登录屏幕的屏幕截图

识别Foto Share中的React数据

从概念上讲,使React最自然的数据收集是用户照片集。 这样做将使Meteor可以在用户共享他或她的照片时更新和重新呈现照片列表。 这就是本概念证明中采用的方法。 对于较大的系统,取决于图像的后端存储体系结构,您可能希望仅使照片的元数据具有React性,而不是使图像本身。

看一下清单11所示的服务器端数据播种代码,以了解照片的存储方式。

清单11. Foto Share服务器端数据播种和集合发布代码
Meteor.startup(function () {
      
      ...     
      
      Fotos.remove({});
      Fotos.insert({name:"pic1", img: readPic('pic1.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic2", img: readPic('pic2.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic3", img: readPic('pic3.jpg'),
       owner: sing._id, shared:false});
      Fotos.insert({name:"pic4", img: readPic('pic4.jpg'),
       owner: joe._id, shared:false});
      Fotos.insert({name:"pic5", img: readPic('pic5.jpg'),
       owner: joe._id, shared:false});
      Fotos.insert({name:"pic6", img: readPic('pic6.jpg'),
       owner: joe._id, shared:false});

    Meteor.publish("photos", function () {
      if (this.userId) {  // only visible to logged in users
       return Fotos.find( {$or : [{owner: this.userId}, {shared: true}]},
  {fields: {"name": 1, "img":1 , "owner": 1}}); 
      }

  });
});

服务器发布的收藏集是FotosFotos代表照片的每个文档都有nameimgowner字段。 从相应的本地存储的JPG文件中读取img字段。 再次注意,订阅客户端收到的数据仅包含该用户自己的照片,以及其所有者共享的任何其他照片。 在这里,选择性字段过滤也用于从客户端接收的Foto集合中删除shared字段。 owner字段尚未被过滤掉,因为客户端可能希望显示共享图片的所有者名称。 清单12显示了readPic()辅助函数。 该函数使用Meteor的Assets.getBinary()帮助程序将图像读取到内存中,然后将二进制流编码为base64以存储到img字段中。 当在客户端检索照片时,此格式很方便显示照片。 Assets包可用于访问专用子目录下仅对服务器可用的资源。

清单12.读取MongoDB存储的JPG图像的Helper函数
function readPic(infile)  {       
      var data = Assets.getBinary('images/' + infile);
      var buf =  new Buffer(data);
      var tp = buf.toString('base64');
      return  'data:image/jpeg;base64,' + tp;       
  }

从数据库重构图像时,模板代码利用了大多数现代浏览器中<IMG>标记中的数据URL支持。 <IMG>标记的SRC属性支持数据URL,从而可以通过base64编码的字符串动态设置图像的二进制位。 Listing 13 shows the photoitem template. In this template the base64-encoded img field from a photo is used to render the image.

Listing 13. Setting an IMG tag's SRC attribute using data URL
<template name="photoitem">
  <div class="m-item">
       <img id="{{_id}}" src="{{img}}" />
  </div>
</template>

Meteor Remote Methods: Custom RPCs made simple

Even though the insecure package was removed, no access rule has been created in Foto Share. Without access rules, no client can update data via Minimongo. But when the Share button is tapped, the share field of the photo must have been updated somehow. 怎么样? The answer is Meteor Remote Methods.

Meteor Remote Methods is a Remote Procedure Call (RPC) mechanism. You can create RPC calls from the client to the server in two steps:

  1. Define a JavaScript function on the server side.
  2. Use Meteor.call() to invoke the server function remotely, optionally passing arguments and callback.

Meteor takes cares of all the endpoint setup, takedown, and data-marshalling chores in between.

When you tap the Share button in Foto Share, the client calls a Meteor Remote Method on the server named shareThisPhoto and passes the photo's ID as an argument. On the server side, the code first checks to see if the caller is the owner of the photo, and it updates the photo's shared field if and only if the owner called the method. Listing 14 shows the server-side shareThisPhoto code.

Listing 14. Meteor Remote Method on the server side to update a photo's shared field
Meteor.methods({
  shareThisPhoto: function (photoId) {
var curPhoto = Fotos.findOne({_id: photoId});
    if (this.userId !== curPhoto.owner)  {
      return "Cannot share this photo.";
    } else {
      Fotos.update({_id: photoId}, {$set :{shared: true}});
      return "Photo shared!";
    }

  },
});

Listing 15 shows the client-side code that invokes the remote method when you tap the Share button.

Listing 15. Client-side code to invoke the remote method when the Share button is tapped
Template.photopage.events({
  'click .fs-logoff': function () {
    Meteor.logout(function() {

      location.reload();
    });
  },
  
  'click .fs-share': function() {
      var curselected = $('.m-active > img').attr('id');

      Meteor.call('shareThisPhoto', curselected, function (error, retval) {
 console.log(retval);
      });
  }
});

I've chosen the RPC approach to demonstrate Meteor Remote Methods. You could instead define an access rule to allow an owner to update the shared field. In that case, you then must locally update the shared field of the photo when the user taps the Share button. Meteor's Minimongo pushes the update to the server, then to all other subscribed clients.

A platform for building modern web applications

Now that you've worked through this article's sample applications, it should make sense that Meteor is designed for realtime asynchronous streaming-update web applications.

These types of applications typically consist of a highly interactive single-page UI. Users typically don't experience new page loads; instead, a portion of the displayed page updates instantaneously in response to user interaction (or data changes), with few or no network round-trip delays. The single-page interface in no way restricts the application, because portions of the page can be updated in an infinite variety of ways. This design is reminiscent of a stand-alone desktop application such as a word processor or spreadsheet.

These types of web applications typically load JavaScript application code on the client browser. This code manages the interaction with the user by dynamically manipulating the browser's DOM, modifying CSS styling, generating new HTML elements/code/styling, and using other browser-provided APIs. All interfacing with the user is controlled by the client-side code; no additional HTML or styling is loaded via the network except for the initial application load. The same code also shuttles data back and forth between the client and the server(s) to implement application features. In effect, the browser loads and runs a rich-client (sometimes called fat-client) application written in JavaScript.

On the server side, endpoints are set up to source and sync data from the client securely. Legacy back ends can have RPCs, XML-based web services, RESTful services, or other JSON-style RPC calls. Modern back ends are likely to be streaming data asynchronously from servers via proprietary protocols that are designed to be efficient for the data on the wire, resilient to occasional disconnection, supportive of a variety of current transports, and topologically scalable.

结论

The Meteor team is working to level the playing field for everyone who wants to create single-page, highly interactive, real-time web applications. Most users prefer such applications over the legacy page-at-a-time style. Many of the major web-based mail and office services — including Facebook's Instagram, Google Gmail, Microsoft Hotmail, and Yahoo Mail — use this application architecture. We don't see many instances of these kinds of web applications other than ones developed by the biggest tech companies or most-well-funded startups because they are difficult to build, requiring significant effort and resources. Meteor's stated core mission is to provide a base on which this class of application can be built easily.

Meteor's entrance on the scene makes this a great time to revisit all those long-forgotten application ideas you have stashed away, and see if converting them into a public-facing service might be an appealing venture. If you are already creating or maintaining web applications, Meteor might prove to be the most potent tool in your ever-expanding array of options.


翻译自: https://www.ibm.com/developerworks/opensource/library/wa-meteor-webapps/index.html

构建meteor应用程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值