node+express学习笔记

node知识点

一些基础知识

node.js的所有api都支持回调函数,可以实现异步编程,并通过回调函数对值进行处理。一般回调函数是作为最后一个参数传入异步操作;其中接收两个参数;一个是错误对象,另一个才是正确数据

const fs = require("fs")
// 测试下同步读取文件数据;会先读取data数据,并通过console打印出来;如果是异步则会输出undefined
let syncData = fs.readFileSync('test.txt') 
console.log(data.toString)
// 体验下异步
fs.readFile('test.txt', function (err, data) {
	if (err) return console.log(err)
	console.log(data.toString())
})

node.js是单进程单线程;但 V8 引擎提供异步执行回调接口,通过这些接口可以处理大量的并发。

node.js的事件机制几乎都采用观察者模式;

事件模块(events)

使用方法和原理

先引入events模块,该模块只提供了EventEmitter对象;通过new 创建一个实例event;
通过event.on(‘xxx’, ()=>{}) 创建一个事件
使用event.emit(xxx) 触发一个事件

/*
const events = require('events') // 只提供一个对象events.EventEmitter
const event = new events.EventEmitter(); // 核心就是事件触发与事件监听器功能的封装
*/
// 也可以写成:
const eventEmitter = require('events').EventEmitter
const event = new eventEmitter (); 
event.on('some_event', function() { 
    console.log('some_event 事件触发1'); 
}); 
event.on('some_event', function() { 
    console.log('some_event 事件触发2'); 
}); // 相同事件可注册多个,触发后依次执行 
setTimeout(() => {
    event.emit('some_event')
}, 2000)

event.addListener('some_event', () => {
	console.log('some_event 事件触发3'); 
})

let listenerList = event.listeners('some_event')
let listenerCount = event.listenerCount('some_event')// 获取监听器数量
console.log(listenerList, listenerCount) // [ [Function], [Function], [Function] ], 3

原理:EventEmitter 的每个事件由一个事件名(some_event)和若干个参数组成。
事件名是一个字符串,通常表达一定的语义。
EventEmitter 支持相同事件中存在若干个事件监听器
当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递

EventEmitter的其他参数

  1. addListener(event, listener)为指定事件添加一个监听器到监听器数组的尾部。
  2. on(event, listener) 为指定事件注册监听器
  3. once(event, listener) 作用同上,只触发一次
  4. removeListener(event, listener) 移除某个事件的某个监听器;
  5. removeAllListeners([event]) 移除所有事件的监听器;也可以指定某个事件
  6. listeners(event) 返回指定事件的监听器数组

Buffer(缓冲区)

作用:js没有二进制数据类型,而处理TCP和文件流时必须使用二进制数据;所以node定义了一个Buffer类来创建一个专门存放二进制数据的缓存区。

创建:

  • Buffer.alloc(size[, fill[, encoding]]) 返回指定大小的Buffe实例,不设置fill,默认填充0
  • Buffer.from(array) 返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
  • Buffer.from(arrayBuffer[, byteOffset[, length]]): 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
  • Buffer.from(buffer): 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
  • Buffer.from(string[, encoding]): 返回一个被 string 的值初始化的新的 Buffer 实例
const buf1 = Buffer.alloc(10);// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf2 = Buffer.from([1, 2, 3]);// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。

写入缓冲区

buf.write(string[, offset[, length]][, encoding])

string - 写入缓冲区的字符串。
offset - 缓冲区开始写入的索引值,默认为 0 。
length - 写入的字节数,默认为 buffer.length
encoding - 使用的编码。默认为 ‘utf8’ 。

返回实际写入的大小,若空间不足写到满后不再写入

const buf = Buffer.alloc(5);
let len = buf.write("test");
console.log("写入字节数 : "+  len); // 写入字节数 : 4

读取文件

buf.toString([encoding[, start[, end]]])

入参:
encoding - 使用的编码。默认为 ‘utf8’ 。
start - 指定开始读取的索引位置,默认为 0。
end - 结束位置,默认为缓冲区的末尾。

encoding: ‘utf8’ ‘ascii’ ‘base64’ ‘hex’

返回:解码缓冲区数据并使用指定的编码返回字符串。

将 Buffer 转换为 JSON 对象

buf.toJSON()

缓冲区合并

Buffer.concat(list[, totalLength])
list - 用于合并的 Buffer 对象数组列表。

totalLength - 指定合并后Buffer对象的总长度。

返回值
返回一个多个成员合并的新 Buffer 对象。

Stream(流)

Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)

读取流中数据

写入流

管道流和链式流

模块系统

作用:可以共享出某文件的变量、方法、构造函数、类。
使用:通过exports.xxx或者module.exports = xxx方法导出(共享);使用require方式引入,不同的导出方法使用时不同

// child.js
function child1() {
	console.log("hello world")
}
exports.child1 = child1 // 导出的第一种
module.exports= child1 // 导出的第二种 也可以module.exports.child1= child1

// parents.js
const child = require("./child.js")
child.child1() // 使用第一种
child() // 使用第二种

注1:exports对于本身是一个变量(对象),它不是module的引用,它是{}的引用,指向module.exports的{}模块。module是一个变量,指向一块内存,exports是module中的一个属性,存储在内存中;exports属性指向{}模块
注2:多次exports.aaa = xxx;会被最后一个覆盖
注3:require加载时是有优先级的,文件系统缓存的模块>原生模块(例:http)>文件加载

全局变量

__filename:正在执行的文件名及其他的绝对路径
__dirname:正在执行的文件名绝对路径

文件系统(fs)

读取文件:
fs.readFile(‘xxx’, (err, data) => {}) //异步读取
const syncData = fs.readFileSync(‘xxx’) //同步读取
打开文件:
fs.open(path, flags[, mode], callback)

path - 文件的路径。
flags - 文件打开的行为。例:r, r+, w, w+等。
mode - 设置文件模式(权限),文件创建默认权限为 0666(可读,可写)。
callback - 回调函数,带有两个参数如:callback(err, fd)。

获取文件信息:

const fs = require('fs');

fs.stat('xxx/fs.js', function (err, stats) {
    console.log(stats.isFile()) //true
    console.log(stats.isDirectory());         //false
})

写入:
fs.writeFile(file, data[, options], callback)file - 文件名或文件描述符。

data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(缓冲) 对象。
options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 , flag 为 ‘w’
callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
关闭:
fs.close(fd, callback)
删除
fs.unlink(path, callback)
创建目录
fs.mkdir(path[, options], callback)
读取目录
fs.readdir(path, callback)
callback - 回调函数,回调函数带有两个参数err, files,err 为错误信息,files 为 目录下的文件数组列表。

删除目录
fs.rmdir(path, callback)

连接数据库

连接mysql

var mysql      = require('mysql'); 
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : '123456',
  database : 'test'
});
 
connection.connect();
 
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

连接MongoDB

var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
 
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
    if (err) throw err;
    var dbo = db.db("runoob");
    var myobj = { name: "菜鸟教程", url: "www.runoob" };
    dbo.collection("site").insertOne(myobj, function(err, res) {
        if (err) throw err;
        console.log("文档插入成功");
        db.close();
    });
});

express

Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,他在node.js基础功能上进行扩充,本质上讲使用express就是为了调用各种中间件。
安装:npm installexpress –g npm install express-generator –g
创建脚手架:express -e projectName

生成的目录:
app.js:项目的主入口,一般都是在这里面做修改,比如新增路由规则等。
bin:项目启动脚本所在目录。比如启动服务的 npm start,其实运行的就是 bin/start 脚本。
public:存放项目的静态文件,比如js、css、img等。
routes:用来存放项目的路由配置。
views:存放项目的模板文件。
node_modules: 项目依赖的node模块,比如各种中间件等。
package.json:项目依赖声明。

bin目录和http模块

其中bin目录是项目启动目录,里面有文件www.js

#!/usr/bin/env node

var app = require('../app');
var debug = require('debug')('myapp:server');
var http = require('http');

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app); // 创建http server

server.listen(port); 
...
...

这里引入了http模块和app.js文件

http模块

http模块主要用于创建http server服务;支持更多特性,不缓冲请求和响应,处理流相关。
var server = http.createServer(): 创建一个server
server.on:绑定事件处理函数
server.listen:监听事件

创建一个服务的简单例子:

var http = require('http');
// 创建http server
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(8080, '127.0.0.1');

app.js文件和path模块的用法

项目的主入口;
app = express()创建一个express实例。我们可以在这个实例中引入中间件,在处理http请求的函数时会一个接一个调用中间件,最终得到我们想要的结果。

每个中间件接收三个参数:request对象(http请求),response对象(http响应),next回调函数(跳到下一个中间件)

如何注册中间件:use方法;例:app.use(logger(‘dev’)); 当收到http请求后,会依次调用(如果有next()的话)

指定变量的值:set方法,例:app.set(‘views’, path.join(__dirname, ‘views’));

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');// 这是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
var logger = require('morgan'); // 在控制台中,显示req请求的信息
var bodyParser = require('body-parser');//node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。
var indexRouter = require('./routes/index'); // 引入路由主文件
var usersRouter = require('./routes/users'); // 引入关于用户的路由文件

var app = express(); // 创建一个express实例
var cors = require('cors')
app.use(cors()) // 解决跨域问题方法一
// view 处理
app.set('views', path.join(__dirname, 'views')); 
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// 设置跨域 解决跨域问题方法二
app.all('*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
  res.header('X-Powered-By', '3.2.1')
  res.header('Content-type', 'application/json;charset=utf-8')
  next()
})

app.use('/', indexRouter); // 页面路由处理,当首页时处理index.js中的路由
app.use('/users', usersRouter);

path模块的用法

  • ath.join([path1][, path2][, …]) 连接路径;正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是"\"
    例:上图app.set(‘views’, path.join(__dirname, ‘views’));
    __dirname为正在执行文件的文件夹的绝对路径;
    在__dirname后面接入views路径名

  • path.resolve([from …], to) 将 to 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径

routes目录下index.js 和mysql、url模块

在app.js中引入了路由级中间件的文件,包含routes中的index.js和users.js文件
其中需要注意的有app.get和router.get的区别
require(‘express’).get(’/’, (res,req,rext)=> {})…是应用级中间件,
而require(‘express’).Router().get(’/’, (res,req,rext)=> {})是路由级中间件。一般项目用他

const express = require('express')
const app = express()
const router = express.Router()
var express = require('express');
var router = express.Router();
var URL = require('url');

var mysql      = require('mysql'); //加载mysql模块
var connection = mysql.createConnection({ // 创建连接设置参数
    host     : 'localhost',
    user     : 'root',
    password : 'tgf123456',
    database : 'nodedemo'
    });
connection.connect(); // 连接到mysql服务器
var  sql = 'SELECT * FROM stude';

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
router.get('/index', function(req, res, next) {
  res.render('index', { title: 'Expressindex' });
});
router.get('/add', function(req, res, next) {
    //解析请求参数
    var params = URL.parse(req.url, true).query;  
    //查
    connection.query(sql,function (err, result) { // 插入sql语句;返回错误信息,查询结果
        if(err){
          console.log('[SELECT ERROR] - ',err.message);
          return;
        }
        console.log(params.id);
        //把搜索值输出
       res.send(result);
    });
});
router.all('*', (req, res, next) => {
  res.json('请求错误')
})
module.exports = router;

mysql模块

如上代码;

//加载mysql模块
var mysql      = require('mysql'); 
// 创建连接设置参数
var connection = mysql.createConnection({ 
    host     : 'localhost',
    user     : 'root',
    password : 'tgf123456',
    database : 'nodedemo'
    });
// 连接到mysql服务
connection.connect(); 
// 查询
let sql = 'select * from stude'
router.get('/search',function(req,res,next){
	connection.query(sql, (err, result) => {res.send(result)})
});


通过connection.query(sql, (err, result) =>{})插入sql语句并进行返回报错信息或者查询结果
传入的sql语句:

除了普通查询外,还有占位符模型
例:let sql = ‘select * from heroes where id < ?’; 有一个占位符
可写为:connection.query(sql, 10, (err, result) =>{})

多个占位符的情况:传递数组
let sql = ‘select * from heroes where id < ? and sex = ?’;
connection.query(sql, [10, 30], (err, result) =>{})

如果一次执行多个sql语句,用;隔开
例:let sql = select id,name from students; select * from boy;;

增加数据时可以用set ?提供键值对
例:const addSql = ‘INSERT INTO stude set ?’;
let addSqlParams = {
name: “zhangsan”,
age: 12,
number: 100
}
connection.query(addSql,addSqlParams,(req, res) => {})

mysql使用优化

在使用mysql模块时可以使用连接池的方法

const pool  = mysql.createPool({
        host: 'localhost', 
        user: 'root',
        password: 'tgf123456',
        database:'nodedemo', // 前面建的user表位于些数据库中
    });
// 接口中使用时用pool.getConnection连接
let sql = 'select * from stude'
router.get('/search',function(req,res,next){
	pool.getConnection((err, connection) => {
		connection.query(sql, (err, result) => {}) // 正常用
		connection.release(); // 释放连接
	})
});

在开发web应用程序时,连接池是一个很重要的概念。建立一个数据库连接所消耗的性能成本是很高的。在服务器应用程序中,如果为每一个接收到的客户端请求都建立一个或多个数据库连接,将严重降低应用程序性能。
因此在服务器应用程序中通常需要为多个数据库连接创建并维护一个连接池,当连接不再需要时,这些连接可以缓存在连接池中,当接收到下一个客户端请求时,从连接池中取出连接并重新利用,而不需要再重新建立连接。
所以代替var connection = mysql.createConnection({xxx})的连接方式
其中mysql.createPool的两个入参分别是createConnection方法中可以使用的各种属和数据库连接的必要参数;也可只传后者.

其中,connection.release()是归还到连接池;connection.destroy()当连接不在需要,从连接池中移除;connection.end()当连接池不在需要时,关闭连接池

url模块

  1. url.parse(urlString,boolean,boolean) 将一个url的字符串解析并返回一个url的对象
    例:var params = url.parse(req.url, true).query;
    第一个参数url:传入请求的url地址
    第二个参数传入布尔值(选填):默认false,为true时返回的url对象中,query的属性为一个对象
    第三个参数传入布尔值(选填):默认false,为true时不用指定协议,即请求时不用加http
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?name=%E5%94%90%E5%A4%A7&age=17&number=100',
  query: [Object: null prototype] { name: '唐三', age: '17', number: '100' },
  pathname: '/add',
  path: '/add?name=%E5%94%90%E5%A4%A7&age=17&number=100',
  href: '/add?name=%E5%94%90%E5%A4%A7&age=17&number=100'
}
  1. url.format(urlObj): 将传入的url对象编程一个url字符串并返回
let newUrl = url.format({
    protocol:"http:",
    host:"localhost:3000",
    port:"3000"
});
console.log(newUrl) // 'http://localhost:3000'
  1. url.resolve(from,to): 返回一个格式为"from/to"的字符串,感觉是切换路由,将传入的from的host:port和to(要去的)的用"/"符号进行拼接,并返回
    例:search替代了原来的add接口
console.log(url.resolve("http://localhost:3000/add", "search"));
// http://localhost:3000/search;
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Node Express后台管理项目需要掌握Node.jsExpress框架的基础知识。首先,需要了解Node.js是什么,它是一个基于JavaScript的运行时环境,可以用来构建服务器端应用程序。然后,需要学习Express框架,它是一个基于Node.js的Web应用程序开发框架,可以简化服务器端应用程序的开发流程。 学习Node Express后台管理项目的关键步骤包括:创建项目,配置路由,处理请求和响应,连接数据库,实现用户认证和授权,设计并实现界面等。需要掌握Express框架的常用中间件、路由和控制器的使用,以及如何与数据库进行交互,如何实现用户认证和授权等。 在学习过程中可以通过阅读官方文档、参考教程和实际操作来深入理解Node Express后台管理项目的开发流程。另外,还可以利用开源项目进行学习和实践,例如使用GitHub上的相关项目来学习项目结构和代码规范,提高自己的编码能力。 学习Node Express后台管理项目还需要注重实践,通过自己动手实现项目功能来加深理解和掌握技能。同时,要注重与他人交流和合作,可以参加相关的技术社区或线下活动,与他人交流经验和学习成果,不断提升自己的技术水平。 总之,学习Node Express后台管理项目是一个系统全面的学习过程,需要持续不断地学习、实践和与他人交流,才能成为一名优秀的后台管理项目开发人员。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值