Node
1、process 全局对象,直接用
console.log(process.env); //得到很多系统变量与用户变量
2、接收命令行参数
// 如在命令行输入 node ./index.js 2 3
console.log(process.argv); // [ 'C:\\Program Files\\nodejs\\node.exe','F:\\node-code\\index.js','2','3' ]
3、获取命令行参数数组的 2,3 索引对应的元素并进行相关计算
let num1 = parseInt(process.argv[2]);
let num2 = parseInt(process.argv[3]); // parseInt也ok
let sum = num1 + num2;
//输出(卡顿输出)(定时输出)
console.log('计算中.....');
//2秒后输出
setTimeout(() => {
console.log('结果为:' + sum); // 5
}, 2000);
注意: 以下代码所在的项目路径为 F:/node-code
4、filename/dirname(全局对象)
- __filename 获取当前运行文件的目录,绝对路径
- __dirname 当前运行文件的绝对路径
console.log(__filename); // F:\node-code\index.js
console.log(__dirname); // F:\node-code
5、拼接路径 path.join()
// 引入核心对象
const path = require('path'); // 核心对象 path在node.exe里面
// 3段路径来自不同用户的输入
const myPath = path.join(__dirname, '//one//', '//two//', '//three///');
console.log(myPath); // F:\node-code\one\two\three\
6、根据相对路径,返回绝对路径
// 如 ./abv/efg.js 非要一个绝对路径
const str = './abv/efg.js';
let temp = path.resolve(str);
console.log(temp); // F:\node-code\abv\efg.js
7、解析路径为对象 path.parse()
const path = require('path');
// 接受一段字符串路径
let myPath = path.join(__dirname, 'jack', 'rose', 'mick.txt');
// 解析这个路径为对象,更易于操作
let pathObj = path.parse(myPath);
console.log(pathObj); // { root: 'F:\\', dir: 'F:\\node-code\\jack\\rose', base: 'mick.txt',ext: '.txt',name: 'mick'}
// base可以作为修改文件名,或后缀的方式
pathObj.base = 'mick_die.good';
// 接收路径对象,转换成路径字符串
myPath = path.format(pathObj);
console.log(myPath); // F:\node-code\jack\rose\mick_die.good
8、IO
// I or O?
// I input 计算机来说,就是输入
// O output 计算机来说 ,展现/写入数据就是输出,
9、读取文件 fs.readFile()
//读取文件
// 引入核心对象
const fs = require('fs');
fs.readFile('./a.txt', 'utf8', (err, data) => {
if (err) throw err; // 抛到控制台显示异常信息
// console.log(data);
// 需要获取字符串数据,就可以调用 buffer篮子.toString(编码)函数
// console.log(data.toString('utf8')); 默认urf8可以不传递
console.log(data); // 如在第二个参数传了 utf8 则可以直接打印而无需转译
});
10、编写文件 fs.writeFile()
// 引入核心对象
const fs = require('fs');
fs.writeFile('./a.txt', '我今天赚了2块钱', { flag: 'a' }, err => {
// {flag: 'a'} 则表示是追加模式 如无这个参数 文件每次编写时都会覆盖所有内容重新编写
// window中目录层级超级深的时候,写入会报错
if (err) throw err;
console.log('写文件完成了');
});
// 文件编写追加方式: appendFile('path',data,callback);
fs.appendFile('./a.txt', '我今天赚了1块钱', err => {
if (err) throw err;
console.log('文件追加成功');
});
11、文件的一些其他操作
- stat 获取文件状态
- readdir 读取文件夹数据
- access 判断文件或文件夹是否存在
// 接收命令行参数,根据该目录,读取目录下的所有文件并输出(遍历文件夹)
const path = require('path');
const fs = require('fs');
//引入别人包的入口的文件
// 1: 接收命令行参数 node ./01_read_dir_files.js .//xxx//xxx//xx
// 2: 修正该路径 path.resolve(process.agrv[2]);
let inputPath = path.resolve(process.argv[2]);
// 3: 判断该路径是否存在 fs.access(fs.constants.F_OK)
function testReadFiles(dir) {
try {
fs.accessSync(dir, fs.constants.F_OK); //判断该路径是否存在 同步写法
let state = fs.statSync(dir); // 获取文件的状态
if (state.isFile()) {
//判断是否是文件
console.log(dir);
} else if (state.isDirectory()) {
//判断是否是文件夹
let files = fs.readdirSync(dir); // 读文件
files.forEach(file => {
testReadFiles(path.join(dir, file));
});
}
} catch (e) {
console.log(e);
console.log('该文件或文件夹不存在!');
}
}
// 只判断一次
// fs.accessSync(dir, fs.constants.F_OK);
testReadFiles(inputPath);
12、创建服务器
// 1:引入核心对象http
const http = require('http');
// 2: 用这个东西创建服务器
let server = http.createServer();
// 3: 基于事件, 很多的on('xxx')
server.on('request', (req, res) => {
//不管请求是什么,都返回同一个数据
res.end('xxx');
});
// IP 找计算机, 端口找程序
server.listen(8888, () => {
console.log('服务器启动在8888端口');
});
13、EventEmitter 类
- events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
你可以通过 require("events");来访问该模块。
// 引入 events 模块
var events = require('events');
// 创建 emitter 对象
var emitter = new events.EventEmitter();
// 监听函数
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
// 监听函数
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
// 触发函数
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
// 结果:
// listener1 arg1 参数 arg2 参数
// listener2 arg1 参数 arg2 参数
14、util
- util 是一个 Node.js 核心模块,提供常用函数的集合,用于弥补核心 JavaScript 的功能 过于精简的不足。
// util.inspect
// util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法,通常用于调试和错误输出。它至少接受一个参数 object,即要转换的对象。
var util = require('util');
function Person() {
this.name = 'byvoid';
this.toString = function() {
return this.name;
};
}
var obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj, true));
// Person { name: 'byvoid', toString: [Function] }
// Person {
// name: 'byvoid',
// toString:
// { [Function]
// [length]: 0,
// [name]: '',
// [arguments]: null,
// [caller]: null,
// [prototype]: { [constructor]: [Circular] } } }
// util.isArray(object) 判断是否为数组
util.isArray(new Array()); // true
util.isArray({}); // false
// util.isRegExp(object) 判断是否为正则表达式
util.isRegExp(/some regexp/); // true
util.isRegExp({}); // false
// util.isDate(object) 判断是否为日期
util.isDate(new Date()); // true
util.isDate({}); // false
15、querystring 模块
- querystring 从字面上的意思就是查询字符串,一般是对 http 请求所带的数据进行解析。
- querystring.parse parse 这个方法是将一个字符串反序列化为一个对象。
const querystring = require('querystring'); querystring.parse('name=whitemu&sex=man&sex=women'); /* return: { name: 'whitemu', sex: [ 'man', 'women' ] } */
- querystring.stringify stringify 这个方法是将一个对象序列化成一个字符串,与 querystring.parse 相对。
- querystring.escape escape 可使传入的字符串进行编码
- querystring.unescape unescape 方法可将含有%的字符串进行解码
16、GET/POST 请求
- 获取 GET 请求内容
var http = require('http');
var url = require('url');
http
.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
// url.parse(url, true) 第二个参数为true时解析的 query 为对象 false则为路径
console.log(url.parse(req.url, true));
res.end('打印成功')
})
.listen(3000);
// 在浏览器中访问 http://127.0.0.1:8888/user?name=xiaoming&url=www.baidu.com 然后查看返回结果:
/*
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=xiaoming&url=www.baidu.com',
query:
[Object: null prototype] { name: 'xiaoming', url: 'www.baidu.com' },
pathname: '/user',
path: '/user?name=xiaoming&url=www.baidu.com',
href: '/user?name=xiaoming&url=www.baidu.com'
}
/*
- 获取 POST 请求内容
var http = require('http');
var querystring = require('querystring');
var postHTML =
'Node.js 实例 ' +
'' +
'' +
'';
http
.createServer(function(req, res) {
var body = '';
req.on('data', function(value) {
body += value;
});
req.on('end', function() {
// 解析参数
body = querystring.parse(body);
// 设置响应头部信息及编码
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf8' });
if (body.name && body.url) {
// 输出提交的数据
res.write('网站名:' + body.name);
res.write('
');
res.write('网站 URL:' + body.url);
} else {
// 输出表单
res.write(postHTML);
}
res.end();
});
})
.listen(3000);
express 的使用
- 安装
npm i express -S
- 1:引入 express 第三方对象
- 2:构建一个服务器对象
- 3:开启服务器监听端口
- 4:处理响应
- 在 express 中,保留了原生 http 的相关属性和函数
1、使用 express 开启一个服务
// - 1:引入express第三方对象
const express = require('express'); // 自动逐级向上查找node_modules/express的文件夹-> package.json(main属性) || express的文件夹/index.js
// - 2:构建一个服务器对象
let server = express(); // let server = http.createServer();
// - 3:开启服务器监听端口
server.listen(8888);
// - 4:处理响应
server.use((req, res) => {
// 使用(请求与响应的过程中)
res.end('hello world!!'); // 原生API
});
2、next()的使用
const express = require('express');
let app = express();
app.listen(8888, () => {
console.log('服务器启动在8888端口');
});
// 1: app.use是请求与响应中执行的一件事,按代码顺序来执行 请求路径相同时只会执行第一个 next可以触发下一个
// 2:next() 是放行到下一件事的开关
// 3:如果全next,最终没有end页面数据,框架帮我们处理了
// status:404
// 用户选择性url开头的部分,选择性调用对应的事
app.use('/sucai', (req, res, next) => {
console.log('萝卜');
next(); // 放行开关
});
// 一件事
app.use('/sucai', (req, res, next) => {
console.log('白菜');
next();
});
app.use('/huncai', (req, res, next) => {
console.log('牛肉');
next();
});
app.use('/huncai', (req, res, next) => {
console.log('羊肉');
next();
});
3、router
- 使用步骤
- 1:获取路由中间件对象
let router = express.Router();
- 2:配置路由规则
router.请求方式(URL,fn事)
- fn 中参数有 req,res,next
- 3:将 router 加入到应用
app.use(router)
- 1:获取路由中间件对象
const express = require('express');
let server = express();
// - 1:获取路由中间件对象 let router = express.Router();
let router = express.Router();
// - 2:配置路由规则 router.请求方式(URL,fn事)
router
.get('/login', (req, res) => {
res.end('login page');
})
.get('/register', (req, res) => {
res.end('register page');
});
// - fn中参数有req,res,next
// - 3:将router加入到应用server.use(router)
server.use(router);
server.listen(8888);
4、res 扩展函数
const express = require('express');
let server = express();
// - res.json() 响应数据,最常用 , 返回ajax数据
// - res.redirect() 重定向
// - res.download() 下载
// - res.jsonp() 跨域处理
// - 1:获取路由中间件对象 let router = express.Router();
let router = express.Router();
// - 2:配置路由规则 router.请求方式(URL,fn事)
router
.get('/json', (req, res) => {
res.json([{ name: 'jack' }]); // res.end只能响应string||读文件中的data Buffer
})
.get('/redirect', (req, res) => {
res.redirect('http://www.baidu.com');
})
.get('/jsonp', (req, res) => {
res.jsonp('jack love rose');
})
.get('/download', (req, res) => {
res.download('./app.js'); // 注意文件是如何被下载成功的
// 基于服务器回写的content-type。等头信息
});
// - fn中参数有req,res,next
// - 3:将router加入到应用server.use(router)
server.use(router);
server.listen(8888);
5、使用 art-template 模板引擎
- 下载 express-art-template art-template
- npm i express-art-template art-template -S
- app.js 中配置
- 注册一个模板引擎
-
app.engine('.html',express-art-template);
- 设置默认渲染引擎
app.set('view engine','.html');
- 设置默认渲染引擎
-
- res.render(文件名,数据对象);
- express 这套使用,默认在当前 app.js 同级的 views 目录查找
- 注册一个模板引擎
// ./index.js
const express = require('express');
let server = express();
// / - 注册一个模板引擎
// - app.engine('.html',express-art-template);
// 渲染文件的后缀名(引擎名称)
server.engine('.html',require('express-art-template'));
// 区分开发和生产环节的不同配置
server.set('view options', {
debug: process.env.NODE_ENV !== 'production',
// debug : 不压缩,不混淆,实时保持最新的数据
// 非debug: 压缩/合并, list.html 静态数据不回实时更新(服务器重启才更新)
imports:{
// 数据的导入,和过滤显示的操作
num:1,
reverse:function(str) {
return '^_^' + str + '^_^';
}
}
});
// 配置默认渲染引擎
server.set('view engine','.html'); // 设置模板引擎的类型为html
let router = express.Router();
router.get('/hero-list',(req,res) => {
res.render('list.html',{
heros:[{name:'貂蝉'},{name:'吕布'},{name:'董卓'}]
});
})
server.use(router);
server.listen(8888);
// ./views/list.html
Document
我是英雄列表
{{num}}
// 1
{{reverse('abcde')}}
// '^_^abcde^_^'
{{each heros}}
- {{$value.name}}
// 输出数据
{{/each}}
补充:
// views, 设置放模板文件的目录,比如:
app.set('views', './views'); // 那么渲染的文件就是在这个路径下面找比如渲染index,就是就是找到./views/index.xxx文件
// view engine, 模板引擎,比如:
app.set('view engine', 'jade');
//这个接着上面,渲染文件index.xxx,那根据这个规则最后添加后缀为,index.jade,但是还不能生成html,也就是说,如果不设置这个,那么render的时候就要指定index.jade,而不是index就够了。app.engine的作用就是根据上面解析的文件名,调用相应的引擎,来把这个jade文件生产html文件。
6、next all
// ... 省略部分代码
router
.get('/', (req, res, next) => {
// 假如获取文件
let errorPath = './abc/e.txt';
try {
fs.readFileSync(errorPath);
res.render('index');
} catch (err) {
// throw err; // 给用户看到了异常,太恶心
next(err); // 触发一个具备4个参数的中间件函数
}
})
// 最后一条路由中 判断路由的错误 如果路由错误将触发
.all('*', (req, res) => {
res.send('地址错误,您去首页吧');
});
server.use(router);
// 处理错误(参数位置错误优先) -> 优雅的用户体验
server.use((err, req, res, next) => {
res.send(
'亲爱的用户,您访问的页面,有事儿了,去首页看看?
'
);
});
server.listen(8888);
7、nodemon
- 修改代码自动重启刷新 不需要手动重启
- 安装全局命令行工具
npm i -g nodemon
- 进入到指定目录命令行
nodemon ./xxx.js
- 手动触发重启,在命令行输入 rs 回车
8、静态文件
- Express 提供了内置的中间件 express.static 来设置静态文件如:图片, CSS, JavaScript 等。
你可以使用 express.static 中间件来设置静态文件路径。例如,如果你将图片, CSS, JavaScript 文件放在 public 目录下,你可以这么写:app.use('/public', express.static('public'));
9、路由
var express = require('express');
var app = express();
// 主页输出 "Hello World"
app.get('/', function(req, res) {
console.log('主页 GET 请求');
res.send('Hello GET');
});
// POST 请求
app.post('/', function(req, res) {
console.log('主页 POST 请求');
res.send('Hello POST');
});
// /del_user 页面响应
app.get('/del_user', function(req, res) {
console.log('/del_user 响应 DELETE 请求');
res.send('删除页面');
});
// /list_user 页面 GET 请求
app.get('/list_user', function(req, res) {
console.log('/list_user GET 请求');
res.send('用户列表页面');
});
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {
console.log('/ab*cd GET 请求');
res.send('正则匹配');
});
var server = app.listen(8081, function() {
var host = server.address().address;
var port = server.address().port;
console.log('应用实例,访问地址为 http://%s:%s', host, port);
});
mongodb
在官网下载 mongodb
[mongodb 教程]https://www.mongodb.org.cn为了在任何地方都能使用 mongod 命令 需要配置 mongodb 环境变量 具体配置过程网上搜索
[环境变量配置参考]https://jingyan.baidu.com/article/6525d4b1af0d9bac7d2e941f.html启动 mongodb 服务
mongod --dbpath='./data'
如果出现 waiting for connections on port 27017 就表示启动成功。
- mongodb 常用启动参数
选项 | 含义 |
---|---|
--bind_ip | 绑定服务 IP,若绑定 127.0.0.1,则只能本机访问,不指定默认本地所有 IP |
--port | 指定服务端口号,默认端口 27017 |
--logpath | 指定 MongoDB 日志文件,注意是指定文件不是目录 |
--logappend | 使用追加的方式写日志 |
--dbpath | 指定数据库路径 |
--directoryperdb | 设置每个数据库将被保存在一个单独的目录 |
--serviceName | 指定服务名称 |
--serviceDisplayName | 指定服务名称,有多个 mongodb 服务时执行 |
--install | 指定作为一个 Windows 服务安装。 |
1、将 MongoDB 服务器作为 Windows 服务运行
像上面那样启动 mongodb,发现没办法输入命令行了,这是可以采用打开多个窗口来连接,但这样就太麻烦了,解决办法就是将 MongoDB 服务器作为 Windows 服务运行。
输入以下命令(需要以管理员身份打开命运提示符):
F:\mongodb\bin>mongod --dbpath "f:\data\db" --logpath "f:\data\log\mongodb.log" --serviceName "mongodb" --serviceDisplayName "mongodb" --install
如看到了类似如下输出:
2016-10-20T23:32:46.339+0800 I CONTROL log file "f:\data\log\mongodb.log" exists; moved to "f:\data\log\mongodb.log.2016-10-20T15-32-46".
说明 mongodb 服务安装成功。启动 mongodb 服务:
F:\mongodb\bin>mongo
MongoDB 服务已经启动成功。
2、数据库操作
-
查询有哪些数据库
- 查询数据库:
show dbs;
- 切换数据库:
use 数据库名;
如无这个数据库则自动创建并切换,创建后如果 show dbs 会发现并没有刚刚创建的库,需加入一些数据才能显示 如db.test.insert({"name":"菜鸟教程"})
- 查询数据库:
删除数据库:
db.dropDatabase()
删除当前数据库,默认为 test,你可以使用 db 命令切换数据库删除-
查询当前 db 下有哪些集合
show collections;
在 test 数据库中创建 mycol2 集合:
db.createCollection("mycol2")
在 MongoDB 中,你不需要主动创建集合。当你插入一些文档时,MongoDB 会自动创建集合
> db.mycol2.insert({"name" : "小明"})
> show collections
mycol2
-
删除集合
db.集合.drop()
- 如删除 mycol2 集合
db.mycol2.drop()
- 如删除 mycol2 集合
-
向集合中插入数据文档
db.集合.insert()
或db.集合.save()
- 第一种:
db.mycol2.insert({'name': '小明'})
- 第二种:
db.mycol2.save({'name': '小明'})
- 第一种:
以上实例中 mycol2 是我们的集合名,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。
- 删除集合中的数据文档
db.集合.remove(
, , ) - query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别
如 db.mycol2.remove({'title':'MongoDB'}, 1)
表示删除 mycol2 里满足条件的文档 且只删除一个文档
-
查询集合中的数据文档
db.集合.find()
- 如
db.mycol2.find()
- 如
-
更新集合中的数据文档
db.集合.update()
db.集合名.update({匹配条件对象},{$set:{修改后的对象}});
db.mycol2.update({name:'小明'},{$set:{contry:'印度'}});;
3、条件查询
- db.mycol2.find({name:'小明'}) 查询姓名为小明的学生
- db.mycol2.find({score:{$gt:90}}) 查找成绩大于 90 分的学生 $lt 小于
- db.mycol2.find({score:{$ne:88}}) 查询数学成绩不等于 88 的同学
- db.mycol2.find({score:{$gt:200}}) 查询总分大于 200 分的所有同学
4、分页
db.mycol2.find().skip(3).limit(3);
- db.集合名称.find().跳到 3 显示 3 条
5、排序
db.mycol2.find().sort({key:排序方式});
-
db.mycol2.find().sort({'score':1});
//正数代表升序,负数代表降序
6、模糊匹配
-
db.mycol2.find({name:{$regex:'小'}});
查找集合中的 name 属性有'小'字的数据 -
db.mycol2.find({name:{$regex:'明'}});
查找集合中的 name 属性有'明'字的数据
7、聚合函数
-
添加基础数据:
db.mycol2.save({contry:'中国',name:'小明',score:77});
db.mycol2.save({contry:'中国',name:'小红',score:88});
db.mycol2.save({contry:'中国',name:'小张',score:99});
db.mycol2.save({contry:'美国',name:'jack',score:45});
db.mycol2.save({contry:'美国',name:'rose',score:67});
db.mycol2.save({contry:'美国',name:'mick',score:89});-
db.mycol2.aggregate([{$group:{_id:"$contry",num:{$sum:'$score'}}}])
以 contry 为划分为组 以 score 为计算的总和
结果:
{ "_id" : "美国", "num" : 201 }
{ "_id" : "中国", "num" : 264 }
-
8、联合查询
// 添加数据
db.orders.insert([
{ _id: 1, item: 'almonds', price: 12, quantity: 2 },
{ _id: 2, item: 'pecans', price: 20, quantity: 1 },
{ _id: 3 }
]);
db.inventory.insert([
{ _id: 1, sku: 'almonds', description: 'product 1', instock: 120 },
{ _id: 2, sku: 'bread', description: 'product 2', instock: 80 },
{ _id: 3, sku: 'cashews', description: 'product 3', instock: 60 },
{ _id: 4, sku: 'pecans', description: 'product 4', instock: 70 },
{ _id: 5, sku: null, description: 'Incomplete' },
{ _id: 6 }
]);
db.orders.aggregate([
{
$lookup: {
from: 'inventory', // 要关联的集合
localField: 'item', // 当前的集合的字段
foreignField: 'sku', // 要关联的集合的字段
as: 'inventory_docs' // 返回的字段名
}
}
]);
// 查询结果
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2, "inventory_docs" : [ { "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 } ] }
{ "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1, "inventory_docs" : [ { "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 } ] }