Meteor学习笔记

Meteor是一个基于Nodejs+Websocket+MongoDB的Web应用程序开发平台。
Metror的七个特性
1.只有数据:不在网络上传输HTML,只传输数据并让客户端决定如何渲染
2.一种语言:前后端接口统一使用js
3.无处不在的数据库:客服端,服务器使用相同,透明的API访问数据库
4.延迟补偿:客户端上使用预读和模式模拟技术,使它看起来与数据库的连接是零延迟的
5.完整的响应式:默认实时模式,从数据库到模板的所有层面上,都要使事件驱动的接口有效
6.包容一切:开源的,能与现有的工具和框架整合
7.简单等于生产力

Meteor 1.1开始,支持 Windows/MongoDB 3.0

我们先以win7下的meteor安装为例
安装器下载地址为:
https://install.meteor.com/windows
点击打开之后会自动下载安装,时间有点长,之后需要注册Meteor开发者账号,可以跳过


这样就安装成功了

通过在命令行输入

meteor help

可以查看所有的Meteor指令

下面我们先来创建一个meteor项目

meteor create mypro


之后根据提示输入下列指令来启动meteor

cd mypro
meteor

meteor会先启动proxy,再启动mongoDB,最后启动应用程序

之后在浏览器输入http://localhost:3000/就可以访问meteor应用了

虽然Meteor是基于nodejs的,但是nodejs的包不能直接在Meteor中使用,在Meteor目录下运行如下指令可以查看当前可用的包

meteor list

下面我们通过实例来分析meteor项目的结构,通过
https://github.com/meteor/meteor
下载meteor的源码,在examples里我们进入leaderboard目录,执行

meteor

在浏览器中打开这个项目


这是一个简单的meteor应用,点击名字,下面会出现给这个人加5分的按钮,点击之后会加5分并且自动重新排序
首先,我们看一下leaderboard.html
Meteor默认使用Handelbars模板系统
1.模板的加载

{{> 模板名}}

2.模板的定义

<template name="模板名">...</template>

3.遍历数据集合

{{#each 集合名}}...{{/each}}

4.判断

{{#if 条件为真}}...{{/if}}.....{{#unless 条件为假}}...{{/unless}}
{{#if 条件为真}}...{{/else}}...{{/if}}

Meteor的数据操作共享和延迟补偿技术说明
每个meteor客户端包含一个内存数据库缓存Minimongo,在操作客户端的数据变更时,其实是操作的Minimongo,同时客户端会向服务器发送一个变更请求,Meteor使用DDP(Distributed Data Protocol 分布式数据协议)来传递数据。
Meteor有个机制,客户端向服务器端发起一个写操作时,会立即更新本地缓存而不必等待服务器的响应,如果服务器拒绝变更请求,Meteor会修正客户端缓存,这种技术就叫“延迟补偿”,客户端持有最新的数据,同时服务器对于变更请求有最终的定夺的权利。
在客户端修改数据库确实方便,不过会有安全性问题,所以一般发布到生产环境会移除Meteor的autopublish和insecure包,它们能够模拟每个客户端对服务器上的数据拥有完全读/写权限的效果。

下面来看一下核心代码leaderboard.js
1._id规则

Players = new Mongo.Collection("players");

Meteor在MongoDB中生成的_id是17位的简化id,如果要用mongodb默认的24位id则可以通过

new Meteor.Collection(name,{idGeneration:'MONGO'});

也可以通过下列方法创建ObjectID

new Meteor.Collection.ObjectID(hexString)

2.客户端服务器运行不同的代码
因为leaderboard.js是客户端和服务器都加载的,所以如果要判断是客户端的操作还是服务器端的操作需要通过

if(Meteor.isClient){
    //客户端执行的代码
}
if(Meteor.isServer){
    //服务器端执行的代码
}

目录说明:
服务器端

JavaScript/所有js
private/所有js
server/所有js

客户端

client/所有js

公用资源

public/资源文件

其他目录下的文件会被客户端和服务器端两者加载

3.Meteor可以使用的数据库操作API

find,findOne,insert,update,upsert,remove,allow,deny

4.Session
Session只能用于客户端

Session.set(key,value);  //设置key的value
Session.setDefault(key,value); //设置key默认的value
Session.get(key) //获取key的value
Session.equals(key,value) //判断key的值是否等于value

5.startup
Meteor.startup()是Meteor提供的核心API,可以用在客户端和服务器端,当用在服务器端时,会在服务器进程启动完毕后立即执行,客户端时,会在DOM准备就绪时立即执行。
通常,Meteor.startup()用来做一些初始化的事情,比如往数据库里插入文档或从数据库读取文档并进行展示。

Meteor信奉响应式编程的理念
我们可以在控制台直接给Session赋值,就可以在页面上直接看到效果


能够响应式计算的有

Templates
Meteor.render,Meteor.renderList
Deps.autorun

能够触发变化的响应式数据源有

Session内的变量
Collections内的数据库查询
Meteor.status
Meteor.subscribe内的ready()方法
Meteor.user
Meteor.userId
Meteor.loggingIn

insecure包
模拟每个客户端对服务器上的数据库拥有完全读/写权限的效果,通常生产环境需要移除这个包

meteor remove insecure

这时如果给玩家加5分,会发现玩家排名和分数上移后又瞬间回到原样了,控制台显示update failed: Access denied


这就是延迟补偿,去掉了insecure包,需要修改代码
方法一
在服务器端执行的代码增加

Players.allow({
    update: function(userId,doc,fieldNames,modifier){
        return true;
    }
});

如果返回true,允许客户端执行update操作,false时拒绝,也可以使用collection.deny方法来拒绝客户端修改数据库的请求
如果只允许得分大于30分的进行修改

Players.allow({
    update: function(userId,doc,fieldNames,modifier){
        return doc.score >= 30 ? true : false;
    }
});

只有在客户端试图修改数据时才会触发,而服务器端不受这个限制

方法二.
通过Meteor.methods和Meteor.call的组合来实现客户端修改数据

//server
Meteor.methods({
    add5:function(selectedPlayer){
      Players.update(selectedPlayer,{$inc:{score:5}});
    }
});
//client
Template.leaderboard.events({
    'click .inc': function () {
      Meteor.call('add5',Session.get("selectedPlayer"));
    }
});

autopublish包
使用autopublish包,Meteor会客户端Minimongo中的内容和服务器端的MongoDB同步(除了users集合部分的内容和索引)通常生产环境也需要移除这个包

meter remove autopublish

这时候客户端和服务器端的数据库就不同步了,需要修改代码

//server
Meteor.publish("leaderboard",function(){
    return Players.find();
});
//client
Meteor.subscribe("leaderboard");

这样就可以了,假如我们有多个集合,可以选择性地从服务器端发布,然后从客户端订阅
Meteor.publish只能用于服务器端
Meteor.subscribe只能用于客户端

这里要说一下,leaderboard.js所有的修改之后Meteor服务器会自动重启应用,这样就能看到最新的修改结果,还是很方便的

Meteor文件的加载顺序

lib目录下的文件先加载
main.*的文件最后加载
子目录的文件在根目录的文件之前加载
同目录的文件按文件名的字母顺序加载

下面我们以搭建一个微博为例子来讲解需要注意的地方

我们采用的meteor组件是jquery+bootstrap+backbone+accounts-password
Meteor添加包
Meteor添加bootstrap依赖包

meteor add bootstrap

无须在<head>中引入bootstrap即可使用它,也无需引用jquery,jquery已经内置在Meteor的核心包中

在Meteor的页面里必须包含head,body标签,不然会报错,在template模板页面里不需要

我们不用在html页面里引入只含有template标签的模板页面,因为Meteor会将每个模板转化成js函数并加载它们

添加backbone包来实现路由功能

meteor add backbone

backbone的详细使用可以参考
http://backbonejs.org/
这里需要注意meteor session的用法
session只能用于客户端,当session值改变时,如果需要更新页面,需要在helpers里返回

Session.setDefault("currentUrl",{index:"active",reg:""});
var urlRouter = Backbone.Router.extend({
    routes:{
        "":"index",
        "reg":"reg"
    },
    index:function(){
        console.log("index");
        Session.set("currentUrl",{index:"active",reg:""});

    },
    reg:function(){
        console.log("reg");
        Session.set("currentUrl",{index:"",reg:"active"});
    },
    redirect:function(url){
        this.navigate(url,true);
    }
});

Router = new urlRouter;

Template.container.helpers({
    currentUrl: function () {
        return Session.get('currentUrl');
    }
});

Meteor.startup(function(){
    Backbone.history.start({pushState:true});
});

这样在html里才能访问到currentUrl

{{#if currentUrl.index}}
    {{> index}}
{{/if}}
{{#if currentUrl.reg}}
    {{> reg}}
{{/if}}

还有一种方法是直接通过模板名下的变量名来返回,但是浏览器会警告

Template.info.info = function(){
    return Session.get("info");
}

添加accounts-password包构建用户认证系统,他可以帮助你快速的完成用户的注册,登陆

meteor add accounts-password

Template.reg.events({
    'click #submit': function(e){
        e.preventDefault();
        Accounts.createUser({username:$("#username").val(),password:$("#password").val()});
    }
});

这样就会在数据库中保存用户名和密码,密码是经过SRP加密的


{{currentUser}}存储了当前在线用户的信息(其实是调用了Meteor.user()),可以用来判断用户是否在线,不在线返回null

{{#if currentUser}}
    <a href="/logout" class="btn btn-primary-large">退出</a>
{{else}}
    <a href="/reg" class="btn btn-primary-large">注册</a>
{{/if}}

Meteor.userId()可以用来判断用户是否在线,存储当前在线用户的_id,不在线返回null

logout:function(){
    if(Meteor.userId()){
        Meteor.logout();
        this.navigate("/",true);
        Session.set("info",{success:"退出成功",error:""});
    }else{
        this.navigate("/",true);
        Session.set("info",{success:"",error:"用户不在线"});
    }
},

Meteor.loginWithPassword可以实现用户登录功能

Meteor.loginWithPassword($("#username").val(),$("#password").val(),function(err){
    if(err){
        Session.set("info",{success:"",error:err.reason});
    }else{
        Session.set("info",{success:"登陆成功",error:""});
        Router.redirect("/");
    }
});

如果密码错误,err.reason会返回


如果用户不存在,err.reason返回


这些认证判断都是Meteor为我们做好的

Meteor对html标签的闭合要求是很高的,如果有没有闭合的标签,就会提示出错,还是很智能的

如果我们在客户端的js文件里定义了数据集

Posts = new Meteor.Collection("posts");

之后直接调用insert方法会报错


因为数据集在服务器端没有定义,我们需要的服务器端的js文件里也增加一句,然后可以通过allow来控制谁可以操作数据

Posts = new Meteor.Collection("posts");
Posts.allow({
    insert:function(userId,doc){
        return userId && (doc.user._id === userId);
    }
});

添加markdown支持
Meteor提供了一个showdown包,只需将Markdown文本添加到{{#markdown}}...{{/markdown}}标签内

meteor add showdown

该Meteor微博的完整源码我已上传到Github上
https://github.com/ccfromstar/meteor_weibo

最后说一下Meteor的部署
有两种方法
1.部署到Meteor提供的免费服务器上

meteor deploy weibocc.meteor.com


删除站点重新部署,如果想清空数据库

meteor deploy weibocc.meteor.com -D

如果希望是自己私有的,可以设置一个密码,这样下次更新代码时候就需要密码才能更新

meteor deploy weibocc.meteor.com -P

2.将应用打包部署到自己的服务器上

meteor bundle weibocc.tgz

要运行这个应用,需要Nodejs和MongoDB

PORT=3000 MONGO_URL=mongodb://localhost:27017/weibo node bundle/main.js

这里需要注意的是我们必须重新编译fibers包

cd bundle/programs/server/node_modules
rm -r fibers
npm install fibers@1.0.1

这样就可以了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 什么是Meteor? Meteor是高性能Javascript全端开发框架优势: Javascript 全平台单一...
    KeKeMars阅读 3,856评论 2 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • 引言 想知道这个新奇又好玩的东西---Meteor是如何工作的?那就太好了,你来对地方了. 我会向你展示一个Met...
    XguoX阅读 7,403评论 0 16
  • 微笑是一种国际礼仪,它体现了人类最真诚的相互尊重与亲近。微笑也是我们最基本的礼仪,它应伴随着我们度过工作和生活中每...
    爱粉阅读 640评论 4 9