Javascript

node.js+MySQL知识点

本文主要是介绍node.js+MySQL知识点,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

fs模块

fs常用方法

const fs = require('fs')

// 读取文件
// fs.readFile(path[, options], callback)  
// options:表示以什么编码格式读取文件(可选),不选择时输出为一个Buffer对象
// callback:文件读取完成后通过回调函数拿到读取的结果
fs.readFile('./files/1.txt', 'utf8', (err, dataStr) => {
    if(err) {
        return console.log(err) // 若读取成功 err = null,失败则输出一个错误对象
    }
    console.log(dataStr) // 若读取失败则为 undefined
})

// 写入内容
// fs.writeFile(file, data[, options], callback)
// file:文件路径字符串
// data:写入的内容
// options:表示以什么编码格式写入文件(可选),不选择时输出为一个Buffer对象
// callback:文件写入完成后的回调函数
// 注意点:
// 1. 写入文件时文件夹必须存在,文件可不存在,文件不存在时则新建文件
// 2. 重复调用时新写入的内容会覆盖之前的旧内容
fs.writeFile('./files/1.txt', 'Go!', 'utf8', (err) => {
    if(err) {
        return console.log(err) // 若写入成功 err = null,失败则输出一个错误对象
    }
    fs.readFile('./files/1.txt', 'utf8', (err, dataStr) => {
        if(err) {
            return console.log(err)
        }
        console.log('写入的数据为:' + dataStr)
    })
})

fs路径动态拼接问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kehzyTDh-1641905820826)(D:\typora\image-20220108171708425.png)]

// __dirname 表示当前文件所处的目录
const fs = require('fs')

fs.readFile(__dirname + '/files/1.txt', 'utf8', (err, dataStr) => {
    if(err) {
        return console.log(err)
    }
    console.log(dataStr)
})

path路径模块

const path = require('path')

// 拼接完整路径字符串
// path.join()
const pathStr = path.join('/a', '/b/c', '../', '/d', 'e')
console.log(pathStr) // 输出 \a\b\d\e,其中'../'会抵消一层路径 

const pathStr2 = path.join(__dirname, '/files/1.txt')
console.log(pathStr2) // 输出当前路径下所处目录的\files\1.txt

// 从路径字符串中解析文件名
// path.basename(path[, ext])
// ext为文件扩展名
const fpath  = path.join(__dirname, '/files/2.txt')

let fullName = path.basename(fpath)
console.log(fullName) // 输出 2.txt

let nameWithoutExt = path.basename(fpath, '.txt')
console.log(nameWithoutExt) // 输出 2

// 获取路径中文件的扩展名
// path.extname(path)
let ext = path.extname(fpath)
console.log(ext) // 输出 .txt

http模块

URL中的80端口可以被省略,每个端口号不能被多个web服务占用

// 创建web服务器
const http = require('http')

// 创建web服务器实例
const server = http.createServer()

// 为服务器实例绑定request事件,访问此网页即触发此事件
// req请求对象:在事件处理函数中访问与客户端相关的数据或属性,如req.url 请求url地址(/后面的内容,包括'/') req.method 请求类型
// res响应对象:在事件处理函数中访问与服务器相关的数据或属性
server.on('request', (req, res) => {
    console.log('Someone visit our web server!')
    const str = `Your request url is ${req.url == '/'? '根目录': req.url}, and request method is ${req.method}.`   
    // 防止响应乱码
    res.setHeader('Content-Type', 'text/html;  charset=utf-8')
    // 向客户端响应内容
    res.end(str)
})

// 启动服务器
server.listen(80, () => {
    console.log('http server running at http://127.0.0.1')
})

http动态响应内容

// 创建web服务器
const http = require('http')
const fs = require('fs')

// 创建web服务器实例
const server = http.createServer()

// 为服务器实例绑定request事件,访问此网页即触发此事件
server.on('request', (req, res) => {
    const url = req.url
    // 优化资源请求路径
    let fpath = ''
    if(url == '/'){
        fpath = path.join(__dirname, './clock/index.html')
    } else {
        fpath = path.join(__dirname, './clock', url)
    }
    fs.readFile(fpath, 'utf8', (err, dataStr) => {
        if (err) return res.end('<h1>404 Not found!</h1>')
        res.end(dataStr)
    })
})

// 启动服务器
server.listen(80, () => {
    console.log('http server running at http://127.0.0.1')
})

Node.js模块

Node.js中的模块作用域

自定义模块中定义的变量、方法等成员只能在当前模块被访问,这种模块级别的访问限制称为模块作用域。

向外共享模块作用域中的成员需要使用module.exports对象

const username = 'wj'

function makeMoney() {
    console.log('30w')
}

// 外界使用 require() 方法导入自定义模块时得到的就是 module.exports 所指向的对象
// 其中,使用 require() 方法加载模块属于 CommonJS 规范 
module.exports = {
    username,
    makeMoney
}

module.exports.income = '30w'
module.exports.go = () => {
    console.log('go!')
}
// 以上 module.exports 均可用 exports 替换,默认情况下两者指向同一个对象
// 重点:
// 最终共享的结果还是以 module.exports 指向的对象为准
// 注意点:
// 1.module.exports = {} 不能使用 exports 代替,因为如果使用 exports = {} 即将exports指向另外一个新的对象
// 2.如需混用最好只使用 module.exports.new1 和 exports.new2 的形式

包的语义化版本规范

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gym6xjzc-1641905820828)(D:\typora\image-20220110161005639.png)]

npm切换下包镜像源

npm config get registry
npm config set registry=https://registry.npm.taobao.org/

i5ting_toc将md文档转换为html页面的小工具

i5ting_toc -f '要转换的md文件路径' -o

模块的加载机制

模块在第一次加载后被毁缓存,多次调用 require() 不会导致模块的代码被执行多次。

内置模块的加载优先级最高。

使用 require() 加载自定义模块时必须指定与 ./ 或 …/ 开头的路径标识符,若没有 node 会把它当作内置模块或第三方模块及逆行加载。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LklMRlBx-1641905820828)(D:\typora\image-20220110194741040.png)]

express基础

创建web服务器

const express = require('express')

// 创建web服务器
const app = express()

// 启动web服务器
app.listen(80, () => {
    console.log('express server running at http://127.0.0.1')
})

监听GET请求和响应res.send()

/* app.get('请求URL', (req,res) => {
    // 处理函数
}) */

app.get('/user', (req,res) => {
    res.send({name:'wj', income:'30w'})
})

app.post('/user', (req,res) => {
    res.send('请求成功!')
})

获取URL中携带的查询参数 req.query

app.get('/', (req,res) => {
    // req.query 查询的是客户端使用 ?name=wj&income=30w 这种字符串形式,默认情况下为 {}
    res.send(req.query)
})

获取URL中携带的动态参数 req.params

app.get('/:id/:name', (req,res) => {
    // req.params: URL地址中通过 :参数名 的形式,匹配动态参数值
    // :id 中的 id 即为 req.params 对象的属性名 
    // 请求时直接写 http://http://localhost/256/wj
    res.send(req.params) // 输出JSON对象 {"id":"256","name":"wj"}
})

托管静态资源 express.static()

// 创建一个静态资源服务器
// 访问时不用加 public 这一级,且文件夹可以不叫 public
// 也可有多个文件夹被托管,会根据目录的添加顺序查找所需要的文件
app.use(express.static('public'))
app.use(express.static('clock'))

// 可以在静态资源访问路径之前挂载路径前缀
// 之后如果需要访问 public 文件夹内的文件时必须添加 /public 前缀,前缀可以任意,一般使用目录名
app.use('/public', express.static('public')) // http://http://localhost/public/clock/index.html 才能访问

express路由

路由概念

express路由指的是客户端的请求与服务器处理函数之间的映射关系。

// app.METHOD(PATH, HANDLER)
app.get('/user', (req,res) => {
    res.send({name:'wj', income:'30w'})
})

app.post('/user', (req,res) => {
    res.send('请求成功!')
})
// 以上皆为路由
// 匹配时按照路由的顺序进行匹配

模块化路由

// 路由抽离为单独模块的步骤,以下为模块.js

// 创建路由模块对应的 .js 文件
const express = require('express')

// 调用 express.Router() 函数创建路由对象
const router = express.Router()

// 向路由对象上挂载具体的路由
router.get('/user/list', (req,res) => {
    res.send({name:'wj', income:'30w'})
})

// 使用 moudule.exports 向外共享路由对象
router.post('/user/add', (req,res) => {
    res.send('请求成功!')
})

// 使用 app.use() 函数注册路由模块
module.exports = router
// 调用
const express = require('express')
const app = express()
const userRouter = require('./router/router1')

app.listen(80, () => {
    console.log('express server running at http://127.0.0.1')
})

// app.use()函数注册全局中间件
// 同时可添加路由前缀,访问时必须加上路由前缀
app.use('/api', userRouter)
// 请求时触发 userRouter 内的 get 和 post 方法

express中间件

中间件的作用:**多个中间件之间共享一份 req 和 res。**基于这样的特性可在上游的中间件中统一为 req 或 res 对象添加自定义的属性和方法,供下游的中间件或路由进行使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cxh8Cla3-1641905820829)(D:\typora\image-20220110214414703.png)]

中间件本质:function处理函数

// 中间件函数的形参列表中必须包含next函数,而路由处理函数中只包含 req 和 res
app.get('/user', (req, res, next) => {
	next()
})
// next() 表示流转关系转交给下一个中间件或路由

// 定义中间件函数
// 常量 mv 所指向的就是一个中间件函数
const mw = function(req, res, next){
    // 中间件函数必须调用next()函数,表示把流转关系转交给下一个中间件或路由
    next()
}

全局中间件

// 客户端发起任何请求,到达服务器之后都会触发的中间件叫做全局中间件
// 通过调用 app.use(中间件函数) 即可定义一个全局中间件
const mw = function(req, res, next){
    // 中间件函数必须调用next()函数,表示把流转关系转交给下一个中间件或路由
    next()
}

app.use(mw)
// 流转关系:经过一个中间件后再转交给下一个中间件,若无中间件则转交给路由
// 中间件之间按定义的先后顺序流转

// 简化写法
app.use((req, res, next) => {
    next()
})

局部中间件

// 直接定义在路由中的中间件为局部中间件,只在当前路由中生效
app.get('/about', (req, res, next) => {
    next()
},(req, res) => {
    res.send('About Page')
})

// 可一次性定义多个局部中间件,执行顺序为定义先后顺序
app.get('/', mw1, mw2, (req, res) => {})
app.get('/', [mw1, mw2], (req, res) => {})

中间件的5个注意事项

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LjP3Rfl-1641905820829)(D:\typora\image-20220111100358561.png)]

express中间件分类

除了错误级别的中间件其他均需在路由之间注册中间件!!!

应用级别的中间件

// 通过 app.use() 或 app.get() 或 app.post(),绑定到app实例上的中间件都叫做应用级别的中间件
app.get('/about', (req, res, next) => {
    next()
},(req, res) => {
    res.send('About Page')
})

app.use((req, res, next) => {
    next()
})

路由级别的中间件

// 绑定到 express.Router() 实例上的中间件叫做路由级别的中间件,express.Router() 为路由实例
const express = require('express')
const app = express()

const router = express.Router()

router.use((req, res, next) => {
    next()
})

app.listen(80, () => {
	console.log('http://127.0.0.1')
})

错误级别的中间件

注意!!!错误级别中间件必须注册在所有路由之后!!!

// 专门捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
// 且错误级别中间件必须包含四个形参
app.get('/', (req, res) => {
    throw new Error('Throw a error!')
    res.send('Home page.')
})

app.use((err, req, res, next) => {
    res.send('Error! ' + err.message)
})

express内置中间件

// 1.express.static 快速托管静态资源的内置中间件,无兼容性问题
app.use(express.static('public'))

// 2.express.json 解析JSON格式的请求体数据,4.16.0+ 版本才可使用
app.use(express.json())

app.post('/user', (req, res) => {
    // 在服务器端可以使用 req.body 这个属性来接收客户端发送过来的请求体数据
    // 默认情况下不加此中间件默认 req.body = undefined
    console.log(req.body)
    res.send('ok')
})

// 3.express.urlencoded 解析 URL-encoded 格式的请求体数据,4.16.0+ 版本才可使用
// URL-encoded 是一种键值对形式的表单格式
app.use(express.urlencoded({ extended: false }))

app.post('/book', (req, res) => {
    // 默认情况下不加此中间件默认 req.body = {}
    console.log(req.body)
    res.send('ok')
})

注:

使用postman发送JSON格式请求体数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BMbjPjT-1641905820830)(D:\typora\image-20220111110129048.png)]

使用postman发送URL-encoded 格式请求体数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwyFb0Hi-1641905820830)(D:\typora\image-20220111110100607.png)]

第三方中间件

在 express@4.16.0 以前使用 body-parser 第三方中间件解析请求体数据。

const parser = require('body-parser')
// 解析 URL-encoded 格式的请求体数据
app.use(parser.urlencoded({ extended: false }))

自定义中间件

// 模块化 --> 中间件.js
// node.js 内置了 querystring 模块,parse() 专门用来查询字符串。
const qs = require('querystring')

function bodyParser(req, res, next) {
    // 监听 req 对象的 data 时间,来获取客户端发送到服务器的数据
    // 若数据量较大无法一次性发完,则客户端会将数据切割后分批发送到服务器端,所以 data 事件可能会触发多次
    // 每次触发获取到的数据只是完整数据的一部分,需要手动对接收到的数据进行拼接
    let str = ''
    req.on('data', (chunk) => {
        // 拼接请求体数据,隐式转换为字符串
        str += chunk
    })
    // 当请求体数据接收完毕后会自动触发 req 的 end 事件
    req.on('end', () => {
        // 此时 str 为完整请求体数据
        const body = qs.parse(str)
        req.body = body
        next()
    })
}

module.exports = {
    bodyParser
}

/*-----------------------------------------------------*/

// 调用 --> main.js
const express = require('express')
const app = express()
const myBodyParser = require('./diymw')

app.use(myBodyParser.bodyParser)

app.post('/user', (req, res) => {
    res.send(req.body)
})

app.listen(80, () => {
    console.log('http://127.0.0.1')
})

使用express写接口

GET接口

// 模块 --> apiRouter.js
const express = require('express')
const apiRouter = express.Router()

apiRouter.get('/get', (req, res) => {
    const query = req.query
    res.send({
        status: 0,   // 状态,0表示成功,1表示失败
        msg: 'GET请求成功', // 状态描述
        data: query  // 需要相应给客户端的具体数据
    })
})

module.exports = apiRouter

POST接口

const express = require('express')
const apiRouterPost = express.Router()

apiRouterPost.post('/post', (req, res) => {
    const body = req.body
    res.send({
        status: 0,  // 状态,0表示成功,1表示失败
        msg: 'POST请求成功', // 状态描述
        data: body     // 需要响应给客户端的具体数据
    })
})

module.exports = apiRouterPost

调用接口

const express = require('express')
const app = express()
const apiRouterGet = require('./apiRouter/apiRouterGet.js')
const apiRouterPost = require('./apiRouter/apiRouterPost.js')

// 注意:获取请求体数据时需要使用中间件对其解析
app.use(express.json())
app.use(express.urlencoded({ extended: false }))

app.use('/api', apiRouterGet)
app.use('/api', apiRouterPost)

app.listen(80, () => {
    console.log('http://127.0.0.1')
})

解决跨域问题

// 协议、域名或端口号任一项不同就存在跨域问题
// 解决方案
// 1.CORS(跨域资源共享)中间件,一定在路由前注册
// CORS本质就是一些列HTTP响应头
// CORS具有兼容性问题,只有支持 XMLHttpRequest Level2 的浏览器才能正常访问开启了 CORS 的服务端接口
const cors = require('cors')
app.use(cors())

/*
扩展:
1.CORS 响应头部 Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
其中,origin 参数的值指定了允许访问该资源的外域URL
res.setHeader('Access-Control-Allow-Origin', 'http://www.baidu.com')

2.CORS 响应头部 Access-Control-Allow-Header
默认情况下,CORS 仅支持客户端向服务器发送如下的 9 个请求头:
Accept, Accept-Language, Content-Language, DPR, Downlink, Sava-Data, Viewport-Width, Width, Content-Type
且值仅限于 text/plain, multipart/form-data, application/x-www-form-urlencoded 三者之一
如果客户端向服务器发送额外的请求头信息,则需要在服务器端通过 Access-Control-Allow-Header 对额外的请求头进行声明,否则此次请求失效
res.setHeader('Access-Control-Allow-Header', 'Content-Type, X-Custom-Header')

3.CORS 响应头部 Access-Control-Allow-Methods
默认情况下 CORS 仅支持客户端发起 GET、POST、HEAD 请求
如果需要通过 PUT、DELETE 等方式请求服务器的资源则需要通过 Access-Control-Allow-Methods来指明允许使用的 HTTP 方法
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DElETE, HEAD')
res.setHeader('Access-Control-Allow-Methods', '*')

4.CORS分类
简单请求:GET、POST、HEAD三者之一,且头部信息不超过以下几种并无自定义头部字段
Accept, Accept-Language, Content-Language, DPR, Downlink, Sava-Data, Viewport-Width, Width, Content-Type
预检请求:
(1) GET、POST、HEAD之外的请求
(2) 请求头中包含自定义头部字段
(3) 向服务器发送了 application/json 格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。
服务器成功响应预检请求后才会发送真正的请求,并且携带真实数据。

*/

// 2.JSONP(只支持 GET 请求)
// 概念:浏览器端通过 <script> 标签的 src 属性请求服务器上的数据,同时,服务器返回一个函数的调用,这种方式称为JSONP
// jsonp 接口
app.get('/api/jsonp', (req, res) => {
    // 获取客户端发送过来的回调函数名字
    const funcName = req.query.callback

    // 得到要通过 JSONP 形式发送给客户端的数据
    const data = { name: 'wj', age: 25 }

    // 根据前两步得到的数据,拼接处一个函数调用的字符串
    const scriptStr = `${funcName}(${JSON.stringify(data)})`

    // 把上一步拼接得到的字符串响应给客户端的 <script> 标签进行解析执行
    res.send(scriptStr)
})

/*---------------------------------------------------*/

// jQuery 中 JSONP 请求
$('#btnJSONP').on('click', function () {
	$.ajax({
		method: 'GET',
		url: 'http://127.0.0.1/api/jsonp',
		dataType: 'jsonp',
		success(res) {
		console.log(res)
		}
	})
})

MySQL数据类型和字段

DataType数据类型:

(1)int 整形

(2)varchar(len) 字符串

(3)tinyint(1) 字符串

字段的特殊表示:

(1)PK(Primary Key)主键、唯一标识

(2)NN(Not Null)值不允许为空

(3)UQ(Unique)值唯一

(4)AI(Auto Increment)值自动增长

SQL语句

SELECT

-- 从 FROM 指定的【表中】,查询出【所有】的数据
-- SELECT * FROM 表名称
SELECT * FROM users;

-- 从 FROM 指定的【表中】,查询出指定【字段】的数据
-- SELECT 列名称 FROM 表名称
SELECT username, password FROM users;

-- 使用 WHERE 查询
-- SELECT 列名称 FROM 表名称 WHERE 列 运算符 值
SELECT * FROM users WHERE id <> 4;

-- 使用 AND 和 OR 运算符
SELECT * FROM users WHERE id <> 2 AND username = 'wj';
SELECT * FROM users WHERE id > 2 OR id < 2;

-- SQL语句中关键字(SELECT、FROM等)对大小写不敏感

INSERT INTO

-- 向指定的表中插入如下几列数据,列的值通过 values 一一指定
-- 列和值要一一对应,多个列和多个值之间使用英文逗号隔开
-- INSERT INTO table_name(列1, 列2, ...) VALUES (值1, 值2, ...)
INSERT INTO user (username, password) VALUES ('lmj', '7856');

UPDATE

-- 指定要更新哪个表中的数据
-- 用 SET 指定列对应的新值
-- 用 WHERE 指定更新的条件
-- UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
UPDATE users SET password = '123789', status = 1 WHERE username = 'lmj01';

DELETE

-- 从指定表中根据 WHERE 条件删除对应的数据行
-- DELETE FROM 表名称 WHERE 列名称 = 值
DELETE FROM users WHERE username = 'temp';

ORDER BY

-- ORDER BY 默认进行升序排序
-- ASC 关键字代表升序排序
SELECT * FROM users ORDER BY status;
SELECT * FROM users ORDER BY status ASC;
-- DESC 降序排序
SELECT * FROM users ORDER BY status DESC;

-- 多重排序
-- 先按照 status 进行降序排序,再按照 username 的字母排序进行升序排序
SELECT * FROM users ORDER BY status DESC, username ASC;

COUNT(*)

-- 查询 users 表中 status 为 0 的总数据条数
SELECT COUNT(*) FROM users WHERE status = 0;

AS

-- 将列名称从 COUNT(*) 修改为 total
SELECT COUNT(*) AS total FROM users WHERE status = 0;
-- 普通的列也可以
SELECT username AS uname, password as pwd FROM users WHERE status = 0;
这篇关于node.js+MySQL知识点的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!