node.js应用--转载

最近,在向大学生们介绍 HTML5 的时候,我想要对他们进行问卷调查,并向他们显示实时更新的投票结果。鉴于此目的,我决定快速构建一个用于此目的的问卷调查应用程序。我想要一个简单的架构,不需要太多不同的语言和框架。因此,我决定对所有一切都使用 JavaScript — 对服务器端使用 Node.js 和 Express,对数据库使用 MongoDB,对前端用户界面使用 AngularJS。

这个 MEAN 堆栈(Mongo、Express、Angular 和 Node)只需要一天即可完成,远比 Web 应用程序开发和部署所用的 LAMP 堆栈(Linux、Apache、MySQL 和 PHP)简单得多。

运行该应用程序

在 JazzHub 上获取源代码

我选择使用 JazzHub 来管理我的项目的源代码。它不仅为我的代码提供了一个完整的版本控制系统,还为在云中编辑代码提供了一个在线 IDE,以及用于项目管理的敏捷特性。JazzHub 很容易与 Eclipse 相集成,Eclipse 还提供了一些插件,支持对平台( 比如 BlueMix 或 Cloud Foundry)的一键式部署。

构建该应用程序的先决条件

第 1 步. 构建一个基础 Express 后台

在 Eclipse 中,切换到 Node 透视图,并创建一个新的 Node Express 项目。如果您创建了一个 JazzHub 项目,请像我所做的那样,使用相同的名称为您的 Node Express 项目命名。选择使用 Jade 作为模板引擎。Eclipse 会自动下载所需的 npm 模块,以便创建一个简单 Express 应用程序。

运行这个 Express 应用程序

在 Project Explorer 中,找到位于您项目的根目录中的 app.js,右键单击并选择 Run As > Node Application。这将启动一个 Web 服务器并将应用程序部署到该服务器。 接下来,打开浏览器并导航到 http://localhost:3000

图 1. Starter Express 应用程序

配置基础前端

这个问卷调查应用程序对常见用户界面和布局使用了 Bootstrap 框架。现在,让我们对 Express 应用程序做一些改动来反映这一点。首先,打开 routes/index.js,将标题属性更改为 Polls

清单 1. routes/index.js
        exports.index = function(req, res){
             res.render(‘index‘, { title: ‘Polls‘ });
         };

接着,更改 views/index.jade 模板以包含 Bootstrap。Jade 是一种速记模板语言,可编译成 HTML。它使用缩进消除了对结束标签的需求,极大地缩小了模板的大小。您只需要使用 Jade 作为主页面布局即可。在下一步中,还可以使用 Angular 局部模板向这个页面添加功能。

清单 2. views/index.jade
        doctype 5
        html(lang=‘en‘)
          head
            meta(charset=‘utf-8‘)
            meta(name=‘viewport‘, content=‘width=device-width,
	initial-scale=1, user-scalable=no‘)
            title= title
            link(rel=‘stylesheet‘, href=‘//netdna.bootstrapcdn.com/bootstrap/3.0.1/
	css/bootstrap.min.css‘)
            link(rel=‘stylesheet‘, href=‘/stylesheets/style.css‘)
          body
            nav.navbar.navbar-inverse.navbar-fixed-top(role=‘navigation‘)
              div.navbar-header
                a.navbar-brand(href=‘#/polls‘)= title
            div.container
              div

想要查看对您的应用程序所做的更改,请结束 Eclipse 中的 Web 服务器进程,再次运行 app.js 文件:

图 2. 问卷调查应用程序样板文件

注意:在使用 Jade 模板时,注意适当缩进您的代码,否则您会遇到麻烦。另外,还要避免使用混合缩进样式,如果您尝试这样做,Jade 将会报错。

第 2 步. 使用 AngularJS 提供前端用户体验

如果要使用 Angular,首先需要在您的 HTML 页面中包含它,还需要在 HTML 页面中添加一些指令。在 views/index.jade 模板中,对 html 元素进行如下更改:
html(lang=‘en‘, ng-app=‘polls‘)

在该文件的标头中添加以下脚本元素: :

清单 3. 将脚本元素加载到 Angular 和 Angular Resource 模板
        script(src=‘//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js‘)
        script(src=‘//ajax.googleapis.com/ajax/libs/angularjs/1.0.8
/angular-resource.min.js‘)

接下来,更改模板中的 body 元素,添加一个 ng-controller 属性(稍后使用该属性将用户界面绑定到控制器逻辑代码中):
body(ng-controller=‘PollListCtrl‘)

最后,更改模板中的最后一个 div 元素,以便包含一个 ng-view 属性: div(ng-view)

构建 Angular 模块

Angular 中令人影响较为深刻的特性就是数据绑定,在后台模型发生改变时,该功能会自动更新您的视图。这极大地减少了需要编写的 JavaScript 的数量,因为它对凌乱的 DOM 操作任务进行了抽象。

在默认情况下,Express 发布了静态资源,比如 JavaScript 源文件、CSS 样式表以及位于您项目的公共目录中的图像。在公共目录中,创建一个名为 javascripts 的新的子目录。在这个子目录中,创建一个名为 app.js 的文件。该文件将包含用于应用程序的 Angular 模块,而且还定义了用于用户界面的路由和模板:

清单 4. public/javascripts/app.js
        angular.module(‘polls‘, [])
          .config([‘$routeProvider‘, function($routeProvider) {
            $routeProvider.
              when(‘/polls‘, { templateUrl: ‘partials/list.html‘, controller:
PollListCtrl }).
              when(‘/poll/:pollId‘, { templateUrl: ‘partials/item.html‘, controller:
PollItemCtrl }).
              when(‘/new‘, { templateUrl: ‘partials/new.html‘, controller:
PollNewCtrl }).
              otherwise({ redirectTo: ‘/polls‘ });
          }]);

Angular 控制器定义了应用程序的范围,为要绑定的视图提供数据和方法。

清单 5. public/javascript/controllers.js
        // Managing the poll list
        function PollListCtrl($scope) {
          $scope.polls = [];
        }
        // Voting / viewing poll results
        function PollItemCtrl($scope, $routeParams) {
          $scope.poll = {};
          $scope.vote = function() {};
        }
        // Creating a new poll
        function PollNewCtrl($scope) {
          $scope.poll = {
            question: ‘‘,
            choices: [{ text: ‘‘ }, { text: ‘‘ }, { text: ‘‘ }]
          };
          $scope.addChoice = function() {
            $scope.poll.choices.push({ text: ‘‘ });
          };
          $scope.createPoll = function() {};
        }

创建局部 HTML 和模板

为了呈现来自控制器的数据,Angular 使用了局部 HTML 模板,该模板允许您使用占位符和表达式来包含数据和执行操作,比如条件和迭代操作。在公共目录中,创建一个名为 partials 的新的子目录。我们将为我们的应用程序创建 3 个局部模板,第一个局部模板将会展示可用投票的列表,我们将使用 Angular 通过一个搜索字段轻松过滤该列表。

清单 6. public/partials/list.html
        <div class="page-header">
          <h1>Poll List</h1>
        </div>
        <div class="row">
          <div class="col-xs-5">
            <a href="#/new" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> New Poll</a>
          </div>
          <div class="col-xs-7">
            <input type="text" class="form-control" ng-model="query"
placeholder="Search for a poll">
          </div>
        </div>
        <div class="row"><div class="col-xs-12">
<hr></div></div>
        <div class="row" ng-switch on="polls.length">
          <ul ng-switch-when="0">
            <li><em>No polls in database. Would you like to
 <a href="#/new">create one</a>?</li>
          </ul>
          <ul ng-switch-default>
            <li ng-repeat="poll in polls | filter:query">
              <a href="#/poll/{{poll._id}}">{{poll.question}}</a>
            </li>
          </ul>
        </div>
        <p>&nbsp;</p>

第二个局部模板允许用户查看投票。它使用 Angular 切换指令来确定用户是否已投票,并根据这些判断,显示一个就此次问卷调查进行投票的表格,或者一个包含显示问卷调查结果的图表。

清单 7. public/partials/item.html
        <div class="page-header">
          <h1>View Poll</h1>
        </div>
        <div class="well well-lg">
          <strong>Question</strong><br>{{poll.question}}
        </div>
        <div ng-hide="poll.userVoted">
          <p class="lead">Please select one of the following options.</p>
          <form role="form" ng-submit="vote()">
            <div ng-repeat="choice in poll.choices" class="radio">
              <label>
                <input type="radio" name="choice" ng-model="poll.userVote"
	value="{{choice._id}}">
                {{choice.text}}
              </label>
            </div>
            <p><hr></p>
            <div class="row">
              <div class="col-xs-6">
                <a href="#/polls" class="btn btn-default" role="button"><span
class="glyphicon glyphicon-arrow-left"></span> Back to Poll
              </div>
              <div class="col-xs-6">
                <button class="btn btn-primary pull-right" type="submit">
	Vote &raquo;</button>
              </div>
            </div>
          </form>
        </div>
        <div ng-show="poll.userVoted">
          <table class="result-table">
            <tbody>
              <tr ng-repeat="choice in poll.choices">
                <td>{{choice.text}}</td>
                <td>
                  <table style="width: {{choice.votes.length
	/poll.totalVotes*100}}%;">
                    <tr><td>{{choice.votes.length}}</td></tr>
                  </table>
                </td>
              </tr>
            </tbody>
          </table>
          <p><em>{{poll.totalVotes}} votes counted so far. <span
ng-show="poll.userChoice">You voted for <strong>{{poll.userChoice.text}}
</strong>.</span></em></p>
          <p><hr></p>
          <p><a href="#/polls" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-arrow-left"></span> Back to
Poll List</a></p>
        </div>
        <p>&nbsp;</p>

第三个也是最后一个局部模板定义了支持用户创建新的问卷调查的表单。它要求用户输入一个问题和三个选项。提供一个按钮,以便允许用户添加额外的选项。稍后,我们将验证用户至少输入了两个选项 — 因为如果没有几个选项,就不能称之为问卷调查。

清单 8. public/partials/new.html
        <div class="page-header">
          <h1>Create New Poll</h1>
        </div>
        <form role="form" ng-submit="createPoll()">
          <div class="form-group">
            <label for="pollQuestion">Question</label>
            <input type="text" ng-model="poll.question" class="form-control"
id="pollQuestion" placeholder="Enter poll question">
          </div>
          <div class="form-group">
            <label>Choices</label>
            <div ng-repeat="choice in poll.choices">
              <input type="text" ng-model="choice.text" class="form-control"
placeholder="Enter choice {{$index+1}} text"><br>
            </div>
          </div>
          <div class="row">
            <div class="col-xs-12">
              <button type="button" class="btn btn-default" ng-click=
"addChoice()"><span class="glyphicon glyphicon-plus">
</span> Add another</button>
            </div>
          </div>
          <p><hr></p>
          <div class="row">
            <div class="col-xs-6">
              <a href="#/polls" class="btn btn-default" role="button">
<span class="glyphicon glyphicon-arrow-left"></span>
Back to Poll List</a>
            </div>
            <div class="col-xs-6">
              <button class="btn btn-primary pull-right" type="submit">
	Create Poll &raquo;</button>
            </div>
          </div>
          <p>&nbsp;</p>
        </form>

最后,为了显示结果,我们需要向 style.css 添加一些 CSS 声明。将该文件的内容替换为以下内容:

清单 9. public/stylesheets/style.css
        body { padding-top: 50px; }
        .result-table {
          margin: 20px 0;
          width: 100%;
          border-collapse: collapse;
        }
        .result-table td { padding: 8px; }
        .result-table > tbody > tr > td:first-child {
          width: 25%;
          max-width: 300px;
          text-align: right;
        }
        .result-table td table {
          background-color: lightblue;
          text-align: right;
        }

此时,如果您运行该应用程序,就会看到一个空的问卷调查列表。如果您试着创建一个新的问卷调查,就能看到此表单并添加更多的选项,但您不能保存该问卷调查。我们将在下一步中详细介绍所有这些内容。


回页首

第 3 步. 使用 Mongoose 在 MongoDB 中存储数据

为了存储数据,该应用程序使用了 MongoDB 驱动程序和 Mongoose npm 模块。它们允许应用程序与 MongoDB 数据库进行通信。要获得这些模块,请打该应用程序根目录中的 package.json 文件,并在依赖关系部分中添加以下这些代码行:。

清单 10. 向依赖关系添加下列代码
        "mongodb": ">= 1.3.19",
        "mongoose": ">= 3.8.0",

保存文件,在 Project Explorer 中右键单击并选择 Run As > npm install。这将安装 npm 模块和其他所有依赖关系。

创建一个 Mongoose 模型

在您应用程序的名为 models 的根目录中创建一个新的子目录,并在这个子目录中创建一个名为 Poll.js 的新文件。在这个文件中,我们定义了我们的 Mongoose 模型,该模型将用于查询数据,并以结构化数据的形式将这些数据保存到 MongoDB 。

清单 11. models/Poll.js
        var mongoose = require(‘mongoose‘);
        var voteSchema = new mongoose.Schema({ ip: ‘String‘ });
        var choiceSchema = new mongoose.Schema({
          text: String,
          votes: [voteSchema]
        });
        exports.PollSchema = new mongoose.Schema({
          question: { type: String, required: true },
          choices: [choiceSchema]
        });

定义数据存储的 API 路由

接下来,在您应用程序的根目录下的 app.js 文件中设置一些路由,以便创建一些 JSON 端点,这些端点可用于根据 Angular 客户端代码来查询和更新 MongoDB。找到 app.get(‘/‘, routes.index) 行,并将下列代码添加到这一行的后面: :

清单 12. 创建 JSON 端点
        app.get(‘/polls/polls‘, routes.list);
        app.get(‘/polls/:id‘, routes.poll);
        app.post(‘/polls‘, routes.create);

现在,您需要实现这些功能。将 routes/index.js 文件的内容替换为下列代码:

清单 13. routes/index.js
        var mongoose = require(‘mongoose‘);
        var db = mongoose.createConnection(‘localhost‘, ‘pollsapp‘);
        var PollSchema = require(‘../models/Poll.js‘).PollSchema;
        var Poll = db.model(‘polls‘, PollSchema);
        exports.index = function(req, res) {
          res.render(‘index‘, {title: ‘Polls‘});
        };
        // JSON API for list of polls
        exports.list = function(req, res) {
          Poll.find({}, ‘question‘, function(error, polls) {
            res.json(polls);
          });
        };
        // JSON API for getting a single poll
        exports.poll = function(req, res) {
          var pollId = req.params.id;
          Poll.findById(pollId, ‘‘, { lean: true }, function(err, poll) {
            if(poll) {
              var userVoted = false,
                  userChoice,
                  totalVotes = 0;
              for(c in poll.choices) {
                var choice = poll.choices[c];
                for(v in choice.votes) {
                  var vote = choice.votes[v];
                  totalVotes++;
                  if(vote.ip === (req.header(‘x-forwarded-for‘) || req.ip)) {
                    userVoted = true;
                    userChoice = { _id: choice._id, text: choice.text };
                  }
                }
              }
              poll.userVoted = userVoted;
              poll.userChoice = userChoice;
              poll.totalVotes = totalVotes;
              res.json(poll);
            } else {
              res.json({error:true});
            }
          });
        };
        // JSON API for creating a new poll
        exports.create = function(req, res) {
          var reqBody = req.body,
              choices = reqBody.choices.filter(function(v) { return v.text != ‘‘; }),
              pollObj = {question: reqBody.question, choices: choices};
          var poll = new Poll(pollObj);
          poll.save(function(err, doc) {
            if(err || !doc) {
              throw ‘Error‘;
            } else {
              res.json(doc);
            }
          });
        };

使用 Angular 服务将数据绑定到前端

此时,设置后台,以便启用查询,并将问卷调查数据保存到数据库,但我们需要在 Angular 中做一些更改,以便让它知道如何与数据库进行通信。使用 Angular 服务很容易完成这项任务,它将与服务器端进行通信的过程包装到了简单的函数调用中:

清单 14. public/javascripts/services.js
        angular.module(‘pollServices‘, [‘ngResource‘]).
          factory(‘Poll‘, function($resource) {
            return $resource(‘polls/:pollId‘, {}, {
              query: { method: ‘GET‘, params: { pollId: ‘polls‘ }, isArray: true }
            })
          });

在创建的这一文件之后,您需要将它包括在您的 index.jade 模板中。在文件标头部分的最后一个脚本元素的下面添加以下这行代码:
script(src=‘/javascripts/services.js‘)

您还需要告诉您的 Angular 应用程序使用这个服务模块。要实现这一点,请打开 public/javascripts/app.js 并将第一行更改为可读,如下所示:
angular.module(‘polls‘, [‘pollServices‘])

最后,更改 Angular 控制器,以便使用该服务在数据库中进行查询和存储问卷调查数据。在 public/javascripts/controllers.js 文件中,将 PollListCtrl 更改如下:。

清单 15. public/javascripts/controller.js
        function PollListCtrl($scope, Poll) {
          $scope.polls = Poll.query();
        }
   ...

更新 PollItemCtrl 函数,以便根据问卷调查的 ID 来查询某个问卷调查:

清单 16. public/javascripts/controller.js (continued)
...
        function PollItemCtrl($scope, $routeParams, Poll) {
          $scope.poll = Poll.get({pollId: $routeParams.pollId});
          $scope.vote = function() {};
        }
 ...

类似地,更改 PollNewCtrl 函数,以便在提交表单时将新调查数据发送到服务器。

清单 17. public/javascripts/controller.js (continued)
...
        function PollNewCtrl($scope, $location, Poll) {
          $scope.poll = {
            question: ‘‘,
            choices: [ { text: ‘‘ }, { text: ‘‘ }, { text: ‘‘ }]
          };
          $scope.addChoice = function() {
            $scope.poll.choices.push({ text: ‘‘ });
          };
          $scope.createPoll = function() {
            var poll = $scope.poll;
            if(poll.question.length > 0) {
              var choiceCount = 0;
              for(var i = 0, ln = poll.choices.length; i < ln; i++) {
                var choice = poll.choices[i];
                if(choice.text.length > 0) {
                  choiceCount++
                }
              }
              if(choiceCount > 1) {
                var newPoll = new Poll(poll);
                newPoll.$save(function(p, resp) {
                  if(!p.error) {
                    $location.path(‘polls‘);
                  } else {
                    alert(‘Could not create poll‘);
                  }
                });
              } else {
                alert(‘You must enter at least two choices‘);
              }
            } else {
              alert(‘You must enter a question‘);
            }
          };
        }

运行应用程序

您已经离成功不远了!此时,应用程序应该允许用户查看和搜索问卷调查数据、创建新的问卷调查并查看单个问卷调查的投票选项。在运行该应用程序之前,请确保您已经本地运行 MongoDB。这通常和打开一个终端或命令提示符以及运行 mongod 命令一样简单。确保在您运行应用程序时终端窗口处于打开状态:

图 3. 查看一个问卷调查的选项

在运行应用程序之后,在您的浏览器中导航到 http://localhost:3000 并创建一些问卷调查。如果您单击一个问卷调查,您就能够看到可用的选项,但是,您无法实际对该问卷调查进行投票,或者暂时看不到问卷调查结果。我们将在下一步和最后一步中对此进行介绍。


回页首

第 4 步. 使用 Socket.io 进行实时投票

Web Sockets 允许服务器端直接与客户端通信以及向客户端发送消息。

剩下的惟一需要构建的特性就是投票功能。该应用程序允许用户进行投票,在他们投票后,会在所有已连接的客户端上实时更新投票结果。使用 socket.io 模块很容易完成这项工作,现在就让我们来实现它吧。

打开您应用程序的根目录中的 package.json 文件,将下列代码添加到依赖关系部分:
"socket.io": "~0.9.16"

保存文件,在 Package Explorer 中右键单击,然后选择 Run As > npm install 来安装 npm 模块。

接下来,打开应用程序根目录中的 app.js 文件, 删除位于文件末尾的 server.listen... 代码块,将其替换为:

清单 18. app.js
...
        var server = http.createServer(app);
        var io = require(‘socket.io‘).listen(server);

        io.sockets.on(‘connection‘, routes.vote);

        server.listen(app.get(‘port‘), function(){
          console.log(‘Express server listening on port ‘ + app.get(‘port‘));
        });

接下来,修改 index.jade 模块以包含 socket.io 客户端库。在运行该应用程序时,该库会自动在指定的位置上变得可用,因此不需要担心自己如何寻找该文件。确保想包含模板中的 angular-resource 库的行的后面包含此文件:
script(src=‘/socket.io/socket.io.js‘)

最后,您需要创建投票功能,以便在用户向 socket.io 发送消息时保存新的投票,并在具有更新结果时将消息发送给所有客户端。将 添加到路由目录中的 index.js 文件的结尾处:

清单 19. routes/index.js
        // Socket API for saving a vote
        exports.vote = function(socket) {
          socket.on(‘send:vote‘, function(data) {
            var ip = socket.handshake.headers[‘x-forwarded-for‘] ||
socket.handshake.address.address;
            Poll.findById(data.poll_id, function(err, poll) {
              var choice = poll.choices.id(data.choice);
              choice.votes.push({ ip: ip });
              poll.save(function(err, doc) {
                var theDoc = {
                  question: doc.question, _id: doc._id, choices: doc.choices,
                  userVoted: false, totalVotes: 0
                };
                for(var i = 0, ln = doc.choices.length; i < ln; i++) {
                  var choice = doc.choices[i];
                  for(var j = 0, jLn = choice.votes.length; j < jLn; j++) {
                    var vote = choice.votes[j];
                    theDoc.totalVotes++;
                    theDoc.ip = ip;
                    if(vote.ip === ip) {
                      theDoc.userVoted = true;
                      theDoc.userChoice = { _id: choice._id, text: choice.text };
                    }
                  }
                }
                socket.emit(‘myvote‘, theDoc);
                socket.broadcast.emit(‘vote‘, theDoc);
              });
            });
          });
        };

注意:如果您想知道为什么应用程序会在常规 API 地址属性的前面查找标头 ‘x-forwarded-for‘,因为这将确保当应用程序被部署到负载平衡环境中时,所使用的是正确的客户端 IP。如果您将该应用程序部署到 BlueMix 或 Cloud Foundry,这对于应用程序是否能正常工作至关重要。

添加一个 Angular 服务将数据发送到 Web 套接字。

Web Sockets 的后端功能现已创建完毕。目前剩下要做的工作是绑定前端,以发送和监听套接字事件。最佳方法是添加一个新的 Angular 服务。使用以下代码替换 public/javascripts 文件夹中的 services.js 文件:

清单 20. public/javascripts/services.js
        angular.module(‘pollServices‘, [‘ngResource‘]).
          factory(‘Poll‘, function($resource) {
            return $resource(‘polls/:pollId‘, {}, {
              query: { method: ‘GET‘, params: { pollId: ‘polls‘ }, isArray: true }
            })
          }).
          factory(‘socket‘, function($rootScope) {
            var socket = io.connect();
            return {
              on: function (eventName, callback) {
                socket.on(eventName, function () {
                  var args = arguments;
                  $rootScope.$apply(function () {
                    callback.apply(socket, args);
                  });
                });
              },
              emit: function (eventName, data, callback) {
                socket.emit(eventName, data, function () {
                  var args = arguments;
                  $rootScope.$apply(function () {
                    if (callback) {
                      callback.apply(socket, args);
                    }
                  });
                })
              }
            };
          });

最后,您需要编辑 PollItemCtrl 控制器,以便它能够监听和发送用于投票的 Web Socket 消息。将原始控制器替换为:

清单 21. public/javascripts/controllers.js
...
        function PollItemCtrl($scope, $routeParams, socket, Poll) {
          $scope.poll = Poll.get({pollId: $routeParams.pollId});
          socket.on(‘myvote‘, function(data) {
            console.dir(data);
            if(data._id === $routeParams.pollId) {
              $scope.poll = data;
            }
          });
          socket.on(‘vote‘, function(data) {
            console.dir(data);
            if(data._id === $routeParams.pollId) {
              $scope.poll.choices = data.choices;
              $scope.poll.totalVotes = data.totalVotes;
            }
          });
          $scope.vote = function() {
            var pollId = $scope.poll._id,
                choiceId = $scope.poll.userVote;
            if(choiceId) {
              var voteObj = { poll_id: pollId, choice: choiceId };
              socket.emit(‘send:vote‘, voteObj);
            } else {
              alert(‘You must select an option to vote for‘);
            }
          };
        }
   ...

查看最终产品

问卷调查应用程序现已创建完成。确保 mongod 仍在运行,并在 Eclipse 中再次运行 Node 应用程序。在浏览器中输入 http://localhost:3000,导航到一个问卷调查并进行投票。随后您就可以看到结果。要查看实时更新,请找到您的本地 IP 地址,并用该地址替换 localhost。在您的局域网中,使用不同的机器(甚至智能手机或平板电脑也可以)导航到这个地址。当您在另一个设备上进行投票时,结果会显示在该设备上,而且会自动发布到您的主要计算机浏览器上:

图 4. 查看问卷调查结果


回页首

下一步:进一步开发和部署

您刚才创建的这个问卷调查应用程序是一个不错的起点,但还有很大的改进空间。在计划创建这类应用程序时,我喜欢使用一种敏捷方法来定义用户案例,并将项目划分为几块来实现。对于这个项目,我使用了 JazzHub,通过将项目的附属代码和源代码一起保存在一个云托管的存储库中,JazzHub 使得开发变得非常简单。

如果您对您的应用程序感到很满意,下一步就是跟全世界的人分享它。在过去,即使部署一个非常简单的应用程序,可能也会是一场噩梦,但值得庆幸的是,那些日子已经一去不复返了。使用 IBM 新兴的兼容 Cloud Foundry 的 BlueMix 平台,您只需几分钟就可以通过最少的配置将您的应用程序部署到云中,一点都不麻烦。


回页首

结束语

这对于开发人员,现在是一个很好的时机。我们手头有大量框架和工具,它们使得开发大量应用程序不仅更简单、更快速,而且更加令人感到愉快。在本文中,您学习了如何使用被称为 MEAN 体系结构(Mongo、Express、Angular 和Node)的技术构建一个应用程序。该堆栈可能只需要一天时间就可以完成任务,远远超过了 LAMP 体系结构(Linux、Apache、MySQL 和 PHP),在 Web 应用程序开发和部署方面,该体系结构也许同样会超越 LAMP 体系结构。对我而言,我已经迫不及待跃跃欲试了。

参考资料

学习

讨论

  • 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
时间: 2024-10-06 18:53:26

node.js应用--转载的相关文章

使用 node.js 开发前端打包程序 ---转载

我们在做前端开发的时候经常会在部署上线的时候做程序的打包和合并,我们接下来就会对如何使用 node.js 开发前端打包程序做非常深入的讲解,希望能够帮到有需要的同学. 我们现在做前端开发更多的是多人共同协作开发,每个人负责不同的模块,便于开发和调试.这样就导致我们最后部署上线的时候需要把所有人开发的模块进行合并,生成单个或多个文件上线.如果手动合并的话肯定是费时又费力,而且非常容易出错,所以我们一般都是通过一些工具来实现自动合并的功能. 打包程序的原理非常简单,入口文件->寻找依赖关系->替换

Node.js的优点和缺点(转载)

著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:FengqiAsia链接:http://www.zhihu.com/question/19653241/answer/15993549来源:知乎 要讲清楚这个问题,先讲讲整个Web应用程序架构(包括流量.处理器速度和内存速度)中的瓶颈.瓶颈在于服务器能够处理的并发连接的最大数量.Node.js解决这个问题的方法是:更改连接到服务器的方式.每个连接发射一个在Node.js引擎的进程中运行的事件,而不是为每个连接生成一个新的O

[转载] Node.js 笔记(一) nodejs、npm、express安装

感谢原作者: http://blog.csdn.net/haidaochen/article/details/7257655 Windows平台下的node.js安装 直接去nodejs的官网http://nodejs.org/上下载nodejs安装程序,双击安装就可以了 测试安装是否成功: 在命令行输入 node –v 应该可以查看到当前安装的nodejs版本号 简单的例子写一段简短的代码,保存为helloworld.js,大致看下nodejs是怎么用的. 如下:该代码主要是创建一个http服

[转载]Node.JS平台上的数据库Redis,MongoDB,HBASE,MySQL

一. MongoDB: 因为10gen是的赞助商之一,所以MongoDB有着良好的Node.JS支持. a. 基本支持:,在Node.JS对MongoDB的支持有两种常用的组件mongodb, mongoose.下面分别介绍. (1)基于mongodb的支持.这个for Node.JS的驱动是基于事件驱动的,所以用法基本上都是异步回调函方式.下载驱动组件$npm install -gd mongodb 在testdb.js加入如下代码: var mongodb = require('mongod

使用Node.js+Socket.IO搭建WebSocket实时应用【转载】

原文:http://www.jianshu.com/p/d9b1273a93fd Web领域的实时推送技术,也被称作Realtime技术.这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新.它有着广泛的应用场景,比如在线聊天室.在线客服系统.评论系统.WebIM等. WebSocket简介 谈到Web实时推送,就不得不说WebSocket.在WebSocket出现之前,很多网站为了实现实时推送技术,通常采用的方案是轮询(Polling)和Comet技术,Comet又可细分为两种实现方

[转载]使用node.js+socket.io搭建实时消息系统

在开发web应用时,经常会有消息接收需求.例如后台处理完某个任务,需要告知用户等.一个简单的做法,是使用ajax轮询.这样带来的问题一是低效,二是消息触达不够实时.另一个方法是使用websocket来接收消息,但可惜IE不支持这种方式.下面推荐一种既能实时接收消息,又能兼容各种浏览器的方案,那就是node.js+socket.io. node.js的异步非阻塞模型,做消息推送非常合适.socket.io则负责屏蔽浏览器的差异,其会选择性的使用下列方式建立连接:websocket, flash s

Express 4.x Node.js的Web框架----《转载》

本文使用node.js v0.10.28 + express 4.2.0 1 Express概述 Express 是一个简洁而灵活的node.js的MVC Web应用框架,提供一系列强大特性创建各种Web应用. Express 不对 node.js 已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的功能. Expressd底层由Node.js的HTTP模块实现. 1.1 express 4.x 安装 express 4.x与之前的版本有了许多的变化,书里和网上的很多方法都不再适用.学

使用Node.js和Redis实现push服务--转载

出处:http://blog.csdn.net/unityoxb/article/details/8532028 push服务是一项很有用处的技术,它能改善交互,提升用户体验.要实现这项服务通常有两种途径,轮询和长连接.轮询就是客户端每隔一段时间就问服务器拿新数据,实现起来很简单但是服务器压力很大,而且大部分请求因为没有新数据都显得很浪费.长连接则是服务器将一个请求挂起,不输出任何内容,直到有新数据产生后才会完成这个请求,浏览器收到响应后则马上再发一个又让服务器挂住,如此反复.这么做的好处是能节

[转载]Node入门 &#187; 一本全面的Node.js教程

http://www.nodebeginner.org/index-zh-cn.html 作者: Manuel Kiessling 翻译: goddyzhao & GrayZhang & MondayChen 关于 本书致力于教会你如何用Node.js来开发应用,过程中会传授你所有所需的“高级”JavaScript知识.本书绝不是一本“Hello World”的教程. 状态 你正在阅读的已经是本书的最终版.因此,只有当进行错误更正以及针对新版本Node.js的改动进行对应的修正时,才会进行