My Little World

learn and share


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于
My Little World

最短路径

发表于 2017-04-02

网图:两个顶点经过的边上权值之和最少的路径
非网图:两个顶点之间经过的边数最少的路径
源点:路径起始的第一个顶点
终点:最后一个顶点
shortestpath1

迪杰斯特拉(Dijkstra)算法

一个顶点到所有顶点的最短路径
主要思路:一步步求出它们之间顶点的最短路径,过程中都是基于已经求出的最短路径的基础上,求得更远顶点的最短路径
编程思路:类似于最小生成树普里姆算法
代码链接

佛洛依德(Floyd)算法

扩展版迪杰斯特拉(Dijkstra)算法,求图中所有结点到所有结点的最大路径,结果由二维数组展现
代码链接
shortestpath2

My Little World

最小生成树

发表于 2017-03-30

图的各结点连线间存在权值,寻找一种访问路径,使得访问各结点最终的路径的权值和最小,
最终访问路径和结点形成树的结构,即最小生成树

普里姆算法

plim
主要思路:研究对象为结点,以某顶点为起点,逐步找各个顶点上最小权值的边来构建最小生成树
编程思路:新建一数组,初始化为起点(最小生成树的根结点)在邻接矩阵所在行的权值
找到该组权值最小值,最小权值下标即要选择路径的终点,同时也是接下来要比较的邻接矩阵权值行的行号,
将该最小权值置0,然后将新建数组与矩阵权值行比较,
相同位置,矩阵行若小于新建数组值,就将新建数组值替换为矩阵行的值,
再次寻找新建数组中的最小权值,重复以上步骤
代码链接

克鲁斯卡尔算法

kluse
主要思路:研究对象为边,将边集数组从小到大排序,依次取边集数组的元素,判断边与边是否形成环路,不会形成则选择该边构建最小树
代码链接

My Little World

关于commonjs、MVC、模板引擎

发表于 2017-03-21

commonjs理解

是一种编写API的标准,根据该标准写的API可以在任何支持JavaScript的环境中使用,尤其是可以满足服务端的应用
四个个关键词
modules:模块,外部用 JavaScript 封装,具有对外接口并有一定功能作用的一个文件
packages:包,多个module的集合,相当于提供了一些固定接口的函数库,提供更高层的的抽象
exports:模块对外的接口对象,在模块文件中编写的功能函数作为它的属性函数,不同写法,使用规则不一样
require:当我们要使用某个模块时,用来获取/加载模块接口的对象,获取模块的 exports 对象。

定义模块与使用

方式一:
定义

1
2
3
4
5
6
7
8
9
function Change(a) {
a = 100;
console.log(a);
};
module.exports = Change;
//定义子函数
Change.childchange = function childchange(val){
console.log(val+20);
}

使用

1
2
3
4
5
var change = require('../models/testchange.js');
var a=10;
var aa=change(a);//100
console.log(a,aa);//10,100
change.childchange(a);//30

方式二:
定义
同时定义多个同级函数

1
2
3
4
5
6
7
8
exports.Change = function(a){
a = 100;
console.log(a);
return a;
}
exports.add = function(a,b){
return a+b;
}

使用

1
2
3
4
5
6
var change = require('../models/testchange.js');
var a=10;
var aa=change.Change(a);//100
console.log(a,aa);//10 100
var b=change.add(a,20);
console.log(b);//30

MVC

MODEL-VIEW-CONTROLL,模型-视图-控制器,是一种软件的设计模式
模型:对象及其数据结构的实现,通常包含数据库的操作
视图:表示用户界面,在网站中通常就是HTML的组织结构
控制器:用于处理用户请求和数据流,复杂模型,将输出传递给视图
noun2

模板引擎

是一个生成HTML的工具
其功能是将页面模板和要显示的数据结合起来生成HTML页面
既可以运行在服务端又可以运行在客户端,
大多数时候它都在服务器端直接被解析为HTML,解析完后再传输给客户端
有时候也可以运行在客户端,即浏览器中
MVC架构中,模板引擎包含在服务器端,流程如下:
控制器得到用户请求后,从模型(原来页面)获取数据,调用模板引擎
模板引擎以数据(经过后台处理,要传递给客户端的)和页面模板为输入,生成HTML页面
返回给控制器,由控制器交会回给客户端
noun1

My Little World

mongoDB使用

发表于 2017-03-19

启动

cmd到mongoDB的bin文件夹,执行
mongod –dbpath data文件夹路径(例:D:\MongoDB\data)//运行
再打开一个cmd,同样切目录到bin文件夹下,执行
mongo //连接到数据库

命令

基础命令

use dbname //名为dbname的数据库若存在就将当前数据库切换到该数据库,若不存在,则新建该数据库并切换至该数据库
db //查看当前数据库
show dbs //查看所有数据库,新建的库,在插入数据后才会显示
db.dropDatabase() //删除当前数据库,但用db查看当前库,还是被删的这个库
db.tablename.drop() //删除数据库中名为tablename的集合
db.tablename.insert({“key”:”value”}) //创建名为objectname的表(对象),并插入数据,批量操作时可以直接在shell里面写for循环
show tables //查看该库中所有表(对象)
db.tablename.find() //在仓库中查找名为tablename的表,如果有就会将表中内容打印出来
db.tablename.find({“key”:”value”}) //在tablename表中查找具体数据,注意格式
mongodb1
db.tablename.update({查找值},{替换值}) //将查找值所在的集合替换为替换值
mongodb2
db.tablename.remove({查找值}) //删除查找值所在对象的全部数据,若为空,则将整表清空
mongodb3

条件查找

1.比较查询
将查找条件放在value部分,用{}括起来
下图查询条件为age大于”$gt”22, 大于等于”$gte”22, 小于”$lt”22, 小于等于”$lte”22, 不等于”$ne”20,等于20的查询格式
mongodb4
使用正则表达式匹配时同样将正则表达式放在value的位置,而且不用{}或者””包括,直接/开始/结束
2.逻辑查询
下图查询条件分别为且,或者$or,在氛围内$in,不在范围内$nin
mongodb5

局部修改

$inc 属性不存在就创建并赋值,如果存在,就在原来的基础上增加要修改的值
$set 仅修改

1
2
3
4
5
6
7
8
9
10
11
12
13
> db.person.find()
{ "_id" : ObjectId("58ccdcb002efa48d7589f2ae"), "name" : "jack", "age" : 20 }
{ "_id" : ObjectId("58ccdcb502efa48d7589f2af"), "name" : "joe", "age" : 25 }
{ "_id" : ObjectId("58ccdcd302efa48d7589f2b0"), "name" : "mark", "age" : 15 }
> db.person.update({"name":"jack"},{$inc:{"age":10}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.person.update({"name":"mark"},{$set:{"age":10}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.person.find()
{ "_id" : ObjectId("58ccdcb002efa48d7589f2ae"), "name" : "jack", "age" : 30 }
{ "_id" : ObjectId("58ccdcb502efa48d7589f2af"), "name" : "joe", "age" : 25 }
{ "_id" : ObjectId("58ccdcd302efa48d7589f2b0"), "name" : "mark", "age" : 10 }
>

特殊情况:update的第一个参数不存在,即查找值不在person中,可以如下设置,将其新增
db.person.update({“name”:”jackson”},{$inc:{“age”:10}},true)
注意:update默认仅更新匹配得到的第一个集合,如果想更新全部匹配得到的结果,
可以将第四个参数设为true

数据处理

1.计数
db.person.count() //获取person中数据条数
db.person.count({“age”:20}) // 获取person中age等于20的数据条数
2.统计
db.person.distinct(“age”) //获取person中所有age的值,重复的值只取一次
3.分组
db.person.group({
“key”:{“age”:true},//按age分组,age相同的分一组
“initial”:{“person”:[]}, //分组内容
“$reduce”:function(cur,prev){ //符合分组条件,将该条数据放入该组集合中,cur指当前处理的该条数据,prev指上次函数的累计对象,第一次为initial的值。
prev.person.push(cur.name);
},
“finalize”:function(out){//将一条数据划分到一组后执行的处理
out.count = out.person.length;
},
“condition”:{“age”:{$lt:25}}//分组条件,对什么样的数据进行分组
})
4.映射
通过map对集合进行分组,通过reduce对分组结果进行处理,理解为复杂的重组处理,最后会生成一个全新的集合

1
2
3
4
5
6
7
8
9
10
11
12
var map = function(){
emit(this.name,{count:1}); //集合按照name分组,分组内容均为{count:1}
}
var reduce = function(key,value){ //对分组结果进行处理
var result = {count:0};
for(var i = 0;i<value.length;i++){
result.count +=value[i].count;
}
return result;
}
db.person.mapReduce(map,reduce,{"out":"collection"})
db.collection.find()

5.循环处理
可以将集合赋值给一个变量然后进行循环处理,
var list = db.person.find();
list.forEach(function(x){
print(x.name):
})

6.可以多操作查询
对person集合数据按name排序然后分页
var single=db.person.find().sort({“name”,1}).skip(2).limit(2);

7.索引查询
建立索引:
db.person.ensureIndex({“name”:1}) //建立按照name进行排序的索引,1为升序,-1为降序
db.person.ensureIndex({“name”:1},{“unique”:true}) //建立唯一索引,集合中不能出现重复键值对
db.person.ensureIndex({“name”:1,”birthday”:1}) //组合索引
查询优化器做出的选择往往是最优的,因为我们做查询时,查询优化器会使用我们建立的这些索引来创建查询方案,
如果某一个先执行完则其他查询方案被close掉,这种方案会被mongodb保存起来,当然如果非要用自己指定的查询方案,这也是可以的,在mongodb中给我们提供了hint方法让我们可以暴力执行。
db.person.find({“name”:”jack”,”birthday”:”1998-3-2”}).hint({“name”:1,”birthday”:1})

删除索引:
db.person.dropIndexes(“name_1”)

主从复制

将数据库数据复制到多台服务器上,防止因为一台服务器死机而导致数据无法使用的问题出现
将安装文件复制到其他磁盘上,模拟不同的服务器
启动H盘上的mongodb,把该数据库指定为主数据库
H:\mongoDB\bin>mongod –dbpath H:\mongoDB\data –master
启动D盘上的mongodb,把该数据库指定为从属数据库
D:\mongoDB\bin>mongod –dbpath D:\mongoDB\data –port 8888 –slave –source=127.0.0.1:27017
更换端口为8888,source表示主数据库地址
2017-03-20T10:12:17.424+0800 I REPL [replslave] syncing from host:127.0.0.1:
27017
然后分别打开主shell(mongo 127.0.0.1:27017)和从shell(mongo 127.0.0.1:8888)查看所有集合
show dbs
因为从服务器上的数据库是不允许进行读写操作,所以从shell中会报错
mongodb7
解决,先执行:rs.slaveOk()
现在主shell中更改数据,在从shell中查看,看是否进行了同步
但有可能因为服务连接状态问题导致数据内容不同
mongodb8

集群

不设定特定主数据库,如果哪个数据库死机了,集群就会推选一个从属数据库作为主数据库顶上,实现自动修复的效果
1.建立集群,命名集群名为shopex,replSet让服务器知道shopex下有端口为3333的另一个数据库服务器
新打开cmd
H:\mongoDB\bin>mongod –dbpath H:\mongoDB\data –port 2222 –replSet shopex/127.0.0.1:3333
2.打开端口为3333的另一个数据库服务器
新打开cmd
D:\mongoDB\bin>mongod –dbpath D:\mongoDB\data –port 3333 –replSet shopex/127.0.0.1:2222
3.在admin集合中初始化“副本集”
新打开cmd,开启shell
H:\mongoDB\bin>mongo 127.0.0.1:2222/admin

1
2
3
4
5
6
7
8
9
10
11
12
13
> db.runCommand({"replSetInitiate":{
... "_id":"shopex",
... "members":[
... {
... "_id":1,
... "host":"127.0.0.1:2222"
... },
... {
... "_id":2,
... "host":"127.0.0.1:3333"
... }
... ]}})
{ "ok" : 1 }

4.设置仲裁服务器
新打开cmd,开启服务
D:\mongoDB\bin>mongod –dbpath F:\mongoDB\data –port 4444 –replSet shopex/127.0.0.1:2222
开启shell,设置及产看结果
H:\mongoDB\bin>mongo 127.0.0.1:2222/admin
shopex:PRIMARY> rs.addArb(“127.0.0.1:4444”)
{ “ok” : 1 }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
shopex:PRIMARY> rs.status()
{
"set" : "shopex",
"date" : ISODate("2017-03-20T05:55:12.742Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 1,
"name" : "127.0.0.1:2222",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 596,
"optime" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-03-20T05:55:07Z"),
"electionTime" : Timestamp(1489989026, 1),
"electionDate" : ISODate("2017-03-20T05:50:26Z"),
"configVersion" : 2,
"self" : true
},
{
"_id" : 2,
"name" : "127.0.0.1:3333",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 296,
"optime" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1489989307, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-03-20T05:55:07Z"),
"optimeDurableDate" : ISODate("2017-03-20T05:55:07Z"),
"lastHeartbeat" : ISODate("2017-03-20T05:55:11.766Z"),
"lastHeartbeatRecv" : ISODate("2017-03-20T05:55:10.786Z"
),
"pingMs" : NumberLong(0),
"syncingTo" : "127.0.0.1:2222",
"configVersion" : 2
},
{
"_id" : 3,
"name" : "127.0.0.1:4444",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 44,
"lastHeartbeat" : ISODate("2017-03-20T05:55:11.765Z"),
"lastHeartbeatRecv" : ISODate("2017-03-20T05:55:07.948Z"
),
"pingMs" : NumberLong(0),
"configVersion" : 2
}
],
"ok" : 1
}

现在如果关掉2222端口服务器,再打开,在执行rs.status(),可以看到2222的“stateStr”变成”SECONDARY”
“3333”的变成”PRIMARY”
相关链接

My Little World

开发小结

发表于 2017-03-15

对于路由的理解

1
2
3
官方定义:
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下: app.METHOD(path, [callback...], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。

当浏览器向服务器发过来一个http请求时,会携带请求路径和请求方法,服务器根据发过来的路径和请求方法进行匹配,二者都匹配的话,就执行对应的回调函数
请求的目的在客户端看来可能多种多样,比如单纯的访问页面,重新获取页面数据,向后台传递数据,但是在服务端看来都是一样的处理方法,匹配路径和方法,进行回调函数,
即通过匹配执行相应的动作,比如
客户端想访问一个页面,回调函数就执行渲染页面的操作
客户端要传递数据给数据库,回调函数就获取传递的数据然后给到数据库
作用就像一个指南针,根据客户端不同的请求,执行不同的操作
但涉及到的具体操作(数据处理)可能会通过其他文件的处理函数来实现
官方文档

对于中间件的理解

1
2
3
4
5
6
7
8
官方定义
中间件(Middleware) 是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。
中间件的功能包括:
执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

粗浅的理解为功能处理函数,比如路由匹配里的回调函数,根据功能和使用方式不同分成多种
1.应用级中间件, app.use() 和 app.METHOD()的回调函数
2.路由级中间件,var router = express.Router(), router.use() 或 router.VERB() 的回调函数
3.错误处理中间件,进行错误处理的的函数,参数与其他不同
4.内置中间件, express.static
5.第三方中间件,通过npm安装的模块,即我们使用的模块也算是中间件
官方文档

My Little World

对于一些模块的探究

发表于 2017-03-15

express-session

用来提供会话支持,获取用户的会话对象,用来维护用户相关信息
当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session对象,生成一个类似于key,value的键值对, 然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带key(cookie),找到对应的session(value)。 客户的信息都保存在session中。
当客户访问其他页面时,可以判断客户的登录状态,做出提示,相当于登录拦截。
session可以和Redis或者数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)丢失。

常用参数:

secret: 一个String类型的字符串,作为服务器端生成session的签名。
name: 返回客户端的key的名称,默认为connect.sid,也可以自己设置。
resave: (是否允许)当客户端并行发送多个请求时,其中一个请求在另一个请求结束时对session进行修改覆盖并保存。

默认为true。但是(后续版本)有可能默认失效,所以最好手动添加。

saveUninitialized: 初始化session时是否保存到存储。默认为true, 但是(后续版本)有可能默认失效,所以最好手动添加。

cookie: 设置返回到前端key的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }。

一些方法:

Session.destroy():删除session,当检测到客户端关闭时调用。

Session.reload():当session有修改时,刷新session。

Session.regenerate():将已有session初始化。

Session.save():保存session。

connect-flash

官方解释
The flash is a special area of the session used for storing messages. Messages are written to the flash and cleared after being displayed to the user. The flash is typically used in combination with redirects, ensuring that the message is available to the next page that is to be rendered.

即一个在session中存放临时信息的地方,显示给用户后,在渲染下一个页面前被清空

函数用法:

(1)如果传入的参数多于两个,那么首先获取第二个以及以后的参数,然后对第二个以后的参数进行format操作,最后把数据封装到req.session.flash中,同时返回
req.flash(‘info’, ‘email has been sent to %s.’, userName);
(2)如果传入的第二个参数是一个数组,那么把这个数组每一个元素封装到req.session.flash中,然后返回特定type的数据的长度
(3)如果仅仅传入了type则返回指定类型的数据,并把数据从req.session.flash中删除

1
2
3
req.flash('info', 'email re-sent');
req.flash('info');// => ['email sent', 'email re-sent']
req.flash('info');// => []这时候info已经清空了

(4)如果用户没有传入任何参数那么返回的原来的局部变量保存到的req.session.flash对象,清空req.session.flash域

实际使用:

安装

1
2
$ npm install express-session //flash放在session中
$ npm install connect-flash

配置

1
2
3
4
5
6
7
8
9
10
var flash = require('connect-flash');
var session = require('express-session');
app.use(session({ //一些参数配置
secret: params1,
key: params2,
cookie: {maxAge: 60000},
resave: false,
saveUninitialized: true
}));
app.use(flash());

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
router.post('/login', function(req, res, next) {
User.get(req.body.username,function(err,user){
if(!user || user.name === ''){
req.flash('error','用户不存在');
return res.redirect('login');
}
if(req.body.password != user.password){
req.flash('error','密码不对');
return res.redirect('login');
}
req.flash('info','登录成功');
res.redirect('login');
})
});

一般和redirect一起使用,保证在渲染下一个页面的时候数据可用

My Little World

搭建博客步骤

发表于 2017-03-12

搭建

如果全局安装express 使用npm install -g express 语句安装后,无法使用express命令
则先执行npm install express-generator -g
express在4.0之后,需要安装the executable(执行器express-generator)才能执行express命令
express –view=ejs microblog //在当前文件夹创建文件夹microblog,并在里面部署express
cd microblog //进入microblog
npm install //安装nodejs包
DEBUG=microblog:* npm start //运行
npm install -g supervisor //安装supervisor,监视代码改动
supervisor ./bin/www //运行,会提示输入rs重新开始,输入’rs’回车即可,
//这里就不用每次改完都去手动中断进程再重新开始

路由初步配置

匹配

打开app.js文件
var index = require(‘./routes/index’); //引入不同访问路径的回调函数所在文件
app.use(‘/‘, index); //为回调函数配置访问路径

如果要建立分支路径,可以在回调函数文件中配置相应分支路径的回调函数
假如我想访问http://localhost:3000/users/111 和 http://localhost:3000/users/id/111
首先在app.js中配置

1
2
var users = require('./routes/users');
app.use('/users', users);

然后配置routes路径下的users.js

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/:id', function(req, res, next) {
res.send('USER:'+req.params.id);
});

router.get('/id/:id', function(req, res, next) {
res.send('USERID:'+req.params.id);
});

module.exports = router;

注意路径参数id的获取,在app.js配置时是访问路径的共有前缀,在users.js中获取的是分支前缀
深入链接

控制权转移

express 处理路由规则时,会优先匹配先定义的陆游规则,后面的规则被屏蔽
通过调用回调函数的第三个参数next,可以将控制权转移到后面的规则
即执行完先定义的规则后会继续执行后面定义的规则
node1

手动安装片段视图

由于网站中多页面head和footer相同,所以要建立模板文件,然后让其他页面文件来来填充基于这种处理方法
express 4.x需要手动安装partials
npm install express-partials
在app.js中注册
var partials = require(‘express-partials’);
app.use(partials());

引入bootstrap 和 JQuery

从http://twitter.github.com/bootstrap/下载bootstrap.zip,
将 img 目录复制到工程 public 目录下,
将 bootstrap.css、bootstrap-responsive.css 复制到 public/stylesheets 中,
将 bootstrap.js 复制到 public/javascripts 目录中,
然后从http://jquery.com/下载一份最新版的 jquery.js 也放入 public/javascripts 目录中。

界面

用.ejs文件当html文件,
ejs 的标签系统只有以下3种标签。
 <% code %>: JavaScript 代码。
 <%= code %>:显示替换过 HTML 特殊字符的内容。
 <%- code %>:显示原始 HTML 内容。
新建layout.ejs 做模板文件 ,调整index.ejs内容做首页填充内容,访问 http://localhost:3000/ 查看效果

MongoDB 数据库

安装

选用 MongoDB 作为网站的数据库系统
在http://dl.mongodb.org/dl/win32/x86_64 可下载安装包
遇到该步骤时,
mongodb.png
选择custom可以自定义安装路径
安装完成后,在bin所在的文件夹,与bin同级建立data文件夹,然后cmd到bin文件夹,执行
mongod –dbpath data文件夹路径(例:D:\MongoDB\data)
执行完最后一行出现:
2017-03-12T13:16:29.286+0800 I NETWORK [thread1] waiting for connections on por
t 27017
浏览器输入 http://localhost:27017/ 可以看到显示信息为
It looks like you are trying to access MongoDB over HTTP on the native driver port.
说明安装完成

使用

修改package.json,dependencies中增加 “mongodb”: “>= 0.9.9”
npm install //更新依赖模块
在与app.js同级目录下新建settings.js,内容如下:

1
2
3
4
5
module.exports = {
cookieSecret: 'microblogYooHannah',
db: 'microblog',
host: 'localhost',
};

新建models文件夹,并在里面新建文件db.js,内容如下:

1
2
3
4
5
var settings = require('../settings'),
Db = require('mongodb').Db,
Connection = require('mongodb').Connection,
Server = require('mongodb').Server;
module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {}), {safe: true});

修改package.json,dependencies中增加 “connect-mongo”: “>= 0.1.7”
npm install更新依赖模块
修改app.js

1
2
3
4
5
6
7
8
9
var MongoStore = require('connect-mongo');
var settings = require('./settings');

app.use(express.session({
secret: settings.cookieSecret,
store: new MongoStore({
db: settings.db
})
}));

由于session不再绑定在express上,这里会报错,所以要单独安装session
npm install express-session
修改app.js

1
2
3
4
5
6
7
8
9
10
11
var session    = require('express-session');
var MongoStore = require('connect-mongo')(session);
var settings = require('./settings');


app.use(session({
secret: settings.cookieSecret,
store: new MongoStore({
url: 'mongodb://localhost/db'//链接数据库地址
})
}));

如出现错误:
MongoError: failed to connect to server [localhost:27017] on first connect
可能是没有运行刚才安装的MongoDB,这时要回到cmd,执行
mongod –dbpath data文件夹路径(例:D:\MongoDB\data)
如出现以下提醒:
express-session deprecated undefined resave option;
express-session deprecated undefined saveUninitialized option;
则补充上这两个配置参数

1
2
3
4
app.use(session({
resave: false, //添加 resave 选项
saveUninitialized: true, //添加 saveUninitialized 选项
}));

注册页面

在view中新建reg.ejs,内容如下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<form class="form-horizontal" method="post">
<fieldset>
<legend>用户注册</legend>
<div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="input-xlarge" id="username" name="username">
<p class="help-block">你的账户名称,用于登录和显示。 </p>
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">口令</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password" name="password">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password-repeat">重复输入口令</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password-repeat" name="password-repeat">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">注册</button>
</div>
</fieldset>
</form>

在app.js和routes/index中增加访问路径和响应函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//app.js
var router = require('./routes/index');//路由
var app = express();
app.use('/', router);
app.use('/reg',router );

//routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: '首页' });
});

router.get('/reg', function(req, res, next) {
res.render('reg', { title: '用户注册' });
});

router.post('/reg', function(req, res) {
//检验用户两次输入的口令是否一致
if (req.body['password-repeat'] != req.body['password']) {
req.flash('error', '两次输入的口令不一致');
return res.redirect('/reg');
}
//生成口令的散列值
var md5 = crypto.createHash('md5');
var password = md5.update(req.body.password).digest('base64');
var newUser = new User({
name: req.body.username,
password: password,
});
//检查用户名是否已经存在
User.get(newUser.name, function(err, user) {
if (user)
err = 'Username already exists.';
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
//如果不存在则新增用户
newUser.save(function(err) {
if (err) {
req.flash('error', err);
return res.redirect('/reg');
}
req.session.user = newUser;
req.flash('success', '注册成功');
res.redirect('/');
});
});
});
module.exports = router;

响应函数中的User是用户模型,在models中创建user.js,再引入到routes/index
响应函数会出现
1.title is not defined的问题
解决办法就是将views/layout.ejs的title换成locals.title
2.req.flash会报错说req.flash is not a function,则
npm install connect-flash
app.js修改:
var flash = require(‘connect-flash’);
app.use(flash());
这样所有的req就可以使用flash()函数
3.crypto没有被定义
npm install crypto
routes/index.js引入
var crypto = require(‘crypto’);

视图交互

实现不同登录状态下页面呈现不同内容的功能,创建动态视图助手
app.js

1
2
3
4
5
6
7
8
9
10
11
app.use(function(req,res,next){
res.locals.user=req.session.user;

var err = req.flash('error');
var success = req.flash('success');

res.locals.error = err.length ? err : null;
res.locals.success = success.length ? success : null;

next();
});

放在路由配置前面
接下来,修改 layout.ejs中的导航栏部分,为已登入用户和未登入用户显示不同的信息

1
2
3
4
5
6
7
8
9
<ul class="nav">
<li class="active"><a href="/">首页</a></li>
<% if (!user) { %>
<li><a href="/login">登入</a></li>
<li><a href="/reg">注册</a></li>
<% } else { %>
<li><a href="/logout">登出</a></li>
<% } %>
</ul>

在 container 中,<%- body %>之前加入:

1
2
3
4
5
6
7
8
9
10
<% if (success) { %>
<div class="alert alert-success">
<%= success %>
</div>
<% } %>
<% if (error) { %>
<div class="alert alert-error">
<%= error %>
</div>
<% } %>

它的功能是页面通知。

登录登出操作,状态判断;建立微博模型,处理微博发表操作

同样建立连接路由,写响应函数

处理首页登录前后状态

省略步骤可参考书籍
代码详见

My Little World

同步/异步和使用

发表于 2017-03-11

同步/异步

同步读取一个文件

1
2
3
4
5
6
7
8
9
//readfile.js
var fs = require('fs');
var data = fs.readFileSync('file.txt','utf-8');
console.log(data);
console.log('end.');
//执行
$node readfile.js
contents of the file.
end.

异步读取一个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//readfile.js
var fs = require('fs');
fs.readFile('file.txt','utf-8',function(err,data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
})
console.log('end.');
//执行
$node readfile.js
end.
contents of the file.

使用

node的REPL模式

即输入代码回车立即执行的模式
在command prompt中直接输入node进入该模式,连续两次Ctrl+C可退出

监视代码改动

npm install -g supervisor //安装supervisor
supervisor app.js //代替node app.js,修改代码后自动终止进程并重启

包

把文件夹封装为一个模块,即所谓的包,包通常是一些模块的集合,在模块的基础上提供了更高层的抽象,相当于一些固定接口的函数库
包安装:作为工程运行,通过本地安装;如果要在命令行下使用,则使用全局模式安装

My Little World

js理解

发表于 2017-03-11

作用域

不通过花括号来界定,通过函数来定义,

1
2
3
4
if(true){
var somevar = "value";
}
console.log(somevar);//value

在访问未定义的变量或定义了但没有初始化的变量时都会获得undefined

1
2
3
4
5
var scope = "1111";
var f = function(){
console.log(scope); //undefined
var scope = 'f';
}

作用域的嵌套关系在定义时确定,不在调用时确定

1
2
3
4
5
6
7
8
9
10
var scope = "top";
var f1 = function(){
console.log(scope);
};
f1();//top
var f2 = function(){
var scope = 'f2';
f1();
};
f2(); //top

全局作用域是个对象,这个对象叫全局对象,nodejs是global对象,浏览器是window对象,包括
在最外层定义的变量
全局对象的属性
未用var定义直接赋值的变量

闭包

由函数(环境)及其封闭的自由变量组成的集合体,
可以想象成一个容器,里面包括一个函数和它用到的变量,每当想使用一次这个容器里的函数,就将这个容器复制一次给调用者:
1.不通调用者得到的容器相互隔离,没有关系,
2.被复制到调用者的函数,会自己形成一个独立的运行环境,每次调用完会根据变量性质,更新变量值,不会释放变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var generateClosuer = function() {
var count = 0;
var get = function(){
count++;
return count;
}
return get;
}
var counter1 = generateClosuer();
var counter2 = generateClosuer();
console.log(counter1()); //1
console.log(counter1()); //2
console.log(counter2()); //1
console.log(counter1()); //3

对象

上下文对象即this指针,即被调用函数所处的环境,
上下文对象的作用是在一个函数内部引用调用它的对象本身。

1
2
3
4
5
6
7
8
function User(name,url){
this.name = name;
this.url = url;
this.diaplay = function(){
console.log(this.name);
}
}
var someuser = new User('byvoid','http://www.byvoid.com');

创建someuser对象时,构造函数的this指调用它的someuser
函数类型的变量指向这个函数实体的一个引用,在引用之间赋值不会对对象产生复制行为。
我们可以通过函数的任何一个引用调用这个函数,但该函数的上下文即this不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var someuser = {
name:'byvoid',
func: function(){
console.log(this.name);
}
};
var foo = {
name:'foobar'
};
someuser.func();//byvoid
foo.func = someuser.func; //引用someuser.func这个函数实体,其实就是someuser.func的代码内容
foo.func();//foobar this是foo

name = 'global';
func = someuser.func;
func();//global

call/apply

让其他对象调用本对象的方法
A对象名.函数属性名.call(B对象名,函数参数表(逗号隔开)); //B调用A的方法
A对象名.函数属性名.apply(B对象名,函数参数数组);//B调用A的方法

bind

永久绑定函数的上下文,使其无论被谁调用,上下文都是固定的
A对象名.函数属性名.bind(B对象名,函数参数表(逗号隔开));
bind方法返回上下文为B对象的A对象的函数
如果在使用bind时,绑定了参数表,则在调用返回函数时,只需要传入未绑定的参数即可
注意不能重复绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var someuser = {
name:'byvoid',
func:function(){
console.log(this.name);
}
};
var foo = {
name:'foobar'
};
func = someuser.func.bind(foo);
func();//foobar

func2 = func.bind(someuser);
func2();//foobar;

原型

构造函数创建属性
除非必须用构造函数闭包,否则尽量用原型定义成员函数
原型定义的成员是多个实例共享的,因此尽量在构造函数内定义一般成员尤其是对象或数组
原型链

1
2
3
4
5
6
7
8
9
10
11
function Foo(){
}
object.prototype.name = 'my object';
Foo.prototype.name = 'Bar';
var obj = new object();
var foo = new Foo();
console.log(obj.name);//my object
console.log(foo.name);//Bar
console.log(foo.__proto__.name);//Bar
console.log(foo.__proto__.__proto__.name);//my object
console.log(foo.__proto__.constructor.prototype.name);//Bar

typeof

【广发证券nodejs应用](http://slides.com/loskael/node#/)

My Little World

深度广度优先遍历+马踏棋盘算法

发表于 2017-03-07

深度优先遍历/深度优化搜索DFS

Traversal1
右手原则:在没有碰到重复顶点的1情况下,分叉路口始终是向右手边走,没路过一个顶点就做一个记号

主要思路是右手原则,把自己想象成从一个顶点出发的小人,每次选择下一步要走的路径时,就选择右手方向的路径,并给自己即将离开的顶点做一个已经遍历过的标记,直到碰到右手选择的路径将要到达的顶点是已经遍历过的顶点,这时则判断从右手方向开始的路径的终点顶点是否已遍历,若没有遍历,则选择该路径继续往下,若碰到所有路径终点顶点都是已经遍历过的,则沿到达该顶点的路径返回上一个顶点,检查上一顶点的其他路径顶点是否已经遍历,未遍历的话,则沿该路径走下去,即碰到所有路径顶点都遍历过则返回上一顶点,以此类推,直到返回起点顶点

整个图的遍历过程算法上是一个递归的过程,遍历方式上类似于树的前序遍历
Traversal2
看蓝色的路径即顶点遍历过程
A->B->C->D->E->F->G->H (往回走,看红色路径顶点都已遍历过)->G->F->E->D->I->D->C->B->A

编程思路:
遍历图的邻接矩阵,邻接矩阵建立时注意选择是使用右手原则还是左手原则,从起点开始遍历该顶点所在行,便利到非0值且对应的列顶点未访问过就开始遍历该列顶点对应顶点所在的行,同样遍历非0未遍历过的顶点,如果该行所有顶点都遍历过则返回上一顶点继续重复遍历找未遍历的顶点,直到返回起点位置
代码链接

马踏棋盘问题

国际象棋的棋盘为8*8的方格棋盘,现将“马”放在任意指定的方格中,按照“马”走棋的规则将“马”进行移动
要求每个方格只能进入一次,最终使得“马”走遍棋盘64个方格

一个位置最多有八种选择,如下
chess
代码链接

图的广度优先遍历

主要思路:树的层序遍历
结构:队列
原则:右手原则
将复杂的图调整结构为层的形状,从最上一层结点唯一结点出发,入队列
遍历第二层,从与上一层结点相连的右手边的结点开始遍历,先将上一层相连的结点出队列,然后第二层结点入队列
以此类推,即在本层遍历时,先将与将要遍历的结点的上层结点出队列,然后将本层结点入队列,
遍历完一个上层结点的本层连接点,先将上层下一个结点出队列,在将上层下一个节点的本层链接点入队列
出队列顺序即遍历顺序
tug1
选定一个起点结点(A),依次遍历与该结点相连结点(B、F),每个结点遍历完后添加遍历标记,
再依次遍历刚刚遍历过的结点(先B后F)的相连结点(CIG、E),同样遍历完要加标记
以此类推,再遍历C的连接点D,G的连接点H
BreadthMaptraversal2
编程思路:
将每次遍历的结点入队列,每遍历完一层,出一次队列,出队列顺序即遍历顺序
代码链接

1…202122…27
YooHannah

YooHannah

262 日志
1 分类
23 标签
RSS
© 2025 YooHannah
由 Hexo 强力驱动
主题 - NexT.Pisces