NodeStudy

NODE

官网:NODE

Explanation

Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

由官方定义亦知:Node.js 不是一门语言,也不是类似于Vue、React这些框架,而是一个

能够运行 JS运行环境

Features:

  • 事件驱动
  • 非阻塞 I/O 模型(异步)
  • 轻量和高效
  • 文件操作
  • 网络数据操作(http/https)

Apply:NPM 包管理工具(npm install xxx)

Node 中不存在 BOM & DOM

环境搭建直接去官网下载对应版本即可,不再陈述。

Usage

先来个简单的 NODE 入门

Hello NODE

//	hello.js
console.log('Hello NODE')
//	cd into hello.js directory
node hello.js

// Output
Hello NODE

require

console.log('first')

// 加载执行 a.js,后缀名可省略
require('./a.js')

console.log('last')

// 引入某个对象或者第三方模块
const fs = require('js')

exports & module.exports

var module = {
exports: {
foo: 123,
fun: ...
}
}
return module.exports

// foo.js
module.exports.foo = 123
// 此时会覆盖掉之前的 123
module.exports.foo = function() {
console.log('function')
}

// main.js
const foo = require('/foo')
console.log(foo) // { foo: [Function] }

// 后续官方优化
var exports = module.exports
console.log(exports === module.exports); // true

// 当我们导出单个值时不能直接赋值 exports
exports = 123 // wrong
// because return module.exports,如果我们直接赋值则会使得 exports 指向另一个内存地址而非 module.exports 的内存地址,使得修改并未改动 module.exports

// 如果我们又直接给 module.exports 则原理一样
module.exports = 'hello'
exports.foo = 123
// 此时 require 接收的就是 'hello'

exports.foo = 123
exports.fun = function() {
console.log('function')
}

console.log(foo) // { foo: 123, fun: [Function] }
console.log(foo.foo, foo.fun); // 123 [Function]

// 通常这样使用(以上不理解记住此即可)
module.exports = {
foo: 123,
fun: function() {
console.log('function')
}
}

console.log(foo) // { foo: 123, fun: [Function] }

// require 引入加载也会优先从缓存加载,如果前面已经导入过则不再执行,而是直接拿到导入对象的接口对象,提高运行效率。

require 第三方模块加载规则:

一个项目有且只有一个 node_modules,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包,不会出现有多个 node_modules

  • 模块查找机制
    优先从缓存加载
    核心模块
    路径形式的文件模块
    第三方模块
    node_modules/art-template/
    node_modules/art-template/package.json
    node_modules/art-template/package.json main
    index.js 备选项
    进入上一级目录找 node_modules
    按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx
    一个项目有且仅有一个 node_modules 而且是存放到项目的根目录

更多细节可以阅读 深入 Node.js 的模块机制

More:module.exports

Read || Write File

//	导入 js 模块
const fs = require('js')

// Read file
// 如果是相对路径则是相对于当前执行 node 的文件路径而不是相对于正在执行的文件

// 先来看看 fs.readFile 的参数列表(不止下面一种,只是当做示例,可自行查看)
function readFile(
path: PathLike | number,
options: { encoding?: string | null; flag?: string; } | string | undefined | null,
callback: (err: NodeJS.ErrnoException | null, data: string | Buffer) => void,
): void;


fs.readFile('./my.txt','utf8',(err,data) => {
if(err){
console.log(err)
} else{
// 此时 err => null
console.log(data);
}
})

// 通过__filename/__dirname(当前正在执行文件的文件/目录路径)
// 但是这两个并非是全局的,而是按照(function(__dirname,__filename){})(当前正在执行文件的目录,路径)方式来确定该运行模块的 dir/filename
console.log(__filename,__dirname);

fs.readFile(__dirname+'/my.txt','utf8',(err,data) => {

})

注意:

node 错误优先(第一个参数通常是 err),并且在同步操作中通过 try-catch 来捕获异常,

但是异步操作(比如读写文件、网络请求)无法完成,而是通过 if 语句来判断进行后续处理

//  更优雅的方式:
const path = require('path')
let filename = path.join(__dirname,'my.txt')
console.log(filename);

// node write file
fs.writeFile('./my.txt',msg,'utf8',(err) => {
if(err){
console.log('There is some errora: ' + err)
}
else{
console.log('Success!')
}
})

Http

//	导入 http 模块
const http = require('http')
// 创建一台服务器
let server = http.createServer()

// 未给浏览器返回任何东西
server.on('request', () =>
console.log('there has some people visitting the web~')
)

// set response
let server = http.createServer(function (request, response) { //当有人来访问这个服务器时,就会执行function 这个回调函数
console.log('there has some people visitting the web~' + request.url);

// 设置响应报文头:text/plain | text/html | charset=utf-8
response.setHeader('Content-Type','text/plain;charset=utf-8');

response.write('hello Tadm ~'); //向浏览器输出内容
response.write(' these contents from node ~')

response.end(); // 结束此次请求,不能省略

// 判断不同路径返回不同内容
if(request.url === '/'){
response.end('home page')
} else if(request.url ==== '/login') {
response.end('login page')
} else if(request.url ==== '/json') {
let jsonEaxmple = ['hello','tadm']
// Wrong
response.end(jsonEaxmple)
// Correct
response.end(JSON.stringfy(jsonEaxmple))
}
});

// 设置监听端口以及回调函数(可选)
server.listen(8080,() =>
console.log('The server has been started!')
);

// 如果需要根据不同请求 URL 来返回对应内容,则可以通过
fs.readFile(path.join(__dirname,'index.html'),(err,data) => {
if(err) { throw err }
request.end(data)
})
// 同时需要在响应头中设置ContentType:text/html

res.end(sth) => sth 只能为 String or Buffer

优雅化:

Request

Response

const http = require('http')
const fs = require('fs')
const path = require('path')
const mime = require('mime') // npm i mime 通过请求文件类型返回指定 Content-Type

http.createServer((req,res) => {
let publicDir = path.join(__dirname, 'public')
let filename = path.join(publicDir, req.url)

console.log(req.url);
fs.readFile(filename, (err,data) => {
if(err){
res.end('There is some errors~')
}

res.setHeader('Content-Type', mime.getType(filename))

res.end(data)
})
}).listen(8080,() =>
console.log('The Server has been started!')
)

http.createServer((req,res) => {
let publicDir = path.join(__dirname, 'public')
let filename = path.join(publicDir, req.url)
console.log(filename);

req.url = req.url.toLowerCase()
req.method = req.method.toLowerCase()

// loadFile() --- 挂载到 res 对象上,则不再需要传入 res 对象
// res.loadFile = function (filename) { fs.readFile(filename, (err,data) => res.end(data)) }
// res.loadFile(filename)

if((req.url === '/' || req.url === '/index') && req.method === 'get'){
// fs.readFile(path.join(filename,'index.html'),(err,data) => {
// if(err){ res.end('There is some errors~') }
// res.setHeader('Content-Type',mime.getType(filename))
// res.end(data)
// })
loadFile(path.join(filename,'index.html'),res)
}
else if(req.url.startsWith('/resources') && req.method === 'get'){
// fs.readFile(filename,(err,data) => {
// if(err){ res.end('There is some errors~') }
// res.setHeader('Content-Type',mime.getType(filename))
// res.end(data)
// })
loadFile(filename,res)
}

}).listen(8080,() => console.log('The Server has been started!'))

function loadFile(filename, res){
fs.readFile(filename,(err, data) => {
if(err){
res.end('There is some errors~')
}
res.setHeader('Content-Type', mime.getType(filename))
res.end(data)
})
}

此时我们想要 get/post 提交东西到服务器了:

// 提取页面提交到服务器的内容(tittle=test&name=tadm)并写入 data.json
const querystring = require('querystring') // 将 post 提交的 buffer 转换为 json 对象

fs.readFile(filepath(data.json 的位置),'utf8',(err,data) => {
if(err && err.code !=='ENOENT'){
throw err
}

let infoList = JSON.parse(data || '[]')
let array = []

req.on('data',(chunk) => array.push(chunk))

req.on('end',function(){
let postBody = Buffer.concat(array)
postBody = postBody.toString('utf8')
postBody = querystring.parse(postBody)
infoList.push(postBody)
res.end('ok~')
})

fs.writeFile(path.join(__dirname,'data','data.json'),JSON.stringify(infoList),function(err){
if(err){ throw err}
res.statusCode = 302 // 写入数据后重定向
res.statusMessage = 'Found'
res.setHeader('Location','/')
res.end()
})
})

Express

http://expressjs.com/

Install

mkdir express-demo
cnpm i express -S
cd express-demo

Usage

Hello world 示例:

const express = require('express')
// 创建一个 express (like http.createServer())
const app = express()
const port = 3000

// 访问 http://localhost:3000/ 时返回 Hello World!
app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

新建一个 app.js 文件

const express = require('express')
const app = express()
const port = 3000

const path = require('path')

app.get('/', (req, res) => res.send('Hello World~ From Get~')) // 路径、请求方法(===)
app.post('/otr', (req, res) => res.send('Hello World~ From Post~')) // 同上
app.use('/use', (req, res) => res.send('Hello World~ From Use~')) // 不限请求方法,路径:/index/*
app.all('/all', (req, res) => res.send('Hello World~ From All~')) // 不限请求方法,路径(===)

app.get(/^\/index(\/.*)*$/, (req, res) => res.send('Hello World~ From Regex~')) // 正则表达式匹配路径
app.get('/query', (req, res) => console.log(req.query)) // 通过 query 获取参数
// http://localhost:3000/query?name=tadm { name: 'tadm' }
app.get('/params/:title/:name', (req, res) => res.send(req.params)) // 通过 params 获取参数
// http://localhost:3000/params/test/tadm {"title":"test","name":"tadm"}

app.get('/json', (req, res) => res.json({ title:'json',name:'tadm' }))
app.get('/jsonsend', (req, res) => res.send({ title:'json',name:'tadm' }))
app.get('/error', (req, res) => res.status(404).end('There is 404~'))

// 公开指定目录,我们就可以通过 public/* 来访问文件夹下的资源
app.use('/static', express.static(path.join(__dirname, 'public')))

app.listen(port, () => console.log(`Example app listening on port ${port}!`, __dirname))

// More: http://expressjs.com/en/4x/api.html

Nodemon

自动重启工具,不再需要每次重启服务,直接 ctrl+s 完事

Install

npm i nodemon -g

Usage

nodemon --version

nodemon app.js

POST

body-parser

npm i body-parser -S
var express = require('express')
var bodyParser = require('body-parser')

var app = express()

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())

app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
res.end(JSON.stringify(req.body, null, 2))
})

CODE Example

<!DOCTYPE html>
<html>
<head>
<title>test</title>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
</head>
<body>
<div>
<p>There is a beautiful girl</p>
<img width="1000px" height="700px" src="./img45.jpg">
</div>

<div class="comments container">
<form action="/post" method="post">
<div class="form-group">
<label for="input_name">Name</label>
<input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="Please input your name~">
</div>
<div class="form-group">
<label for="textarea_message">Content</label>
<textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>

</body>
</html>
const bodyParser = require('body-parser')

// 公开指定目录,我们就可以通过 public/* 来访问文件夹下的资源
app.use('/static', express.static(path.join(__dirname, 'public')))

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json())

app.post('/post', (req, res) => {
console.log(req.body);
})
// [Object: null prototype] { name: 'Tadm', message: '12345' }

app.use([path,] callback [,callback …])

将指定的一个或多个中间件函数安装在指定的路径上:当所请求路径的基数匹配时,将执行中间件函数path

使用中间件也需要注意顺序,更多查看官方文档

Small Demo

  • app.js
const express = require('express')
const router = require('./router')
const bodyParser = require('body-parser')

let app = express()

app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))

app.engine('html', require('express-art-template'))

// 配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

// 把路由容器挂载到 app 服务中
app.use(router)

app.listen(3000, function () {
console.log('running 3000...')
})

module.exports = app
  • router.js
const express = require('express')
const router = express.Router()

const Student = require('./student')

router.get('/students', function (req, res) {
Student.find(function(err, students) {
if (err) {
return res.status(500).send('Server error.')
}
res.render('index.html', {
fruits: [
'苹果',
'香蕉',
'橘子'
],
students: students
})
})
})

router.get('/students/new', function (req, res) {
res.render('new.html')
})

router.post('/students/new', function (req, res) {
Student.save(req.body, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})

router.get('/students/edit', function (req, res) {
Student.findById(parseInt(req.query.id), function (err, student) {
if (err) {
return res.status(500).send('Server error.')
}
res.render('edit.html', {
student: student
})
})
})

router.post('/students/edit', function (req, res) {
Student.updateById(req.body, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})

router.get('/students/delete', function (req, res) {
Student.deleteById(req.query.id, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})

module.exports = router
  • student.js
const fs = require('fs')
const dbPath = './db.json'

function writeData(students, callback) {
let fileData = JSON.stringify({
students: students
})

fs.writeFile(dbPath, fileData, function (err) {
if (err) {
return callback(err)
}
callback(null)
})
}

exports.find = function (callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
callback(null, JSON.parse(data).students)
})
}

exports.findById = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students
let ret = students.find(function (item) {
return item.id === parseInt(id)
})
callback(null, ret)
})
}

exports.save = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students

student.id = students[students.length - 1].id + 1

students.push(student)

writeData(students,callback)
})
}

exports.updateById = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students

student.id = parseInt(student.id)

let stu = students.find(function (item) {
return item.id === student.id
})

for (let key in student) {
stu[key] = student[key]
}

writeData(students,callback)
})
}

exports.deleteById = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
let students = JSON.parse(data).students

let deleteId = students.findIndex(function (item) {
return item.id === parseInt(id)
})

students.splice(deleteId, 1)

writeData(students,callback)
})
}
  • db.json
{"students":
[
{"id":1,"name":"Foo","gender":"0","age":"24","hobbies":"Study"},
{"name":"Tadm","gender":"0","age":"19","hobbies":"Coding","id":2}
]
}
  • index.html
<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="icon" href="../../favicon.ico">
<title>Dashboard Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="/public/css/main.css" rel="stylesheet">
</head>

<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="#">Project name</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard</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="/">学生管理 <span class="sr-only">(current)</span></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">Dashboard</h1>
<div class="row placeholders">
{{ each fruits }}
<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>{{ $value }}</h4>
<span class="text-muted">Something else</span>
</div>
{{ /each }}
</div>
<h2 class="sub-header">Section title</h2>
<a class="btn btn-success" href="/students/new">添加学生</a>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>爱好</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{ each students }}
<tr>
<td>{{ $value.id }}</td>
<td>{{ $value.name }}</td>
<td>{{ $value.gender }}</td>
<td>{{ $value.age }}</td>
<td>{{ $value.hobbies }}</td>
<td>
<a href="/students/edit?id={{ $value.id }}">编辑</a>
<a href="/students/delete?id={{ $value.id }}">删除</a>
</td>
</tr>
{{ /each }}
</tbody>
</table>
</div>
</div>
</div>
</div>
  • edit.html
<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="#">Project name</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard</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="/students">学生管理 <span class="sr-only">(current)</span></a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h2 class="sub-header">添加学生</h2>
<form action="/students/edit" method="post">
<!--
用来放一些不希望被用户看见,但是需要被提交到服务端的数据
-->
<input type="hidden" name="id" value="{{ student.id }}">
<div class="form-group">
<label for="">姓名</label>
<input type="text" class="form-control" id="" name="name" required minlength="2" maxlength="10" value="{{ student.name }}">
</div>
<div class="form-group">
<label for="">性别</label>
<div>
<label class="radio-inline">
<input type="radio" name="gender" id="" value="0" checked>
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="" value="1">
</label>
</div>
</div>
<div class="form-group">
<label for="">年龄</label>
<input class="form-control" type="number" id="" name="age" value="{{ student.age }}" required min="1" max="150">
</div>
<div class="form-group">
<label for="">爱好</label>
<input class="form-control" type="text" id="" name="hobbies" value="{{ student.hobbies }}">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>
  • new.html
<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="#">Project name</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Dashboard</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="/students">学生管理 <span class="sr-only">(current)</span></a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h2 class="sub-header">添加学生</h2>
<form action="/students/new" method="post">
<div class="form-group">
<label for="">姓名</label>
<input type="text" class="form-control" id="" name="name" required minlength="2" maxlength="10">
</div>
<div class="form-group">
<label for="">性别</label>
<div>
<label class="radio-inline">
<input type="radio" name="gender" id="" value="0" checked>
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="" value="1">
</label>
</div>
</div>
<div class="form-group">
<label for="">年龄</label>
<input class="form-control" type="number" id="" name="age" required min="1" max="150">
</div>
<div class="form-group">
<label for="">爱好</label>
<input class="form-control" type="text" id="" name="hobbies">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div>
</div>
</div>

MongoDB

Hello World

初步认识可参考此篇:mongoDBcommand

官方:mongodb

再次封装版:mongoose

  • Install
npm i mongoose -S
  • Usage
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true});

const Cat = mongoose.model('Cat', { name: String });

const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
  • Result

db
test

show dbs
admin 0.000GB
config 0.000GB
elm 0.001GB
local 0.000GB
test 0.000GB

show collections
cats
student

db.cats.find()
{ “_id” : ObjectId(“5e5115d217508ead24309fb5”), “name” : “Zildjian”, “__v” : 0 }

CRUD

let mongoose = require('mongoose')
let Schema = mongoose.Schema

// 1. 连接数据库
// 指定连接的数据库不需要存在,当你插入第一条数据之后就会自动被创建出来
mongoose.connect('mongodb://localhost/nodemongoose')

// 2. 设计文档结构(表结构)
// 字段名称就是表结构中的属性名称
// 约束的目的是为了保证数据的完整性,不要有脏数据
let userSchema = new Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String
}
})

// 3. 将文档结构发布为模型
// mongoose.model 方法就是用来将一个架构发布为 model
// 第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
// mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称
// 例如这里的 User 最终会变为 users 集合名称
// 第二个参数:架构 Schema
//
// 返回值:模型构造函数

// let User = mongoose.model('User', userSchema)

let User = mongoose.model('User',new Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String
}
})
)

// console.log(User);

// 4. 有了模型构造函数之后,就可以使用这个构造函数对 users 集合中的数据CRUD(增删改查)

// **********************
// #region /新增数据
// **********************
let admin = new User({
username: 'Tadm',
password: '123456',
email: '2873126657@qq.com'
})

admin.save(function (err, ret) {
if (err) {
console.log('保存失败')
} else {
console.log('保存成功')
}
})
// **********************
// #endregion /新增数据
// **********************


// **********************
// #region /查询数据
// **********************
User.find(function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})

User.find({
username: 'Tadm'
}, function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})

User.findOne({
username: 'Tadm'
}, function (err, ret) {
if (err) {
console.log('查询失败')
} else {
console.log(ret)
}
})
// // **********************
// // #endregion /查询数据
// // **********************



// // **********************
// // #region /删除数据
// // **********************
User.remove({
username: 'Tadm'
}, function (err, ret) {
if (err) {
console.log('删除失败')
} else {
console.log('删除成功')
console.log(ret)
}
})
// // **********************
// // #endregion /删除数据
// // **********************


// // **********************
// // #region /更新数据
// // **********************
User.findByIdAndUpdate('5e51f28f79148a150c76977d', {
password: '123'
}, function (err, ret) {
if (err) {
console.log('更新失败')
} else {
console.log('更新成功')
}
})
// // **********************
// // #endregion /更新数据
// // **********************

更多操作 API

MySQL

  • Install
npm i mysql -S
  • CODE
let mysql = require('mysql');

// 1. 创建连接
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'users'
});

// 2. 连接数据库
connection.connect();

// 3. 执行数据操作
connection.query('SELECT * FROM `users`', function (error, results, fields) {
if (error) throw error
console.log('The solution is: ', results)
})

connection.query('INSERT INTO users VALUES(NULL, "Tadm", "123456")', function (error, results, fields) {
if (error) throw error

console.log('The solution is: ', results)
})

// update/delete 操作直接写相关SQL语句即可并放入 connection.query() 中执行

// 4. 关闭连接
connection.end()

Promise

mongoose 的所有 API 均支持 Promise

Node 路径问题

因为在 node 中文件的相对路径是相对于当前执行 node 命令的文件路径而不是相对于正在执行的文件

如何解决:

  • __dirname

动态获取当前文件所在目录的绝对路径

  • __filename

动态获取当前文件所在路径的绝对路径

简单而言:这两个属性始终保存着当前文件的(绝对)路径信息,与 node 命令执行位置无关

let publicDir = path.join(__dirname, 'public')
let filename = path.join(publicDir, req.url)

但是只是针对于文件的路径而言,模块的路径标识不受影响,而且相对路径(‘./ ../‘)不能省略

Express-session

官方文档

npm i express-session -S
Author: 𝓣𝓪𝓭𝓶
Link: https://liuhongwei3.github.io/2020/02/21/NodeStudy/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.