您的位置:首页 > 数据库 > Mongodb

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

2016-08-19 10:33 459 查看
转自 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文件

<!DOCTYPE html>
<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>Title</th>
<th>Year</th>
<th>Director</th>
<th>Genre</th>
<th>Option</th>
</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)">Update</a></td>
</tr>
</tbody>
</table>


menu.html

<div class="container">
<div class="row margin-top-20">
<p class="title-font">Movie Book System</p>
</div>
</div>
<div class="container">
<div class="row">
<div class="ui-view"></div>
</div>
</div>


update.html

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


在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实现数据库操作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  nodejs mongodb angularjs