NodeJS_04

 

NodeJS七天课程学习笔记_第4天

课程内容概要:

1.Nodemon 自重启

2.Express 静态资源路由的4种情况

3.使用Express框架重写 node_21.js 留言本demo

关于/的几个注意事项

1.    文件读取时, 读readFile当前目录下的文件时,

可以写’./anohana.txt’,  也可以省略”./”

所有的文件操作,都是异步操作

如果,只是省略了前面的点, 以斜杠开头的话,比如”/bin/anohana.txt”

所代表的是,从磁盘的根目录下的bin文件夹下的anohana.txt读取

2.    require加载当前路径下的自定义模块时,  “./”不能省略

如果省略点, 以斜杠开头的话,也是代表从磁盘根目录下开始查找模块

NodeJS七天课程主讲老师:李鹏周

第3方命令行工具 nodemon 解决重启问题

第1步:  安装nodemon,在任意目录下执行以下命令:

sudo npm install –global nodemon

第2步: 运行的时候,不再使用 node xxx.js ,

而是使用 nodemon xxx.js 即可

nodemon的原理: 只要是使用nodemon 启动的服务,它会监视文件的改动,自动重启

nodemon的演示效果如下:

Express 静态资源访问的4种情况

事先说明:

在网站的根目录下,有一个public文件夹,里面又有js、css、img、lib等文件夹

例如: /public/img/beyond.jpg

第1种情况:照原样访问

例如请求方式使用: http://localhost:5267/public/img/beyond.jpg

代码如下:

var urlPrefix = '/public/'
或者
var urlPrefix = '/public'

// 当前目录下的public文件夹
var filePath = './public/'   // 也可以直接 'public'

var callbackFunction = expressExport.static(filePath)

appServer.use(urlPrefix,callbackFunction)

完整代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var expressExport = require('express')
// 创建服务器对象
var appServer = expressExport()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	response.send('<html><head><title>beyond心中の动漫神作</title><link rel="icon" href="/public/img/beyond.jpg" /></head><body style="background-image:url(/public/img/sakura4.png);background-repeat:no-repeat;background-position:center center;"><h1 style="text-align:center;color:white;text-shadow:2px 2px 4px #001;letter-spacing:5px;">未闻花名</h1></body></html>')
})
// url不做任何变化 ,照原样访问
// localhost:5267/public/img/beyond.jpg
var urlPrefix = '/public/'
// var urlPrefix = '/public'  这样写也可以

// 静态资源在磁盘上的目录
var filePath = './public/'   // 也可以直接 'public'
var callbackFunction = expressExport.static(filePath)
NSLog('callbackFunction: + \n' + typeof(callbackFunction))
appServer.use(urlPrefix,callbackFunction)

效果如下:

第2种情况:起别名

请求方式url中也要使用别名: http://localhost:5267/static/img/beyond.jpg

代码如下:

var urlPrefix = '/static/'
或者
var urlPrefix = '/static'

// 当前目录下的public文件夹
var filePath = './public/'    // 也可以直接 'public'

var callbackFunction = expressExport.static(filePath)

appServer.use(urlPrefix,callbackFunction)

完整代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var expressExport = require('express')
// 创建服务器对象
var appServer = expressExport()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	response.send('<html><head><title>beyond心中の动漫神作</title><link rel="icon" href="/static/img/beyond.jpg" /></head><body style="background-image:url(/static/img/sakura4.png);background-repeat:no-repeat;background-position:center center;"><h1 style="text-align:center;color:white;text-shadow:2px 2px 4px #001;letter-spacing:5px;">未闻花名</h1></body></html>')
})
// 给url起个别名
// 访问也只能使用 localhost:5267/static/img/beyond.jpg
// var urlPrefix = '/static/'
var urlPrefix = '/static' //  这样写也可以

// 磁盘上的静态资源目录
var filePath = './public/'   // 也可以直接 'public'
var callbackFunction = expressExport.static(filePath)
NSLog('callbackFunction: + \n' + typeof(callbackFunction))
appServer.use(urlPrefix,callbackFunction)

效果如下:

第3种情况:简化(省略)url路径

在url请求中,也使用简化(省略)后的url路径: http://localhost:5267/img/beyond.jpg

// 没有urlPrefix了

// 当前目录下的public文件夹
var filePath = './public/'   // 也可以直接 'public'

var callbackFunction = expressExport.static(filePath)

appServer.use(callbackFunction)

完整代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var expressExport = require('express')
// 创建服务器对象
var appServer = expressExport()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	response.send('<html><head><title>beyond心中の动漫神作</title><link rel="icon" href="/img/beyond.jpg" /></head><body style="background-image:url(/img/sakura4.png);background-repeat:no-repeat;background-position:center center;"><h1 style="text-align:center;color:white;text-shadow:2px 2px 4px #001;letter-spacing:5px;">未闻花名</h1></body></html>')
})
// 没有 urlPrefix 了
// 访问也只能使用 localhost:5267/img/beyond.jpg

// 磁盘上的静态资源目录
var filePath = './public/'   // 也可以直接 'public'
var callbackFunction = expressExport.static(filePath)
NSLog('callbackFunction: + \n' + typeof(callbackFunction))
appServer.use(callbackFunction)

效果如下:

第4种情况:下次再讲

在Express中使用art-template模板引擎

注意: 在art-template官方网站上有详细介绍在express/koa中如何使用模板引擎

第1步安装:

npm install art-template –save

npm install express-art-template –save

运行结果如下:

第2步配置:

核心代码就一句:

appServer.engine(‘html‘,require(‘express-art-template‘))

解释一下:

对于(views目录下)所有后缀名为html的文件,使用模板引擎

注意:如果 不想把模板文件放在默认的views目录下 ,则可以通过下面代码更改设置

appServer.set(‘views’,’其他目录’)

第3步使用:

appServer.get(‘/’,function(request,response){

response.render(‘index/index.html‘,{

girlName: ‘mathilda’,

girlAge: 12,

girlLikeArr: [‘leon’,’milk’,’imitation show’]

})

})

解释说明一下:

模板位置是在网站的根目录下 views目录index文件夹里的 index.html

静态资源是在网站的根目录下 public目录中 img 和 js 和 css 文佳夹里

node_27_3.js 完整使用示例如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	// 使用模板引擎渲染
	// 注意: 模板文件默认是放在views目录下
	// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
	// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
	response.render('index/node_27_3_template.html',{
		author: 'beyond',
		girlName: 'mathilda',
		girlAge: 12,
		loveArr:['leon','milk','imitation show']
	})
})


// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

views目录下index文件夹里的模板文件node_27_3_template.html完整内容如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
    <link rel="icon" href="/public/img/beyond2.jpg" type="image/x-icon"/>
    <meta charset="UTF-8">
    <meta name="author" content="beyond">
    <meta http-equiv="refresh" content="520">
    <meta name="description" content="未闻花名-免费零基础教程-beyond">
    <meta name="viewport" content="width=device-width, 
    initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
    <title>beyond心中の动漫神作</title>
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbasestylewhite5.css">
    <style type="text/css">
        body{
            font-size: 100%; 
            /*声明margin和padding是个好习惯*/  
            margin: 0;  
            padding: 0; 
            padding-left: 10px;
            padding-right: 10px;
            background-image: url("/public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
        }
    </style>
    <!-- 绿色按钮的css效果 -->
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbuttongreen.css">
</head>  
  
<body>  
        <h1 style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">  
            未闻花名
        </h1>       
	        <div style="margin:0 auto;text-align:center">
                hi {{ author }} <br/>
                it's {{ girlName }},I'm {{ girlAge }} years old,I like :</br>
                {{ each loveArr }} 
                    {{ $index }} : {{ $value }} <br/>
                {{ /each }}
            </div>
<footer id="copyright">
            <p style="font-size:14px;text-align:center;font-style:italic;">  
            Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
            </p>        
        </footer>
</body>  
</html>  

在命令行中,使用 命令: nodemon node_27_3.js 运行效果如下:

浏览器访问: localhost:5267 效果如下:

将前面的node_21.js实现的留言板demo,通过express框架重写一下

node_28.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// -----------------------------------

// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

// -----------------------------------

// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// -----------------------------------
var dataObject = {
	recordArr:[
		{
			girlName: '面码',
			girlDescription: '未闻花名',
			pubTime: '2006-06-07'
		},
		{
			girlName: 'mathilda',
			girlDescription: '这个杀手不太冷',
			pubTime: '2006-06-07'
		}
	]
}
// -----------------------------------
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	// 使用模板引擎渲染
	// 注意: 模板文件默认是放在views目录下
	// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
	// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
	response.render('index/node_28_index.html',dataObject)
})
// 处理get请求
appServer.get('/write',function (request,response) {
	// 没有数据需要绑定的时候,不传第2个参数即可
	response.render('index/node_28_write.html')
})
// 处理get请求
appServer.get('/insert',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query
	queryObj.pubTime = '2018-06-07'	
	// 提交评论,理论上应该插入数据库,然后重新刷新
	// 这儿只是临时加到数组的最前面
	dataObject.recordArr.unshift(queryObj)
	// 临时重定向
	response.redirect('/')
})


效果如下:

下面再将留言板demo由get请求改成post请求

在express中,获取get请求中的参数对象,只需要

var queryObject = request.query 即可

在express中,获取post请求中的参数对象,需要两个步骤

第1步: 安装 body-parser 这个 中间件middleware (可在express官网上resource菜单中看到)

express官网中的middleware列表地址如下:http://expressjs.com/en/resources/middleware.html

安装命令:        npm install body-parser –save

第2步: 配置 3 行代码

        var bodyParser = require('body-parser')

        // 设置解析 application/x-www-form-urlencoded

        appServer.use(bodyParser.urlencoded({extended: false}))        

        // 设置解析 application/json

        appServer.use(bodyParser.json())

第3步: 使用 body-parser 解析出post提交过来的对象

var postObj = request.body

下面演示 将留言板demo由get请求改成post请求

第1步:

先将views目录下的index文件夹下的html模板文件:

node_29_insert.html中  表单的method属性 由get改成post

第2步:

在node_29.js中,引入body-parser,并进行配置,最后再处理post请求

node_29.js完整代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  
// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// -----------------------------------

// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

// -----------------------------------

// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// -----------------------------------
var dataObject = {
	recordArr:[
		{
			girlName: '面码',
			girlDescription: '未闻花名',
			pubTime: '2006-06-07'
		},
		{
			girlName: 'mathilda',
			girlDescription: '这个杀手不太冷',
			pubTime: '2006-06-07'
		}
	]
}
// -----------------------------------
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	var queryObj = request.query

	// 使用模板引擎渲染
	// 注意: 模板文件默认是放在views目录下
	// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
	// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
	response.render('index/node_29_index.html',dataObject)
})
// 处理get请求
appServer.get('/write',function (request,response) {
	// 没有数据需要绑定的时候,不传第2个参数即可
	response.render('index/node_29_write.html')
})

// // 处理get请求
// appServer.get('/insert',function (request,response) {
// 	// 至于请求参数可以这样:
// 	var queryObj = request.query
// 	queryObj.pubTime = '2018-06-07'	
// 	// 提交评论,理论上应该插入数据库,然后重新刷新
// 	// 这儿只是临时加到数组的最前面
// 	dataObject.recordArr.unshift(queryObj)
// 	// 临时重定向
// 	response.redirect('/')
// })


// -----------------------------------
// 使用middleware中间件body-parser进行post请求体中数据解析
var bodyParser = require('body-parser')
// 设置解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))        
// 设置解析 application/json
appServer.use(bodyParser.json())


// 处理post请求
appServer.post('/insert',function (request,response) {
	// 至于请求参数可以这样:
	var postObject = request.body
	postObject.pubTime = '2018-06-07'	
	// 提交评论,理论上应该插入数据库,然后重新刷新
	// 这儿只是临时加到数组的最前面
	dataObject.recordArr.unshift(postObject)
	// 临时重定向
	response.redirect('/')
})

执行效果如下:

青花瓷Charles抓包如下:

下面的node_30.js 做一个CRUD的小demo

首页模板node_30_index.html 是从bootstrap的后台模板中,

通过右键查看源代码,扒下来的:https://v3.bootcss.com/examples/dashboard/

node_30_index.html内容如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
    <link rel="icon" href="/public/img/beyond2.jpg" type="image/x-icon"/>
    <meta charset="UTF-8">
    <meta name="author" content="beyond">
    <meta http-equiv="refresh" content="520">
    <meta name="description" content="未闻花名-免费零基础教程-beyond">
    <meta name="viewport" content="width=device-width, 
    initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
    <title>beyond心中の动漫神作</title>
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbasestylewhite5.css">
    <script type="text/javascript" src="/public/js/nslog.js"></script>

    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>


        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
    <![endif]-->

    <style type="text/css">
        body{
            font-size: 100%; 
            /*声明margin和padding是个好习惯*/  
            margin: 0;  
            padding: 0; 
            background-image: url("/public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
        }
    </style>
    <!-- 绿色按钮的css效果 -->
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbuttongreen.css">

    <!-- 引入 jquery 2.1.4 -->
    <!--[if gte IE 9]><!--> 
    <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js">
    </script>
    <!--<![endif]-->


    <link rel="stylesheet" type="text/css" href="/public/lib/bootstrap/bootstrap.css">


    <!-- 分隔线 -->

    <!-- Bootstrap core CSS -->
    <link href="/public/lib/node30_337_bootstrap.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/public/css/node30dashboard.css" rel="stylesheet">

    

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>  
  
<body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <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="#" style="color:white;">beyond</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Dashboard</a></li>
            <li><a href="#">Settings</a></li>
            <li><a href="#">Profile</a></li>
            <li><a href="#">Help</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="Search...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Reports</a></li>
            <li><a href="#">Analytics</a></li>
            <li><a href="#">Export</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item</a></li>
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
            <li><a href="">More navigation</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
          </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
          <h1 class="page-header" style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">未闻花名</h1>

          <div class="row placeholders">
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
          </div>

          <h2 class="sub-header">动漫神作列表</h2>
          <div class="table-responsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>id</th>
                  <th>芳名</th>
                  <th>年龄</th>
                  <th>动漫</th>
                  <th>日期</th>
                </tr>
              </thead>
              <tbody>
              {{ each recordArr }}
                <tr>
                  <td>{{ $value.girlID }}</td>
                  <td>{{ $value.girlName }}</td>
                  <td>{{ $value.girlAge }}</td>
                  <td>{{ $value.girlDescription }}</td>
                  <td>{{ $value.pubTime }}</td>
                </tr>
            {{ /each }}
                
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>

    <footer id="copyright">
            <p style="font-size:14px;text-align:center;font-style:italic;">  
            Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
            </p>        
        </footer>
  </body>
</html>

node_30.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  

// 使用文件数据库
var fs = require('fs')
// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// -----------------------------------

// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

// -----------------------------------

// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// -----------------------------------
// 处理get请求
appServer.get('/',function (request,response) {
	// 至于请求参数可以这样:
	// var queryObj = request.query

	

	// 第2个参数: 可以指定读取的编码
	fs.readFile('node_30.db','utf8',function (error,data) {
		if (error) {
			return response.status(500).send('服务器内部错误')
		}
		// 将读取字符串,转成对象
		var dataObject = JSON.parse(data)

		// 使用模板引擎渲染
		// 注意: 模板文件默认是放在views目录下
		// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
		// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
		response.render('index/node_30_index.html',dataObject)
	})
})

// 处理get请求
appServer.get('/write',function (request,response) {
	// 没有数据需要绑定的时候,不传第2个参数即可
	response.render('index/node_29_write.html')
})

数据库node_30.db文件如下:

{
	"recordArr" : [
		{	
			"girlID": 1,
			"girlName": "面码",
			"girlAge": 15,
			"girlDescription": "未闻花名",
			"pubTime": "2006-06-07"
		},
		{
			"girlID": 2,
			"girlName": "逢坂大河",
			"girlAge": 16,
			"girlDescription": "龙与虎",
			"pubTime": "2007-06-07"
		},
		{
			"girlID": 3,
			"girlName": "k-on",
			"girlAge": 12,
			"girlDescription": "轻音少女",
			"pubTime": "2008-06-07"
		},
		{
			"girlID": 4,
			"girlName": "mathilda",
			"girlAge": 12,
			"girlDescription": "这个杀手不太冷",
			"pubTime": "2009-06-07"
		}
	]
}

效果如下:

推荐了一本书: <结构思维>

从Node开始,后面还会遇到相当多的第3方的,如vue,angular,react,webpack

优先以解决问题为主, 有精力的话再去探求原理

下面演示的是  如何在express中,使用自定义路由模块

自定义路由设计的目的是:

1.让主入口程序的职责更加单一,代码更加简洁
1.1 创建服务
1.2 做一些服务相关的配置,比如:
1.2.1 静态资源配置
1.2.2 模板引擎配置
1.2.3 body-parse 解析表单
1.2.4 挂载自定义路由

1.2.5 监听端口,启动服务

注意: 在主程序app中,配置模板引擎和body-parser, 一定要在挂载路由之前

node_31.js_router.js代码如下:

// express 专门提供了路由的处理方法
var express = require('express')
// 1.使用express专门提供的路由器处理路由
var router = express.Router()

var fs = require('fs')
router.get('/',function (request,response) {
	// 至于请求参数可以这样:
	// var queryObj = request.query
	// 第2个参数: 可以指定读取的编码
	fs.readFile('node_31.db','utf8',function (error,data) {
		if (error) {
			return response.status(500).send('服务器内部错误')
		}
		// 将读取字符串,转成对象
		var dataObject = JSON.parse(data)

		// 使用模板引擎渲染
		// 注意: 模板文件默认是放在views目录下
		// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
		// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
		response.render('index/node_31_index.html',dataObject)
	})	
})

// 3.在模块文件最后,导出router
module.exports = router主

使用了自定义路由模块的主程序入口文件node_31.js如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  


// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// -----------------------------------

// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

// -----------------------------------

// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// -------------注意: 配置模板引擎和body-parser, 一定要在挂载路由之前
// 使用自定义的路由模块 必须使用./
var beyondRouter = require('./node_31_router')
appServer.use(beyondRouter)

效果如下:

补充一下知识点: 回调函数

node_33.js的代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  

function beyondFunction(callbackFunction){
	setTimeout(
		function(){
			var girlSay = 'hello beyond'
			// 为了能够在外部 拿到这个变量 girlSay 进行输出
			// 我们使用回调函数
			callbackFunction(girlSay)
		},1000
	)
}

// 这时我们调用beyondFunction时,只要传递一个block即可拿到定时器内的局部变量 girlSay
NSLog('准备执行函数beyondFunction')
beyondFunction(function ( result ) {
	NSLog('what girl say is: ' + result)
})
NSLog('函数beyondFunction完毕')

运行效果如下:

为了使用自定义路由模块node_32_router.js 与 操作数据库 解耦,

并且同时发挥异步编程的先天优势,我们通过callback回调机制,

创建了一个Dao专门操作数据库的node_32_Dao.js

专门用来对文件数据库node_32.db进行CRUD增删改查

完整案例代码如下:

node_32_index.js代码如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  


// 导入框架
var express = require('express')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('启动失败: ' + error)
	}
	NSLog('服务启动成功')
})
// -----------------------------------

// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'

// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)

// -----------------------------------

// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')

// -----------------------------------
// 使用middleware中间件body-parser进行post请求体中数据解析
var bodyParser = require('body-parser')
// 设置解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))        
// 设置解析 application/json
appServer.use(bodyParser.json())
// -----------------------------------
// 自定义路由设计的目的是:
// 1.让主入口程序的职责更加单一,代码更加简洁
//     1.1 创建服务
//     1.2 做一些服务相关的配置,比如:
//           1.2.1 静态资源配置
//           1.2.2 模板引擎配置
//           1.2.3 body-parse 解析表单
//           1.2.4 挂载自定义路由
//           1.2.5 监听端口,启动服务
// 使用自定义的路由模块 必须使用./
// 注意: 配置模板引擎和body-parser, 一定要在挂载路由之前
var beyondRouter = require('./node_32_router')
appServer.use(beyondRouter)

路由模块node_32_router.js代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  
/*
	自定义路由模块的职责是:
		专门处理所有的路由
		根据不同的请求方式和路径,采取相应的处理方法
*/ 
// express 专门提供了路由的处理方法
var express = require('express')
// 1.使用express专门提供的路由器处理路由
var router = express.Router()

var fs = require('fs')
// ----------------首页-------------------
router.get('/',function (request,response) {
	// 至于请求参数可以这样:
	// var queryObj = request.query
	// 第2个参数: 可以指定读取的编码
	fs.readFile('node_32.db','utf8',function (error,data) {
		if (error) {
			return response.status(500).send('服务器内部错误')
		}
		// 将读取字符串,转成对象
		var dataObject = JSON.parse(data)

		// 使用模板引擎渲染
		// 注意: 模板文件默认是放在views目录下
		// 为此,我们在views目录下  分别为不同的业务模块创建了不同的文件夹
		// 如 login登录 admin后台管理 index前台首页 article文章 comment评论
		response.render('index/node_32_index.html',dataObject)
	})	
})


// ----------------添加的表单页面-------------------
router.get('/add',function (request,response) {
	response.render('index/node_32_add.html')
})
// ----------------引入dao模块-------------------
// 先对dao初始化
var girlDao = require('./node_32_dao')
// 执行初始化函数,参数是一个block (即一个匿名回调函数callback),在读取数据库文件失败时,会回调
girlDao.loadDBFunction(function (error) {
	NSLog('dao error: ' + error)
})

// ----------------增加一条记录-------------------
router.post('/insert',function (request,response) {
	// 1.body-parser得到obj
	var girlObj = request.body
	NSLog(girlObj)
	// 1.调用girlDao写到文件数据库
	girlDao.addGirlFunction(girlObj,function (error) {
		if (error === null) {
			// 没有错误,跳转到首页	
			return response.redirect('/')
		}
		// 有错误
		response.send(error)
	})
})
// ----------------删除一条记录------------------- 
router.get('/delete',function (request,response) {
	// 1.获取query对象
	var queryObj = request.query
	NSLog('id: ' + queryObj.girlID)
	// 2.调用dao从数据库中删除一个对象
	girlDao.deleteModelByIDFunction(parseInt(queryObj.girlID),function (error) {
		if (error === null) {
			// 如果没有错误,跳转到首页
			return response.redirect('/')
		}
		// 有错误
		response.send(error)
	})
})
// ----------------修改页面------------------- 
router.get('/edit',function (request,response) {
	// 查询的girlID
	var queryObj = request.query
	// 由于要根据指定的id查找出对象,所以通过dao
	girlDao.findGirlByIDFunction(parseInt(queryObj.girlID),function (girl) {
		if (girl === null) {
			// 如果查找失败,则显示错误信息
			return response.send('查无此人')
		}
		// 如果异步查找成功,则带着对象去渲染
		return response.render('index/node_32_edit.html',{'girl':girl})
	})
})
// ----------------更新数据库------------------- 
router.post('/update',function (request,response) {
	// 请求体
	var postObj = request.body
	// 使用dao进行更新
	girlDao.updateGirlFunction(postObj,function (error) {
		if (error) {
			// 如果保存出错了
			return response.send(error)
		}
		// 如果保存成功,回首页
		response.redirect('/')
		
	})
})

// 3.在模块文件最后,导出router
module.exports = router

数据库操作模块node_32_dao.js代码如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  

var fs = require('fs')
var dbFilePath = 'node_32.db'
var DBFileObject = {}
// ----------------初始化------------------- 
// 初始化,从磁盘中 读取数据文件,转成对象模型数组
exports.loadDBFunction = function (callback) {
	// 第1步,读文件,转成对象数组
	fs.readFile(dbFilePath,'utf8',function (error,data) {
		// 第2步,在对象数组中,追加一个对象
		if (error) {
			// 出错了,回调给上层
			callback('数据库文件读取失败')
		}	
		// 直接转成对象
		DBFileObject = JSON.parse(data)
		
	})
	
}
// ----------------添加一条记录------------------- 
exports.addGirlFunction = function (girl,callback) {
	// 第1步,处理好girlID
	DBFileObject.girlCount += 1
	// 第2步,添加到数组末尾
	girl.girlID = DBFileObject.girlCount
	// 2.1 修正girlID
	girl.girlAge = parseInt(girl.girlAge)

	girl.pubTime = '2018-05-20'
	DBFileObject.girlArr.push(girl)
	// 第3步,保存到数据库文件,并回调
	fs.writeFile(dbFilePath,JSON.stringify(DBFileObject),function (error) {
		if (error) {
			return callback('写入数据库失败')
		}
		// 写入文件成功
		callback(null)
	})
	
}
// ----------------删除一条记录------------------- 
exports.deleteModelByIDFunction = function (girlID,callback) {
	// 1.根据id,查找索引,删除对象
	var deleteIndex = DBFileObject.girlArr.findIndex(function (girl) {
		// 返回的条件是: 当两者id匹配成功之时
		return girl.girlID === girlID
	})

	// 2.从数组中,通过指定下标,删除1个对象元素
	DBFileObject.girlArr.splice(deleteIndex,1)

	// 3.保存到数据库,并回调
	fs.writeFile(dbFilePath,JSON.stringify(DBFileObject),function (error) {
		if (error) {
			return callback('写入数据库失败')
		}
		// 写入文件成功
		callback(null)
	})
	
}
// ----------------根据girlID查找一个对象------------------- 
exports.findGirlByIDFunction = function (girlID,callback) {
	// 1.查询出数据库里 对应 girlID的对象
	var girl = DBFileObject.girlArr.find(function (item) {
		// 返回的条件是: 当两者girlID相等
		return item.girlID === girlID
	})
	// 回调
	callback(girl)
}
// ----------------根据girlID查找一个对象------------------- 
exports.updateGirlFunction = function (girl,callback) {
	// 1.根据girlID查找 
	var targetGirl = DBFileObject.girlArr.find(function (item) {
		return item.girlID === parseInt(girl.girlID)
	})
	NSLog('targetGirl: ' + targetGirl)
	// 2.重新赋值
	for(key in girl){
		targetGirl[key] = girl[key]
	}
	// 2.1 修正girlID
	targetGirl.girlID = parseInt(targetGirl.girlID)
	targetGirl.girlAge = parseInt(targetGirl.girlAge)
	// 3.重新写回数据库,并回调
	fs.writeFile(dbFilePath,JSON.stringify(DBFileObject),function (error) {
		NSLog('dao error : ' + error)
		if (error) {
			return callback('写入数据库失败')
		}
		// 写入文件成功
		callback(null)
	})
}

.

首页的模板node_32_index.html代码如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
    <link rel="icon" href="/public/img/beyond2.jpg" type="image/x-icon"/>
    <meta charset="UTF-8">
    <meta name="author" content="beyond">
    <meta http-equiv="refresh" content="520">
    <meta name="description" content="未闻花名-免费零基础教程-beyond">
    <meta name="viewport" content="width=device-width, 
    initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
    <title>beyond心中の动漫神作</title>
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbasestylewhite5.css">
    <script type="text/javascript" src="/public/js/nslog.js"></script>

    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>


        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
    <![endif]-->

    <style type="text/css">
        body{
            font-size: 100%; 
            /*声明margin和padding是个好习惯*/  
            margin: 0;  
            padding: 0; 
            background-image: url("/public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
        }
    </style>
    <!-- 绿色按钮的css效果 -->
    <link rel="stylesheet" type="text/css" href="/public/css/beyondbuttongreen.css">

    <!-- 引入 jquery 2.1.4 -->
    <!--[if gte IE 9]><!--> 
    <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js">
    </script>
    <!--<![endif]-->


    <link rel="stylesheet" type="text/css" href="/public/lib/bootstrap/bootstrap.css">


    <!-- 分隔线 -->

    <!-- Bootstrap core CSS -->
    <link href="/public/lib/node30_337_bootstrap.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="/public/css/node30dashboard.css" rel="stylesheet">

    

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>  
  
<body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <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="#" style="color:white;">beyond</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Dashboard</a></li>
            <li><a href="#">Settings</a></li>
            <li><a href="#">Profile</a></li>
            <li><a href="#">Help</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="Search...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Reports</a></li>
            <li><a href="#">Analytics</a></li>
            <li><a href="#">Export</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item</a></li>
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
            <li><a href="">More navigation</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
          </ul>
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
          <h1 class="page-header" style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">未闻花名<small><a href="/add" style="color:white">添加记录(Node版)</a></small></h1>

          <!-- <div class="row placeholders">
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
          </div> -->

          <!-- <h2 class="sub-header">动漫神作列表 </h2> -->
          
          <div class="table-responsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>id</th>
                  <th>芳名</th>
                  <th>年龄</th>
                  <th>动漫</th>
                  <th>日期</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>
              {{ each girlArr }}
                <tr>
                  <td>{{ $value.girlID }}</td>
                  <td>{{ $value.girlName }}</td>
                  <td>{{ $value.girlAge }}</td>
                  <td>{{ $value.girlDescription }}</td>
                  <td>{{ $value.pubTime }}</td>
                  <td>
                    <button class="btn btn-success"><a href="/edit?girlID={{ $value.girlID }}" style="color:white;">修改</a></button>
                    <button class="btn btn-danger"><a href="/delete?girlID={{ $value.girlID }}" style="color:white;">删除</a></button>
                  </td>
                </tr>
            {{ /each }}
                
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>

    <footer id="copyright">
            <p style="font-size:14px;text-align:center;font-style:italic;">  
            Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
            </p>        
        </footer>
  </body>
</html>

添加记录的模板node_32_add.html代码如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
  <link rel="icon" href="/public/img/beyond2.jpg" type="image/x-icon"/>
  <meta charset="UTF-8">
  <meta name="author" content="beyond">
  <meta http-equiv="refresh" content="520">
  <meta name="description" content="未闻花名-免费零基础教程-beyond">
  <meta name="viewport" content="width=device-width, 
  initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
  <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
  <title>beyond心中の动漫神作</title>
  <link rel="stylesheet" type="text/css" href="/public/css/beyondbasestylewhite5.css">
  <script type="text/javascript" src="/public/js/nslog.js"></script>

    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>


        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
        <![endif]-->

        <style type="text/css">
          body{
            font-size: 100%; 
            /*声明margin和padding是个好习惯*/  
            margin: 0;  
            padding: 0; 
            background-image: url("/public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
          }
        </style>
        <!-- 绿色按钮的css效果 -->
        <link rel="stylesheet" type="text/css" href="/public/css/beyondbuttongreen.css">

        <!-- 引入 jquery 2.1.4 -->
        <!--[if gte IE 9]><!--> 
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js">
        </script>
        <!--<![endif]-->


        <link rel="stylesheet" type="text/css" href="/public/lib/bootstrap/bootstrap.css">


        <!-- 分隔线 -->

        <!-- Bootstrap core CSS -->
        <link href="/public/lib/node30_337_bootstrap.css" rel="stylesheet">

        <!-- Custom styles for this template -->
        <link href="/public/css/node30dashboard.css" rel="stylesheet">



        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
      <![endif]-->

    </head>  

    <body>

      <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
          <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
              <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="#" style="color:white;">beyond</a>
          </div>
          <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
              <li><a href="#">Dashboard</a></li>
              <li><a href="#">Settings</a></li>
              <li><a href="#">Profile</a></li>
              <li><a href="#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
              <input type="text" class="form-control" placeholder="Search...">
            </form>
          </div>
        </div>
      </nav>

      <div class="container-fluid">
        <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
            <ul class="nav nav-sidebar">
              <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
              <li><a href="#">Reports</a></li>
              <li><a href="#">Analytics</a></li>
              <li><a href="#">Export</a></li>
            </ul>
            <ul class="nav nav-sidebar">
              <li><a href="">Nav item</a></li>
              <li><a href="">Nav item again</a></li>
              <li><a href="">One more nav</a></li>
              <li><a href="">Another nav item</a></li>
              <li><a href="">More navigation</a></li>
            </ul>
            <ul class="nav nav-sidebar">
              <li><a href="">Nav item again</a></li>
              <li><a href="">One more nav</a></li>
              <li><a href="">Another nav item</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1 class="page-header" style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">未闻花名<small><a href="/" style="color:white;">回到首页</a></small></h1>

            <div class="row placeholders">
              <!-- <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div> -->
            </div>

            <!-- <h2 class="sub-header">动漫神作列表 </h2> -->



            <form action="/insert" method="post">
              <div class="form-group">
                <label for="in_input_name">芳名</label>
                <input type="text" class="form-control" id="in_input_name" placeholder="请输入妳的名字" name="girlName">
              </div>
              <div class="form-group">
                <label for="id_input_age">年龄</label>
                <input type="text" class="form-control" id="id_input_age" placeholder="请输入妳的芳龄" name="girlAge">
              </div>

              <div class="form-group">
                <label for="id_input_anime">动漫推荐</label>
                <input type="text" class="form-control" id="id_input_anime" placeholder="请输入妳主演过的动漫" name="girlDescription">
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
        <footer id="copyright">
          <p style="font-size:14px;text-align:center;font-style:italic;">  
            Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
          </p>        
        </footer>
      </body>
      </html>

修改(回显)记录的模板node_32_edit.html代码如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
  <link rel="icon" href="/public/img/beyond2.jpg" type="image/x-icon"/>
  <meta charset="UTF-8">
  <meta name="author" content="beyond">
  <meta http-equiv="refresh" content="520">
  <meta name="description" content="未闻花名-免费零基础教程-beyond">
  <meta name="viewport" content="width=device-width, 
  initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
  <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
  <title>beyond心中の动漫神作</title>
  <link rel="stylesheet" type="text/css" href="/public/css/beyondbasestylewhite5.css">
  <script type="text/javascript" src="/public/js/nslog.js"></script>

    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>


        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
        <![endif]-->

        <style type="text/css">
          body{
            font-size: 100%; 
            /*声明margin和padding是个好习惯*/  
            margin: 0;  
            padding: 0; 
            background-image: url("/public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
          }
        </style>
        <!-- 绿色按钮的css效果 -->
        <link rel="stylesheet" type="text/css" href="/public/css/beyondbuttongreen.css">

        <!-- 引入 jquery 2.1.4 -->
        <!--[if gte IE 9]><!--> 
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js">
        </script>
        <!--<![endif]-->


        <link rel="stylesheet" type="text/css" href="/public/lib/bootstrap/bootstrap.css">


        <!-- 分隔线 -->

        <!-- Bootstrap core CSS -->
        <link href="/public/lib/node30_337_bootstrap.css" rel="stylesheet">

        <!-- Custom styles for this template -->
        <link href="/public/css/node30dashboard.css" rel="stylesheet">



        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
      <![endif]-->

    </head>  

    <body>

      <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
          <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
              <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="#" style="color:white;">beyond</a>
          </div>
          <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
              <li><a href="#">Dashboard</a></li>
              <li><a href="#">Settings</a></li>
              <li><a href="#">Profile</a></li>
              <li><a href="#">Help</a></li>
            </ul>
            <form class="navbar-form navbar-right">
              <input type="text" class="form-control" placeholder="Search...">
            </form>
          </div>
        </div>
      </nav>

      <div class="container-fluid">
        <div class="row">
          <div class="col-sm-3 col-md-2 sidebar">
            <ul class="nav nav-sidebar">
              <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
              <li><a href="#">Reports</a></li>
              <li><a href="#">Analytics</a></li>
              <li><a href="#">Export</a></li>
            </ul>
            <ul class="nav nav-sidebar">
              <li><a href="">Nav item</a></li>
              <li><a href="">Nav item again</a></li>
              <li><a href="">One more nav</a></li>
              <li><a href="">Another nav item</a></li>
              <li><a href="">More navigation</a></li>
            </ul>
            <ul class="nav nav-sidebar">
              <li><a href="">Nav item again</a></li>
              <li><a href="">One more nav</a></li>
              <li><a href="">Another nav item</a></li>
            </ul>
          </div>
          <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
            <h1 class="page-header" style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">未闻花名<small><a href="/" style="color:white;">回到首页</a></small></h1>

            <div class="row placeholders">
              <!-- <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div>
              <div class="col-xs-6 col-sm-3 placeholder">
                <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                <h4>Label</h4>
                <span class="text-muted">Something else</span>
              </div> -->
            </div>

            <!-- <h2 class="sub-header">动漫神作列表 </h2> -->



            <form action="/update" method="post">
              <div class="form-group">
                <label for="in_input_name">芳名</label>
                <input type="text" class="form-control" id="in_input_name" placeholder="请输入妳的名字" name="girlName" value="{{ girl.girlName }}">
              </div>
              <div class="form-group">
                <label for="id_input_age">年龄</label>
                <input type="text" class="form-control" id="id_input_age" placeholder="请输入妳的芳龄" name="girlAge"  value="{{ girl.girlAge }}">
              </div>
              <!-- 隐藏表单 -->
              <input type="hidden" name="girlID" value="{{ girl.girlID }}" />

              <div class="form-group">
                <label for="id_input_anime">动漫推荐</label>
                <input type="text" class="form-control" id="id_input_anime" placeholder="请输入妳主演过的动漫" name="girlDescription"  value="{{ girl.girlDescription }}">
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
        <footer id="copyright">
          <p style="font-size:14px;text-align:center;font-style:italic;">  
            Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
          </p>        
        </footer>
      </body>
      </html>

项目运行效果如下:

未完待续,下一章节,つづく