Node基础

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 实例 - 锐客网' + '' + '
' + '网站名:
' + '网站 URL:
' + '' + '
' + ''; 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)
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 CONTROLlog file "f:\data\log\mongodb.log" exists; moved to "f:\data\log\mongodb.log.2016-10-20T15-32-46".

说明 mongodb 服务安装成功。启动 mongodb 服务:
F:\mongodb\bin>mongoMongoDB 服务已经启动成功。

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()
  • 向集合中插入数据文档 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、聚合函数
  • 【Node基础】添加基础数据:
    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 } ] }

    推荐阅读