Day 15:Meteor —— 从零开始创建一个 Web 应用

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 到目前为止我们讨论了Bower、AngularJS、GruntJS和PhoneGap等JavaScript技术。今天是“30天学习30种新技术”挑战的第15天,我决定重返JavaScript,学习Meteor框架。虽然Meteor的文档相当好,但是它缺少为初学者准备的教程。我觉得教程的学习效果更好,因为教程可以帮助你快速上手一种技术。本文将介绍如何利用 Meteor 框架构建一个epoll应用。

编者注:我们发现了有趣的一系列文章《30天学习30种新技术》,正在翻译中,一天一篇更新,年终礼包。下面是第15天的内容。


到目前为止我们讨论了BowerAngularJSGruntJSPhoneGap等JavaScript技术。今天是“30天学习30种新技术”挑战的第15天,我决定重返JavaScript,学习Meteor框架。虽然Meteor的文档相当好,但是它缺少为初学者准备的教程。我觉得教程的学习效果更好,因为教程可以帮助你快速上手一种技术。本文将介绍如何利用 Meteor 框架构建一个epoll应用。

image.png

Meteor是什么?

Meteor是新一代的开发即时web应用的开源框架,它能帮助你在最少的时间内完成开发。它的理念和AngularJS、BackboneJS等框架大不相同。当我们在backbone 和 angular 上工作时,客户端(Angular或Backbone)和REST后端通讯。我们可以用任何技术写 REST 后端,例如 Java、NodeJS、PHP。


Meteor使用DDP(分布式数据协议)在客户端和服务器间传送数据。客户端JavaScript开发者需要解决的首要问题是:向后端的数据库发起查询,发送数据到客户端,当数据库变动时,推送变动到客户端。DDP是解决这一问题的标准做法。


Meteor应用的后端基于Node和MongoDB。前端和后端的应用同时使用Meteor的API。未来开发者可以选择 MongoDB 之外的其他数据库。


为什么使用Meteor?

请阅读Meteor的七大原则


应用案例

本文中我们将搭建一个 epoll 应用,该应用允许用户发布问题并投票。这个应用可以做到:

  • 当用户访问/时,会看到一个问题列表。用户需要通过Twitter登录,以便投票或发布新问题。如下图所示,由于未登录,投票按钮不可用。

image.png

  • 当用户点击Sign in with Twitter之后,他将授权 epoll 应用使用他的账号。授权成功之后,用户可以投票或发布新问题。

image.png

GitHub仓库

今天的示例应用的代码可以从GitHub取得。


安装Meteor

开始使用Meteor很容易。如果你使用Mac或Linux,只需输入如下命令:

curl https://install.meteor.com | /bin/sh

Windows用户请参阅文档


创建Meteor应用

创建Meteor应用很容易。安装之后,运行create命令即可。

meteor create epoll

这将创建epoll目录,该目录下有一些模板文件。项目结构如下所示:

image.png

让我们解释下这个结构:

  1. meteor文件夹下保存meteor特定的文件。.gitignore忽略存储MongoDB数据库文件和应用文件的local文件夹。packages指明本应用所需的包。你可以把它们看成是npm包。Meteor以包的形式提供功能。本文中会使用一些包。release保存了meteor版本。本文使用的版本是0.6.6.3
  2. epoll.css决定应用的CSS样式。
  3. epoll.html是应用的HTML标记。目前meteor只支持handlebars模板引擎,不过未来可能支持其他模板引擎
  4. epoll.js是meteor应用的核心。epoll.js同时部署在服务器段和客户端。这允许开发者一次编写、两端使用。meteor创建的epoll.js模板如下所示:

if (Meteor.isClient) {

 Template.hello.greeting = function () {

   return "Welcome to epoll.";

 };

 Template.hello.events({

   'click input' : function () {

     // template data, if any, is available in 'this'

     if (typeof console !== 'undefined')

       console.log("You pressed the button");

   }

 });

}

if (Meteor.isServer) {

 Meteor.startup(function () {

   // code to run on server at startup

 });

}

Meteor.isServerMeteor.isClient区分了服务器端和客户端的代码。

meteor命令可以运行应用:

cd epoll

meteor

可以通过 http://localhost:3000 访问应用。点击按钮后,在chrome developer tools中你可以看到You pressed the button.信息。

image.png

修改epoll.js的欢迎部分:

Template.hello.greeting = function () {

   return "The Missing Meteor Tutorial!!!";

 };

变动会自动应用,页面也会自动刷新。

image.png

MongoDB在哪?

前面提到Meteor使用MongoDB来存储数据。当我们安装meteor的时候,它同时会下载最新版的MongoDB。我们可以看到,MongoDB安装在<user.home>/.meteor目录。使用ps -ef可以找到MongoDB的安装位置。

; ps -ef|grep mongo

501  1704  1687   0  2:22PM ttys001    0:09.28 /Users/shekhargulati/.meteor/tools/0b2f28e18b/mongodb/bin/mongod --bind_ip 127.0.0.1 --smallfiles --nohttpinterface --port 3002 --dbpath /Users/shekhargulati/day15/epoll/.meteor/local/db

在我的机子上,MongoDB运行于3002端口,以避免和其他默认运行于27017端口的MongoDB冲突。


智能的Meteor包管理

前面提到Meteor以包的形式实现功能。这些包在浏览器和服务器上都能使用。运行以下命令可以得知Meteor支持的所有包:

meteor list

使用meteor addmeteor remove命令来添加删除包。


添加Twitter Bootstrap包

我们将使用Twitter Bootstrap作为用户界面的风格。

meteor add bootstrap

注意,Meteor包不一定是最新版。


添加Twitter授权包

在我们的应用中,用户需要首先通过Twitter授权才能投票或添加问题。Meteor提供了accounts-ui包,可以为我们的应用添加登录组件:

meteor add accounts-ui

然后我们添加授权提供者。在这个应用中,我们使用Twitter,不过我们其实也可以使用facebook、github、google、weibo或meetup。

meteor add accounts-twitter

添加包之后,我们需要更新下epoll.html,添加Twitter登录按钮:

<head>

 <title>Epoll : Share your opinion online, anywhere, anytime</title>

</head>

<body>

   <divclass="navbar navbar-static-top navbar-inverse">

     <divclass="navbar-inner">

       <divclass="container">

         <aclass="brand"href="/">Epoll</a>

         <ulclass="nav pull-right">

           <li>

             {{loginButtons}}

           </li>

         </ul>

       </div>

     </div>

</div>

   <divclass="container"id="main">

       {{> banner}}

   </div>

</body>

<templatename="banner">

   <divclass="container">

       <divclass="row">

           <divclass="span6">

               <divclass="well">

                   <h4>Sign in using Twitter to submit new questions or to vote on existing questions.</h4>

                   {{loginButtons}}

               </div>

           </div>

       </div>

   </div>

</template>

然后调整一下样式,增加下面的代码到epoll.css

/* CSS declarations go here */

.login-display-name{color: white }

.login-button{background-color: white}

#main {

   padding-top:20px;

}

应用会自动更新,你会见到这样的页面:

image.png

现在点击Configure Twitter Login,会要求我们输入 twitter 应用的相关信息:

image.png

按照提示配置之后,我们可以使用twitter登录了。

image.png

授权之后我们可以登录应用。使用完毕之后,我们可以登出。

image.png

MongoDB会在用户集合内创建新用户。我们可以使用mongo命令连接数据库查看:

; ~/.meteor/tools/0b2f28e18b/mongodb/bin/mongo --port 3002

MongoDB shell version: 2.4.6

connecting to: 127.0.0.1:3002/test

> show dbs

local   0.03125GB

meteor  0.0625GB

> use meteor

switched to db meteor

> show collections

meteor_accounts_loginServiceConfiguration

system.indexes

users

> db.meteor_accounts_loginServiceConfiguration.find()

{ "service" : "twitter", "consumerKey" : "xxx", "secret" : "xxx", "_id" : "xxx" }

>

>

> db.users.find().pretty()

{

   "createdAt" : ISODate("2013-11-11T18:03:23.488Z"),

   "_id" : "xx",

   "services" : {

       "twitter" : {

           "id" : "66993334",

           "screenName" : "shekhargulati",

           "accessToken" : "xxx-xxx",

           "accessTokenSecret" : "xxx",

           "profile_image_url" : "http://pbs.twimg.com/profile_images/378800000254412405/e4adcf8fb7800c3e5f8141c561cb57e4_normal.jpeg",

           "profile_image_url_https" : "https://pbs.twimg.com/profile_images/378800000254412405/e4adcf8fb7800c3e5f8141c561cb57e4_normal.jpeg",

           "lang" : "en"

       },

       "resume" : {

           "loginTokens" : [

               {

                   "token" : "xxx",

                   "when" : ISODate("2013-11-11T18:03:23.489Z")

               }

           ]

       }

   },

   "profile" : {

       "name" : "Shekhar Gulati"

   }

}

>

定义应用层次

Meteor创建的模板应用有一个问题,客户端和服务器段的epoll.js代码是一样的。任何人的都可以使用浏览器的开发工具查看epoll.js

如果我们不想将服务器端的特有代码发送到客户端,我们可以使用clientserver目录来分隔代码。

cd epoll

mkdir client server

在两个目录下分别创建epollclient.jsepollserver.js文件。

client/epollclient.js内存放客户端代码:

Template.hello.greeting = function () {

   return "The Missing Meteor Tutorial!!!";

};

Template.hello.events({

   'click input' : function () {

     // template data, if any, is available in 'this'

     if (typeof console !== 'undefined')

       console.log("You pressed the button");

   }

});

服务器端代码存放在server/epollserver.js

Meteor.startup(function () {

   // code to run on server at startup

});

```

然后删除`epoll.js`:

```sh

rm -f epoll.js

移除insecure

每一个Meteor应用预装了insecure包。这个应用让用户端可以在数据库上实施一切操作。对于原型开发这很有用,但是通常不适合生产环境。

meteor remove insecure

发布问题

现在我们添加一个功能,已登录的用户可以提交新问题。

<head>

 <title>Epoll : Share your opinion online, anywhere, anytime</title>

</head>

<body>

 <divclass="navbar navbar-static-top navbar-inverse">

     <divclass="navbar-inner">

       <divclass="container">

         <aclass="brand"href="/">Epoll</a>

         <ulclass="nav pull-right">

           <li>

             {{loginButtons}}

           </li>

         </ul>

       </div>

     </div>

</div>

 <divclass="container"id="main">

   {{#if currentUser}}

     {{> addquestion}}

   {{/if}}

   {{#unless currentUser}}

     {{> banner}}

   {{/unless}}

   </div>

</body>

<templatename="banner">

 <divclass="container">

   <divclass="row">

       <divclass="span6">

           <divclass="well">

             <h4>Sign in using Twitter to submit new questions or to vote on existing questions.</h4>

             {{loginButtons}}

           </div>

     </div>

   </div>

 </div>

</template>

<templatename="addquestion">

 <textarearows="3"class="input-xxlarge"name="questionText"id="questionText"placeholder="Add Your Question"></textarea>

 <br/>

 <inputtype="button"class="btn-info add-question"value="Add Question"/>

</template>

仅当用户登录的时候才会渲染addQuestion模板。如果用户登出,则不会见到添加新问题的文本框。

我们需要同时更新客户端和服务器端的代码以便实现这一功能。

client/epollclient.js中加入:

Template.addquestion.events({

   'click input.add-question' : function(event){

       event.preventDefault();

       var questionText = document.getElementById("questionText").value;

       Meteor.call("addQuestion",questionText,function(error , questionId){

         console.log('added question with Id .. '+questionId);

       });

       document.getElementById("questionText").value = "";

   }

});

以上代码中:

  1. 我们首先将点击input事件绑定到add-question类。
  2. 接着我们阻止默认的点击事件,从DOM中获取问题文本。
  3. 然后我们调用Meteor服务器的方法addQuestion。由服务器负责插入、更新、删除数据等有风险的操作。客户端看不到实现,也无法私自修改数据。

现在我们需要修改server/epollserver.js。我们首先定义一个名为Questions的新集合。然后我们会操作这个集合。Meteor使用minimongo作为API接口。参阅Meteor.Collection.documentation查看minimongo支持的所有操作。

Questions = new Meteor.Collection("questions");

Meteor.startup(function () {

   // code to run on server at startup

});

Meteor.methods({

 addQuestion : function(questionText){

   console.log('Adding Question');

   var questionId = Questions.insert({

         'questionText' : questionText,

         'submittedOn': new Date(),

         'submittedBy' : Meteor.userId()

     });

   return questionId;

 }

});

现在访问我们的应用然后提交一个新问题:

image.png

查看下MongoDB中的数据

> db.questions.find().pretty()

{

   "questionText" : "Is Sachin Tendulkar the greatest batsman of all time?",

   "submittedOn" : ISODate("2013-11-11T18:23:02.541Z"),

   "submittedBy" : "Jnu6oXoAZ2um57rZ8",

   "_id" : "nhqvgDcZqgZgLdDB7"

}

问题列表

我们接下来要实现的功能是问题列表。用户不需登录,就可以看到所有问题的列表。

main div中加入:

{{> questions}}

然后添加问题模板:

<templatename="questions">

   <h2>All Questions</h2>

   {{#each items}}

       {{> question}}

    {{/each}}

</template>

<templatename="question">

   <div>

       <pclass="lead">

           {{questionText}}

           <aclass="btn btn-small btn-success yes {{#unless currentUser}}disabled{{/unless}}" href="#"><iclass="icon-thumbs-up"></i> Yes {{yes}}</a>

           <aclass="btn btn-small btn-danger no {{#unless currentUser}}disabled{{/unless}}" href="#"><iclass="icon-thumbs-down"></i> No {{no}}</a>

       </p>

   </div>

</template>

注意我们使用了unless来确保用户未登录的情况下应用disabled css。

为了获取所有问题,我们需要在客户端使用Question集合来获取所有文本。在client/epollclient.js添加如下代码:

Questions = new Meteor.Collection("questions");

Template.questions.items = function(){

   return Questions.find({},{sort:{'submittedOn':-1}});

};

实现投票功能

最后我们需要实现投票功能。我们上面已经在html文件中加入了相关的模板代码,下面我们在client/epollclient.js加入如下代码:

Template.question.events({

   'click': function () {

       Session.set("selected_question", this._id);

   },

   'click a.yes' : function (event) {

     event.preventDefault();

     if(Meteor.userId()){

       var questionId = Session.get('selected_question');

       console.log('updating yes count for questionId '+questionId);

       Meteor.call("incrementYesVotes",questionId);

     }

   },

   'click a.no': function(){

     event.preventDefault();

     if(Meteor.userId()){

       var questionId = Session.get('selected_question');

       console.log('updating no count for questionId '+questionId);

       Meteor.call("incrementNoVotes",questionId);

     }

   }

});

上面的代码实现了:

  1. 绑定点击事件到问题模板。点击任意问题的时,在session中设置questionId。session提供了一个客户端的全局对象,你可以在里面存储任意的键值对。
  2. 当用户点击Yes按钮时,我们会从session中取得选中的questionId,然后在服务器端调用incrementYesVotes方法。我们使用Meteor.userId()来确保用户已经登录了。
  3. 当用户点击No按钮时,我们在服务器端调用incrementNoVotes函数。

最后我们在server/epollserver.js加入incrementYesVotesincrementNoVotes函数。我们使用Meteor的集合更新功能来增加计数器。

incrementYesVotes : function(questionId){

   console.log(questionId);

   Questions.update(questionId,{$inc : {'yes':1}});

 },

incrementNoVotes : function(questionId){

   console.log(questionId);

   Questions.update(questionId,{$inc : {'no':1}});

}

这样每次用户点击yes或no按钮之后,计数器会更新。你可以访问 http://localhost:3000 试验一番。

部署Meteor应用

部署Meteor应用有很多种方法。我们可以在Meteor提供的测试服务器上部署,也可以部署到OpenShift。

如果你打算部署到OpenShift上,请参阅Ryan这篇博客

运行以下命令可以部署到Meteor测试服务器:

meteor deploy epoll

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
23天前
|
SQL 缓存 搜索推荐
后端技术在现代Web开发中的应用与挑战
本文将深入探讨后端技术在现代Web开发中的重要性,涵盖从基础架构到性能优化的多个方面。通过分析当前主流后端技术的优缺点,并提供一些实用的解决方案和建议,帮助开发者更好地应对日常开发中的挑战。
36 1
|
1天前
|
缓存 前端开发 JavaScript
构建高性能Web应用:优化前端性能的策略
构建高性能Web应用:优化前端性能的策略
|
12天前
|
Web App开发 JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的深度整合
【9月更文挑战第28天】在现代Web开发领域,Node.js和Express框架的结合已成为打造高性能、易扩展应用的黄金组合。本文将深入探讨如何利用这一技术栈优化Web应用架构,提供具体实践指导,并分析其性能提升的内在机制。通过代码示例,我们将展示从基础搭建到高级功能的实现过程,旨在为开发者提供一条清晰的学习路径,以实现技术升级和项目效率的双重提升。
26 3
ly~
|
14天前
|
存储 监控 小程序
除了 Web 开发,PHP 还可以应用于哪些领域?
PHP 在 Web 开发之外还有多个应用场景:1)命令行脚本,如批量处理文件、数据库管理及系统监控;2)利用 PHP-GTK 等工具开发桌面应用,满足特定业务需求;3)结合微信云开发功能支持微信小程序后端,处理数据存储与用户认证;4)为小型游戏或特定类型游戏开发游戏服务器逻辑;5)在物联网领域作为后端语言处理设备数据交互与分析。
ly~
30 4
|
15天前
|
JavaScript 前端开发 UED
WebSocket在Python Web开发中的革新应用:解锁实时通信的新可能
在快速发展的Web应用领域中,实时通信已成为许多现代应用不可或缺的功能。传统的HTTP请求/响应模式在处理实时数据时显得力不从心,而WebSocket技术的出现,为Python Web开发带来了革命性的变化,它允许服务器与客户端之间建立持久的连接,从而实现了数据的即时传输与交换。本文将通过问题解答的形式,深入探讨WebSocket在Python Web开发中的革新应用及其实现方法。
28 3
|
14天前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
13 1
|
18天前
|
中间件 API 开发者
深入理解Python Web框架:中间件的工作原理与应用策略
在Python Web开发中,中间件位于请求处理的关键位置,提供强大的扩展能力。本文通过问答形式,探讨中间件的工作原理、应用场景及实践策略,并以Flask和Django为例展示具体实现。中间件可以在请求到达视图前或响应返回后执行代码,实现日志记录、权限验证等功能。Flask通过装饰器模拟中间件行为,而Django则提供官方中间件系统,允许在不同阶段扩展功能。合理制定中间件策略能显著提升应用的灵活性和可扩展性。
17 4
|
1天前
|
存储 缓存 NoSQL
构建高性能Web应用:缓存的重要性及其实现
构建高性能Web应用:缓存的重要性及其实现
|
2天前
|
JSON API 开发者
深入解析Python网络编程与Web开发:urllib、requests和http模块的功能、用法及在构建现代网络应用中的关键作用
深入解析Python网络编程与Web开发:urllib、requests和http模块的功能、用法及在构建现代网络应用中的关键作用
6 0
|
12天前
|
JSON JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的完美结合
【9月更文挑战第28天】在现代Web开发中,Node.js和Express框架的结合为创建高性能、易扩展的应用提供了强有力的支持。本文将深入探讨如何利用这两种技术构建一个简单但功能强大的Web服务,同时提供代码示例以加深理解。