基于Nodejs+express4+Mongodb+Angularjs建立web项目

转自 http://blog.csdn.net/blacksiders/article/details/50081941
基于Nodejs+express4+Mongodb+Angularjs建立web项目

– 基于Nodejs搭建web服务器
– 利用Express4搭建restful服务
– 使用Mongodb作为数据库,用mongoose组件连接Mongodb
– 使用AngularJS+bootstrap设计UI界面
– 使用Webstorm 10.0.4开发
第一部分:服务端搭建

1.通过Webstorm建立Node.js Express APP

File -> New Project -> Node.js Express App,
        Location栏填写项目名称,选择Nodejs和npm位置,
        Options -> Template 选择EJS

在项目下新建文件夹models保存mongodb相关对应model。
在models目录下创建model文件movie.js。
在routes目录下创建restful API 支持文件 movies.js
完成后的目录结构如下

- project
    -- bin
        --- www
    -- models
        --- movie.js
    -- node_modules
        --- ...
    -- public
        --- ...
    -- routes
        movies.js
    app.js
    package.json

2.在package.json中添加mongoose支持及其他相关组件

{
  "name": "project",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "ejs": "~2.3.3",
    "express": "~4.13.1",
    "morgan": "~1.6.1",
    "errorhandler": "~1.4.2",
    "serve-favicon": "~2.3.0",
    "mongoose": "~4.2.5",
    "connect-mongo": "latest",
    "express-session": "latest"
  },
  "engines": {
    "node": ">=0.10.0"
  }
}

3.在movie.js中建立movie模型:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

// define an db object
var movieSchema = new Schema({
    title: String,
    releaseYear: String,
    director: String,
    genre: String
});

// bind module for accessing outside
module.exports = mongoose.model('Movie', movieSchema);

4.在movies.js中建立基于movie的restful API

引入movie模型,并开启router

var Movie = require('../models/movie.js');
var express = require('express');
var router = express.Router();

实现一些基本的功能API

var Movie = require('../models/movie.js');

// get all movies
exports.list = function(req, res){
    Movie.find(function (err, movies) {
        if (err) {
            return res.send(err);
        }
        res.json(movies);
    })
};

// create new movie
exports.create = function(req, res){
    var movie = new Movie(req.body);

    movie.save(function (err) {
        if (err) {
            return res.send(err);
        }
        res.send({message: 'add a movie'});
    });
};

// update a movie
exports.update = function (req, res) {
    //Movie.findById(req.params.id, callback)
    Movie.findOne({_id: req.params.id}, function (err, movie) {
        if (err) {
            return res.send(err);
        }
        for (prop in req.body) {
            movie[prop] = req.body[prop];
        }

        movie.save(function (err) {
            if (err) {
                return res.send(err);
            }
            res.json({message: "update a movie"});
        });
    });
};

//delete a movie
exports.delete = function (req, res) {
    Movie.remove({_id: req.params.id}, function (err, movie) {
        if (err) {
            return res.send(err);
        }
        res.json({message: 'delete a movie'});
    });
};

导出功能模块让其他部分可以使用该模块

module.exports = router;

5.启用Restful服务

在app.js中引入mongoose建立数据库连接

var mongoose = require('mongoose');
// connect to mongodb
var dbName = 'movie';
var url = 'mongodb://localhost:27017/' + dbName;
var mongoOptions = {
    server: {
        socketOptions: {
            keepAlive: 1
        }
    }
};
mongoose.connect(url, mongoOptions);
mongoose.connection.on('error', function (err) {
    console.log('Mongo Error:' + err);
}).on('open', function () {
    console.log('Connection opened');
});

引入router启用Restful服务

var express = require('express');
var app = express();
var movies = require('./routes/movies');
app.use('/api', movies);

由于http通信是基于json格式的,需要指定请求数据格式和编码

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

导出模块

module.exports = app;

6.在bin/www中开启server

var app = require('../app');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

//Create HTTP server
var server = http.createServer(app);
server.listen(port);

第二部分:前端搭建

前端使用AngularJS+Bootstrap搭建

1.引入bower

先安装NodeJS,使用npm工具引入bower。
在项目文件夹pubic下依次建立以下目录结构

- project
    -- ...
    -- public
        --- css
        --- images
        --- js
            ---- controller
            ---- service
        --- views
        index.html

添加bower依赖,在项目根目录下新建.bowerrc文件,指定bower安装路径

{
  "directory": "/public/bower_components"
}

添加bower.json文件指定依赖:

{
  "name": "project",
  "version": "0.0.0",
  "dependencies": {
    "jquery": "~2.1.3",
    "bootstrap": "~3.3.2",
    "angular": "~1.3.8",
    "font-awesome": "~4.2.0",
    "angular-ui-router": "~0.2.13",
    "angular-bootstrap": "~0.12.1"
  }
}

运行bower install,安装相关js插件

2.引入AngularJS组件

在public > js下新建module.js,创建AngularJS项目组件app

'use strict';

var app = angular.module('app', [
    'ui.router',
    'ui.bootstrap'
]);

创建一个service来保存windows session

session.storage.js

(function (app) {
    'use strict';
    app.factory('SessionStorage', function ($window) {
        var store = $window.sessionStorage;
        return { save: function (key, value) { value = angular.toJson(value); store.setItem(key, value); }, get: function (key) { var value = store.getItem(key); if (value) { value = angular.fromJson(value); } return value; }, delete: function (key) { store.removeItem(key); } }
    });
})
(angular.module('app'));

新建一个movie service进行http请求

movie.service.js

(function (app) {
    'use strict';
    app.factory('MovieService', function ($http, $q) {
        return {
            getAllMovies: function () {
                var url = "http://localhost:3000/api/movie/all";
                var deferred = $q.defer();
                $http.get(url).then(
                    function success(respData) {
                        var movies = respData.data;
                        deferred.resolve(movies);
                    },
                    function error(reason) {
                        deferred.reject(reason);
                    }
                );
                return deferred.promise;
            },
            updateMovie: function (movie, id) {
                var url = "http://localhost:3000/api/movie/" + id;
                var deferred = $q.defer();
                $http.put(url, movie).then(
                    function success(respData) {
                        var movies = respData.data;
                        deferred.resolve(movies);
                    },
                    function error(reason) {
                        deferred.reject(reason);
                    }
                );
                return deferred.promise;
            }
        }
    });
})(angular.module('app'));

在controller目录下建立两个controller处理相关数据操作

main.controller.js

(function (app) {
    'use strict';
    app.controller('MainController', function ($scope, $rootScope, $state, SessionStorage, movies) {
        $rootScope.title = 'express_demo2';
        $scope.movies = movies;

        $scope.updateMovie = function (movie) {
            SessionStorage.delete('movie');
            $state.go('movie.update', {data: movie});
        };
    });
})(angular.module('app'));

movie.controller.js

(function (app) {
    'use strict';
    app.controller('MovieController', function ($scope, $rootScope, $state, $stateParams, MovieService, SessionStorage) {
        $scope.movie = $stateParams.data;
        if (!$scope.movie) { $scope.movie = SessionStorage.get('movie'); } else { SessionStorage.save('movie', $scope.movie); }

        $scope.update = function () { var promise = MovieService.updateMovie($scope.movie, $scope.movie._id); promise.then(function (data) { alert('update success!'); SessionStorage.delete('movie'); $state.go('movie.main'); }); };
    });
})(angular.module('app'));

建立uirouter指定路由

(function (app) {
    'use strict';
    app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
        $locationProvider.html5Mode(true);
        $urlRouterProvider.otherwise('/movie');
        $stateProvider
            .state('movie', {
                abstract: 'true',
                templateUrl: '/views/menu.html'
            })
            .state('movie.main', {
                url: '/movie',
                controller: 'MainController',
                templateUrl: '/views/main.html',
                resolve: {
                    'movies': function (MovieService) {
                        return MovieService.getAllMovies();
                    }
                }
            })
            .state('movie.update', {
                url: '/movie/update',
                controller: 'MovieController',
                templateUrl: '/views/update.html',
                params: {
                    data: null
                }
            });
    });
})(angular.module('app'));

在css文件下建立css

.margin-top-20 {
    margin-top: 20px;
}

.title-font {
    font-size: large;
    font-style: italic;
    font-family: Consolas;
    font-weight: bold;
}

在index.html中声明app位置,并导入相关的js和css文件


<html ng-app="app">
<head>
    <meta charset="UTF-8"/>
    <base href='/'/>
    <title ng-bind="title">title>

    <link rel='stylesheet' href='bower_components/bootstrap/dist/css/bootstrap.css'/>
    <link rel='stylesheet' href='bower_components/font-awesome/css/font-awesome.css'/>
    <link rel='stylesheet' href='css/style.css'/>

head>
<body>

<div ui-view>div>

<script src="bower_components/jquery/dist/jquery.min.js">script>
<script src="bower_components/angular/angular.min.js">script>
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js">script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js">script>
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js">script>

<script src="js/module.js">script>
<script src="js/routes.js">script>

<script src="js/controller/main.controller.js">script>
<script src="js/controller/movie.controller.js">script>

<script src="js/service/movie.service.js">script>
<script src="js/service/session.storage.js">script>

body>
html>

在views目录下建立三个html页面进行操作

main.html

<table class="table table-bordered">
    <thead>
    <tr>
        <th>Titleth>
        <th>Yearth>
        <th>Directorth>
        <th>Genreth>
        <th>Optionth>
    tr>
    thead>
    <tbody>
    <tr ng-repeat="movie in movies">
        <td>{{movie.title}}td>
        <td>{{movie.releaseYear}}td>
        <td>{{movie.director}}td>
        <td>{{movie.genre}}td>
        <td><a class="btn btn-default" href="javascript:void(0)" ng-click="updateMovie(movie)">Updatea>td>
    tr>
    tbody>
table>

menu.html

<div class="container">
    <div class="row margin-top-20">
        

class="title-font">Movie Book System

div> div> <div class="container"> <div class="row"> <div class="ui-view">div> div> div>

update.html

"form" class="form form-horizontal"> <div class="form-group"> <div class="col-md-1"> div> <div class="col-md-6"> id="title" type="text" class="form-control" ng-model="movie.title"/> div> div> <div class="form-group"> <div class="col-md-1"> div> <div class="col-md-6"> id="year" type="text" class="form-control" ng-model="movie.releaseYear"/> div> div> <div class="form-group"> <div class="col-md-1"> div> <div class="col-md-6"> id="director" type="text" class="form-control" ng-model="movie.director"/> div> div> <div class="form-group"> <div class="col-md-1"> div> <div class="col-md-6"> id="genre" type="text" class="form-control" ng-model="movie.genre"/> div> div> <div class="form-group"> <div class="col-md-12"> "javascript:void(0)" class="btn btn-default" ng-click="update()">Update div> div>

在app.js中声明html位置

app.set('views', path.join(__dirname, 'public'));
app.engine('html', require('ejs').__express);
app.set('view engine', 'html');
// rewrite to load static resources
app.use(express.static(path.join(__dirname, 'public')));

// static views
app.all('/*', function (req, res) {
    res.sendfile('index.html', {root: path.join(__dirname, 'public')});
});

至此,运行www文件即可启动nodejs项目,在界面上访问localhost:3000即可访问项目。

=========================================

以下是实现过程中自己的一些总结感想:

实现过程中遇到的异常处理:
(1) 在用bower安装依赖的时候,出现了Bower : ENOGIT git is not installed or not in the PATH ,这个错误提示很明显。就是git没有设置在环境变量中!
解决方法一:

添加git到window的环境变量中。设置path路径为C:\Program Files\Git\bin

关于环境变量的设置,在这里就不多说了。

解决方法二:

在不用添加环境变量的情况下,运行下面一个命令,就可以设置当前文件加的环境变量。

$ set PATH=%PATH%;C:\Program Files\Git\bin

运行完了上面的命令,然后你再用bower安装依赖就成功了,不会有Bower : ENOGIT git is not installed or not in the PATH 这个报错了!
(2) 执行bower install命令遇到异常
ECONFLICT Unable to find suitable version for angular
解决方法:

It worked for me by making following changes in "bower.json":
"angular": "latest",
"angular-mocks": "latest",
"jquery": "latest",
"bootstrap": "latest"

(3)查询movie列表时查询结果总为空
解决方法:将movie.js中

module.exports = mongoose.model('Movie',movieSchema);

改为

module.exports = mongoose.model('Movie',movieSchema,'Movie');

原因:
使用Mongoose#model(name, [schema], [collection], [skipInit]);定义模型, mongoose 会把表名变成复数 所以这里collection参数要写上

整个工程流程架构:
views文件夹下定义视图,routes.js中定义路由,路由将视图和控制器Controller进行关联,controller调用service完成业务数据操作,之后将操作结果反映在视图中(例如通过$scope.movies=movies实现变量双向绑定,通过$scope.updateMovie和视图中的ng-click关联)。而service通过调用模型中的API实现数据库操作

你可能感兴趣的:(webstorm,nodejs,mongodb,nodejs,mongodb,angularjs)