前端MVC學習筆記(四)——NodeJS+MongoDB+AngularJS+Bootstrap書店示例

這章的目的是爲了把前面所學習的內容整合一下,這個示例完成一個簡單圖書管理模塊,由於中間須要使用到Bootstrap這裏先介紹Bootstrap。javascript

示例名稱:天狗書店css

功能:完成先後端分離的圖書管理功能,總結前端學習過的內容。html

技術:NodeJS、Express、Monk、MongoDB、AngularJS、BootStrap、跨域前端

效果:java

1、Bootstrap

Bootstrap是一個UI框架,它支持響應式佈局,在PC端與移動端都表現不錯。jquery

Bootstrap是Twitter推出的一款簡潔、直觀、強悍的前端開發框架。git

Bootstrap中包含了豐富的Web組件,根據這些組件,能夠快速的搭建一個漂亮、功能完備的網站。angularjs

在線可視佈局:http://www.ibootstrap.cn/github

演示: http://expo.bootcss.com/mongodb

中文網:http://www.bootcss.com/

官網:http://getbootstrap.com/

安裝:npm install bootstrap@3

1.一、添加引用

也可以使用包管理器也能夠去官網下載後添加引用。

1.二、在頁面中使用BootStrap

添加CSS引用:

<link rel="stylesheet" type="text/css" href="js/bootstrap/dist/css/bootstrap.min.css" />

添加JavaScript引用:

 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="js/bootstrap/dist/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>

在頁面中引用BootStrap定義好的樣式

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>bootstrap</title>
        <link rel="stylesheet" type="text/css" href="js/bootstrap/dist/css/bootstrap.min.css" />
    </head>

    <body>
        <div class="container-fluid">
            <div class="row">
                <div class="jumbotron">
                    <h1>Hello, world!</h1>
                    <p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information</p>
                    <p>
                        <a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a>
                    </p>
                </div>
            </div>
            <div class="row">
                <div class="col-md-6">
                    <button type="button" class="btn btn-default">默認</button>

                    <button type="button" class="btn btn-primary">主要</button>

                    <button type="button" class="btn btn-success">成功</button>

                    <button type="button" class="btn btn-info">信息</button>

                    <button type="button" class="btn btn-warning">警告</button>

                    <button type="button" class="btn btn-danger">錯誤</button>

                    <button type="button" class="btn btn-link">連接</button>
                </div>
                <div class="col-md-6">
                    <button type="button" class="btn btn-default btn-lg">默認</button>
                    <button type="button" class="btn btn-default">默認</button>
                    <button type="button" class="btn btn-default btn-sm">默認</button>
                    <button type="button" class="btn btn-default btn-xs">默認</button>
                </div>
            </div>
        </div>
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script src="js/bootstrap/dist/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>
    </body>

</html>

運行結果:

1.三、可視化佈局

若是想快速高效的佈局能夠使用一些在線輔助工具,如:

http://www.ibootstrap.cn/

點擊下載能夠得到生成的HTML腳本。

2、使用MongoDB建立數據庫

2.一、啓動MongoDB數據庫

數據庫的具體安裝、配置在前面的章節中已經講解過,能夠參考。

若是服務與配置都沒有完成的話能夠啓動:C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe

2.二、啓動數據庫GUI管理工具

 

2.三、建立數據庫與集合

 在localhost上右鍵「create database」建立名稱爲BookStore的數據庫。

建立一個用於存放圖書的集合名稱爲books。

在集合中添加5本圖書。

db.getCollection('books').insert({id:201701,title:"使用AlarJS開發下一代應用程序",picture:"b1.jpg",price:55.0,author:"brad green"});

3、建立一個Express項目

這裏使用Eclipse(HBuilder)爲開發工具,添加Nodeclipse插件,新增一個Express項目:

3.一、建立app.js

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , books = require('./routes/books')
  , http = require('http')
  , path = require('path');

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

app.get('/', books.list);
app.get('/books', books.list);

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

4、Monk訪問MongoDB數據庫

monk是NodeJS平臺下訪問MongoDB數據庫的一個模塊。monk訪問MongoDB更加方便比NodeJS直接訪問。

git倉庫地址:https://github.com/Automattic/monk

文檔:https://automattic.github.io/monk/

安裝:npm install --save monk

4.一、建立鏈接

const monk = require('monk')

// Connection URL
const url = 'localhost:27017/myproject';

const db = monk(url);

db.then(() => {
  console.log('Connected correctly to server')
})

4.二、插入數據

const url = 'localhost:27017/myproject'; // Connection URL
const db = require('monk')(url);

const collection = db.get('document')

collection.insert([{a: 1}, {a: 2}, {a: 3}])
  .then((docs) => {
    // docs contains the documents inserted with added **_id** fields
    // Inserted 3 documents into the document collection
  }).catch((err) => {
    // An error happened while inserting
  }).then(() => db.close())
users.insert({ woot: 'foo' })
users.insert([{ woot: 'bar' }, { woot: 'baz' }])

4.三、更新數據

const url = 'localhost:27017/myproject'; // Connection URL
const db = require('monk')(url);

const collection = db.get('document')

collection.insert([{a: 1}, {a: 2}, {a: 3}])
  .then((docs) => {
    // Inserted 3 documents into the document collection
  })
  .then(() => {

    return collection.update({ a: 2 }, { $set: { b: 1 } })

  })
  .then((result) => {
    // Updated the document with the field a equal to 2
  })
  .then(() => db.close())
users.update({name: 'foo'}, {name: 'bar'})

4.四、刪除數據

const url = 'localhost:27017/myproject'; // Connection URL
const db = require('monk')(url);

const collection = db.get('document')

collection.insert([{a: 1}, {a: 2}, {a: 3}])
  .then((docs) => {
    // Inserted 3 documents into the document collection
  })
  .then(() => collection.update({ a: 2 }, { $set: { b: 1 } }))
  .then((result) => {
    // Updated the document with the field a equal to 2
  })
  .then(() => {

    return collection.remove({ a: 3})

  }).then((result) => {
    // Deleted the document with the field a equal to 3
  })
  .then(() => db.close())
users.remove({ woot: 'foo' })

4.五、查找數據

const url = 'localhost:27017/myproject'; // Connection URL
const db = require('monk')(url);

const collection = db.get('document')

collection.insert([{a: 1}, {a: 2}, {a: 3}])
  .then((docs) => {
    // Inserted 3 documents into the document collection
  })
  .then(() => collection.update({ a: 2 }, { $set: { b: 1 } }))
  .then((result) => {
    // Updated the document with the field a equal to 2
  })
  .then(() => collection.remove({ a: 3}))
  .then((result) => {
    // Deleted the document with the field a equal to 3
  })
  .then(() => {

    return collection.find()

  })
  .then((docs) => {
    // docs === [{ a: 1 }, { a: 2, b: 1 }]
  })
  .then(() => db.close())
users.find({}).then((docs) => {})
users.find({}, 'name').then((docs) => {
  // only the name field will be selected
})
users.find({}, { fields: { name: 1 } }) // equivalent

users.find({}, '-name').then((docs) => {
  // all the fields except the name field will be selected
})
users.find({}, { fields: { name: 0 } }) // equivalent
users.find({}, { rawCursor: true }).then((cursor) => {
  // raw mongo cursor
})
users.find({}).each((user, {close, pause, resume}) => {
  // the users are streaming here
  // call `close()` to stop the stream
}).then(() => {
  // stream is over
})
//建立的數據庫
var monk = require('monk')
var db = monk('localhost:27017/bookstore')

//讀取數據:
var monk = require('monk')
var db = monk('localhost:27017/monk-demo')
 
var books = db.get('books')
  books.find({}, function(err, docs) {
   console.log(docs)
})

//插入數據:
books.insert({"name":"orange book","description":"just so so"})

//查找數據:
books.find({"name":"apple book"}, function(err, docs) {
  console.log(docs)
})

5、建立Rest後臺服務

在routes目錄下增長的books.js文件內容以下:

/*
 * 使用monk訪問mongodb
 * 以rest的方式向前臺提供服務
 */

//依賴monk模塊
var monk = require('monk');
//鏈接並打開數據庫
var db = monk('localhost:27017/BookStore');
//從數據庫中得到books集合,相似表,並不是全部數據, key
var books = db.get('books');

//列出全部的圖書json
exports.list = function(req, res) {
    //無條件查找全部的圖書,then是當查找完成時回調的異步方法
    books.find({}).then((docs) => {
        //返回json給客戶端
        res.json(docs);
    }).then(() => db.close());   //關閉數據庫
};

//得到最大id
exports.getMax=function(req,res){
    //找一個,根據id降序排序,
    books.findOne({}, {sort: {id: -1}}).then((bookObj)=>{
        res.json(bookObj);
    }).then(() => db.close());;
}

//添加圖書
exports.add = function(req, res) {
    //先找到最大的圖書編號
    books.findOne({}, {sort: {id: -1}}).then((obj)=>{
        //從客戶端發送到服務器的圖書對象
        var book=req.body;
        //設置圖書編號爲最大的圖書編號+1
        book.id=(parseInt(obj.id)+1)+"";
        //執行添加
        books.insert(book).then((docs) => {
        //返回添加成功的對象
         res.json(docs);
       }).then(() => db.close());
    });
};

//刪除圖書
exports.del = function(req, res) {
    //從路徑中取參數id,/:id
    var id=req.params.id;
    //移除編號爲id的圖書
    books.remove({"id":id}).then((obj)=>{
        //返回移除結果
        res.json(obj);
    }).then(() => db.close());
};

//更新
exports.update = function(req, res) {
    //得到提交給服務器的json對象
    var book=req.body;
    //執行更新,第1個參數是要更新的圖書查找條件,第2個參數是要更新的對象
    books.update({"id":book.id}, book).then((obj)=>{
        //返回更新完成後的對象
        res.json(obj);
       }).then(() => db.close());
};

爲了完成跨域請求,修改http頭部信息及路徑映射,app.js文件以下:

var express = require('express'),
    routes = require('./routes'),
    books = require('./routes/books'),
    http = require('http'),
    path = require('path');

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "content-type");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    if(req.method == "OPTIONS") {
        res.send("200");
    } else {
        next();
    }
});

// development only
if('development' == app.get('env')) {
    app.use(express.errorHandler());
}

app.get('/', books.list);
//得到全部的圖書列表
app.get('/books', books.list);
//最大的編號
app.get('/books/maxid', books.getMax);
//添加
app.post('/books/book', books.add);
//刪除
app.delete('/books/id/:id', books.del);
//更新
app.put('/books/book', books.update);

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

查詢全部:

其它服務的測試能夠使用Fiddler完成。

6、使用AngularJS調用後臺服務

這裏的UI使用BootStrap完成,前端使用AngularJS調用NodeJS發佈的服務,將數據存放在MongoDB中。

index.js頁面以下:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>天狗書店</title>
        <link rel="shortcut icon" href="favicon.ico" />
        <link rel="bookmark" href="favicon.ico" />
        <link rel="stylesheet" type="text/css" href="js/bootstrap/dist/css/bootstrap.min.css" />
        <style type="text/css">
            .cover {
                height: 40px;
                width: auto;
            }
            
            .addBook {
                padding-top: 10px;
            }
            
            .w100 {
                width: 50px
            }
            
            .w200 {
                width: 200px;
            }
            
            .w300 {
                width: 300px
            }
        </style>
    </head>

    <body ng-app="bookApp">

        <div class="container" ng-controller="BookController">
            <div class="row clearfix">
                <div class="col-md-12 column">
                    <nav class="navbar navbar-default" role="navigation">
                        <div class="navbar-header">
                            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button>
                            <a class="navbar-brand" href="#">天狗書店</a>
                        </div>

                        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                            <ul class="nav navbar-nav">
                                <li class="active">
                                    <a href="#">前端</a>
                                </li>
                                <li>
                                    <a href="#">Java</a>
                                </li>
                                <li>
                                    <a href="#">.Net</a>
                                </li>
                                <li class="dropdown">
                                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">更多類型<strong class="caret"></strong></a>
                                    <ul class="dropdown-menu">
                                        <li>
                                            <a href="#">Action</a>
                                        </li>
                                        <li>
                                            <a href="#">Another action</a>
                                        </li>
                                        <li>
                                            <a href="#">Something else here</a>
                                        </li>
                                        <li class="divider">
                                        </li>
                                        <li>
                                            <a href="#">Separated link</a>
                                        </li>
                                        <li class="divider">
                                        </li>
                                        <li>
                                            <a href="#">One more separated link</a>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                            <form class="navbar-form navbar-left" role="search">
                                <div class="form-group">
                                    <input type="text" class="form-control" />
                                </div> <button type="submit" class="btn btn-default">搜索</button>
                            </form>
                        </div>
                    </nav>
                    <div class="row clearfix">
                        <div class="col-md-12 column">
                            <div class="carousel slide" id="carousel-519027">
                                <ol class="carousel-indicators">
                                    <li class="active" data-slide-to="0" data-target="#carousel-519027">
                                    </li>
                                    <li data-slide-to="1" data-target="#carousel-519027">
                                    </li>
                                    <li data-slide-to="2" data-target="#carousel-519027">
                                    </li>
                                </ol>
                                <div class="carousel-inner">
                                    <div class="item active">
                                        <img alt="" src="img/adv3.jpg" />
                                        <div class="carousel-caption">

                                        </div>
                                    </div>
                                    <div class="item">
                                        <img alt="" src="img/adv2.jpg" />
                                        <div class="carousel-caption">
                                        </div>
                                    </div>
                                    <div class="item">
                                        <img alt="" src="img/adv1.jpg" />
                                        <div class="carousel-caption">
                                            <h4>
                                        Third Thumbnail label
                                    </h4>
                                            <p>
                                                Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
                                            </p>
                                        </div>
                                    </div>
                                </div>
                                <a class="left carousel-control" href="#carousel-519027" data-slide="prev"><span class="glyphicon glyphicon-chevron-left"></span></a>
                                <a class="right carousel-control" href="#carousel-519027" data-slide="next"><span class="glyphicon glyphicon-chevron-right"></span></a>
                            </div>
                        </div>
                    </div>

                </div>
            </div>

            <div class="row clearfix">
                <div class="col-md-12 column">
                    <div class="addBook">
                        <a id="modal-234446" href="#modal-container-234446" role="button" class="btn btn-sm btn-primary" data-toggle="modal"><span class="glyphicon glyphicon-plus"></span> 新書上架</a>

                        <div class="modal fade" id="modal-container-234446" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                            <div class="modal-dialog">
                                <div class="modal-content">
                                    <div class="modal-header">
                                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
                                        <h4 class="modal-title" id="myModalLabel">
                                添加/編輯圖書
                            </h4>
                                    </div>
                                    <div class="modal-body">

                                        <form class="form-horizontal" role="form">
                                            <div class="form-group">
                                                <label for="id" class="col-sm-2 control-label">編號</label>
                                                <div class="col-sm-10">
                                                    <input type="text" class="form-control w100" id="id" ng-model="book.id" ng-readonly="true" />
                                                </div>
                                            </div>

                                            <div class="form-group">
                                                <label for="title" class="col-sm-2 control-label">書名</label>
                                                <div class="col-sm-10">
                                                    <input type="text" class="form-control w300" id="title" ng-model="book.title" />
                                                </div>
                                            </div>

                                            <div class="form-group">
                                                <label for="picture" class="col-sm-2 control-label">圖片</label>
                                                <div class="col-sm-10">
                                                    <input type="text" class="form-control w200" id="picture" ng-model="book.picture" />
                                                </div>
                                            </div>

                                            <div class="form-group">
                                                <label for="price" class="col-sm-2 control-label">價格</label>
                                                <div class="col-sm-10">
                                                    <input type="text" class="form-control w200" id="price" ng-model="book.price" />
                                                </div>
                                            </div>

                                            <div class="form-group">
                                                <label for="author" class="col-sm-2 control-label">做者</label>
                                                <div class="col-sm-10">
                                                    <input type="text" class="form-control w200" id="author" ng-model="book.author" />
                                                </div>
                                            </div>

                                        </form>

                                    </div>
                                    <div class="modal-footer">
                                        <button type="button" ng-click="save()" class="btn btn-primary">
                                        <span class="glyphicon glyphicon-floppy-disk"></span> 
                                            保存</button>
                                        <button type="button" class="btn btn-success" ng-click="clear()" data-dismiss="modal">
                                            <span class="glyphicon glyphicon-refresh"></span> 
                                            清空</button>
                                        <button type="button" class="btn btn-danger" data-dismiss="modal">
                                            <span class="glyphicon glyphicon-remove"></span> 
                                            關閉</button>
                                    </div>
                                </div>

                            </div>

                        </div>

                    </div>
                    <table class="table">
                        <thead>
                            <tr>
                                <th>
                                    序號
                                </th>
                                <th>
                                    編號
                                </th>
                                <th>
                                    書名
                                </th>
                                <th>
                                    圖片
                                </th>
                                <th>
                                    價格
                                </th>
                                <th>
                                    做者
                                </th>
                                <th>
                                    操做
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr ng-repeat="b in books" ng-class="{'info':$odd}">
                                <td>
                                    {{$index+1}}
                                </td>
                                <td>
                                    {{b.id}}
                                </td>
                                <td>
                                    {{b.title}}
                                </td>
                                <td>
                                    <img ng-src="img/{{b.picture}}" class="cover" />
                                </td>
                                <td>
                                    {{b.price | number:1}}
                                </td>
                                <td>
                                    {{b.author}}
                                </td>
                                <td>
                                    <button type="button" class="btn btn-danger btn-xs" ng-click="del(b.id,$index)">刪除</button>
                                    <button href="#modal-container-234446" role="button" class="btn btn-xs btn-primary" data-toggle="modal" ng-click="edit(b)">編輯</button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!--引入angularjs框架-->
        <script src="js/angular146/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="js/jQuery1.11.3/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="js/bootstrap/dist/js/bootstrap.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //定義模塊,指定依賴項爲空
            var bookApp = angular.module("bookApp", []);

            //定義控制器,指定控制器的名稱,$scope是全局對象
            bookApp.controller("BookController", ['$scope', '$http', function($scope, $http) {
                $scope.books = [];
                $scope.save = function() {
                    $http({
                            url: "http://127.0.0.1:3000/books/book",
                            data: $scope.book,
                            method: $scope.book.id ? "PUT" : "POST"
                        })
                        .success(function(data, status, headers, config) {
                            if($scope.book.id) {
                                alert("修改爲功");
                            } else {
                                $scope.books.push(data);
                            }
                        })
                        .error(function(data, status, headers, config) {
                            alert(status);
                        });
                }

                $scope.edit = function(b) {
                    $scope.book = b;
                }
                $scope.clear = function() {
                    $scope.book = {};
                }

                //初始化加載
                $http.get("http://127.0.0.1:3000/")
                    .success(function(data, status, headers, config) {
                        $scope.books = data;
                    })
                    .error(function(data, status, headers, config) {
                        alert(status);
                    });

                $scope.del = function(id, index) {
                    $http.delete("http://127.0.0.1:3000/books/id/" + id)
                        .success(function(data, status, headers, config) {
                            $scope.books.splice(index, 1);
                        })
                        .error(function(data, status, headers, config) {
                            alert(status);
                        });
                }
            }]);
        </script>
    </body>

</html>

運行結果:

新書上架:

編輯圖書

添加成功後:

7、示例下載

前端:https://github.com/zhangguo5/AngularJS04.git

後臺:https://github.com/zhangguo5/AngularJS04_BookStore.git

參照:http://www.cnblogs.com/best/

相關文章
相關標籤/搜索