Node.js知识点总结

Node.js知识点总结

Node.js其本质和浏览器一样是一个JavaScript运行环境。浏览器的运行环境为V8引擎+浏览器内置API(BOM、DOM、Canvas);而node.js的运行环境是V8引擎+node提供的API(fs、path、http)。它使JavaScript可以编写后端。

基本知识

fs文件系统模块

  • 它提供一系列的方法和属性,用来满足用户对文件的操作需求

  • 使用语法:

  • 加载 fs 模块,得到 fs 对象

js 复制代码
const fs = require('fs')
  • 写入文件内容语法:
js 复制代码
fs.writeFile('文件路径', '写入内容', err => {
  // 写入后的回调函数
})
  • 读取文件内容的语法:
js 复制代码
fs.readFile('文件路径', (err, data) => {
  // 读取后的回调函数
  // data 是文件内容的 Buffer 数据流
})
  • 需求:向 test.txt 文件写入内容并读取打印
html 复制代码
/**
 * 目标:使用 fs 模块,读写文件内容
 * 语法:
 * 1. 引入 fs 模块
 * 2. 调用 writeFile 写入内容
 * 3. 调用 readFile  读取内容
 */
// 1.加载fs模块对象
const fs = require('fs')
// 2.写入文件内容
fs.writeFile('./test.txt', 'hello,Node.js', (err) => {
  if(err) console.log(err)
    else console.log('写入成功')
})
// 3.读取文件内容
fs.readFile('./test.txt', (err, data) => {
  if (err) console.log(err)
    // data是buffer16进制数据流对象
    // toString()转换成字符串
    //<Buffer 68 65 6c 6c 6f 2c 4e 6f 64 65 2e 6a 73>
  else console.log(data.toString())
})

path路径模块

  • 它是用来处理路径的模块
  • 使用语法:
  • 加载 path 模块,得到 path对象
html 复制代码
const path = require('path')
  • 将多个路径片段拼接成一个完整路径字符串
html 复制代码
const path = require('path')
const fs = require('fs')

// 注意:  ../ 会抵消前面的路径
// const pathStr = path.join('/a', '/b/c', '../../', './d', 'e')
// console.log(pathStr)  // \a\b\d\e

// fs.readFile(__dirname + '/files/1.txt')

fs.readFile(path.join(__dirname, './files/1.txt'), 'utf8', function(err, dataStr) {
  if (err) {
    return console.log(err.message)
  }
  console.log(dataStr)
})
  • 从路径字符串中,将文件名解析出来
html 复制代码
const path = require('path')

// 定义文件的存放路径
const fpath = '/a/b/c/index.html'

// const fullName = path.basename(fpath)
// console.log(fullName)

const nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) //输出index
  • 获取路径中的扩展名部分
html 复制代码
const path = require('path')

// 这是文件的存放路径
const fpath = '/a/b/c/index.html'

const fext = path.extname(fpath)
console.log(fext)//输出.html

http 模块

是用来创建 web 服务器的模块,通过 http模块提供的http.createServer() 方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而提供资源服务

  • 基本语法:
html 复制代码
// 1. 导入 http 模块
const http = require('http')
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件,监听客户端的请求
server.on('request', function (req, res) {
  console.log('Someone visit our web server.')
})
// 4. 启动服务器
server.listen(8080, function () {  
  console.log('server running at http://127.0.0.1:8080')
})
URL端口号
  • 是标记服务器里对应的服务程序,值为(0-65535 之间的任意整数
  • http 协议,默认访问的是 80 端口
req、res
  • req:是请求对象,包含了与客户端相关的数据和属性
  • res:是响应对象,包含了与服务器相关的数据和属性
html 复制代码
const http = require('http')
const server = http.createServer()
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res) => {
  // req.url 是客户端请求的 URL 地址
  const url = req.url
  // req.method 是客户端请求的 method 类型
  const method = req.method
  const str = `Your request url is ${url}, and request method is ${method}`
  console.log(str)
  // 调用 res.end() 方法,向客户端响应一些内容
  res.end(str)
})
server.listen(80, () => {
  console.log('server running at http://127.0.0.1')
})

模块化

CommonJS 标准

Node.js中每一个文件都是一个独立的模块,项目由多个模块组成

由于各个模块的属性和函数是私有的,如果对外使用,则需要标准语法导入、导出,即 CommonJS 标准

  • 导出语法:
html 复制代码
module.exports = {
  对外属性名: 模块内私有变量
}
  • 导入语法:
html 复制代码
const 变量名 = require('模块名或路径')
// Node.js 环境内置模块直接写模块名(例如:fs,path,http)
// 自定义模块:写模块文件路径(例如:./utils.js)
  • 代码实现:

  • 导出

html 复制代码
/**
 * 目标:基于 CommonJS 标准语法,封装属性和方法并导出
 */
const baseURL = 'http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)

// 导出
module.exports = {
  url: baseURL,
  arraySum: getArraySum
}
  • 导入
html 复制代码
/**
 * 目标:基于 CommonJS 标准语法,导入工具属性和方法使用
 */
// 导入
const obj = require('./utils.js')
console.log(obj)
const result = obj.arraySum([5, 1, 2, 3])
console.log(result)

ECMAScript标准-默认导出和导入

  • CommonJS 规范为 Node.js 环境中默认的,后来官方推出 ECMAScript 标准语法

  • 注意:Node.js 默认只支持 CommonJS 标准语法,如果想要在当前项目环境下使用 ECMAScript 标准语法,请新建 package.json 文件设置 type: 'module' 来进行设置

html 复制代码
{ "type": "module" }
  • 导出语法:
js 复制代码
export default {
  对外属性名: 模块内私有变量
}
  • 导入语法:
js 复制代码
import 变量名 from '模块名或路径'
  • 语法实现:

  • 导出:

html 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,封装属性和方法并"默认"导出
 */
const baseURL = 'http://hmajax.itheima.net'
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)

// 默认导出
export default {
  url: baseURL,
  arraySum: getArraySum
}
  • 导入:
html 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,"默认"导入,工具属性和方法使用
 */
// 默认导入
import obj from './utils.js'
console.log(obj)
const result = obj.arraySum([10, 20, 30])
console.log(result)

ECMAScript标准-命名导出和导入

  • 命名导出语法:
js 复制代码
export 修饰定义语句
  • 命名导入语法:
js 复制代码
import { 同名变量 } from '模块名或路径'
  • 语法实现:

  • utils.js 导出

js 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,封装属性和方法并"命名"导出
 */
export const baseURL = 'http://hmajax.itheima.net'
export const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0)
  • index.js 导入
js 复制代码
/**
 * 目标:基于 ECMAScript 标准语法,"命名"导入,工具属性和方法使用
 */
// 命名导入
import {baseURL, getArraySum} from './utils.js'
console.log(obj)
console.log(baseURL)
console.log(getArraySum)
const result = getArraySum([10, 21, 33])
console.log(result)

npm包

  • 将模块,代码,其他资料整合成一个文件夹,这个文件夹就叫包

  • 包分类:

项目包:主要用于编写项目和业务逻辑

软件包:封装工具和方法进行使用

包管理工具

  • 初始化清单文件: npm init -y
  • 下载软件包:npm i 软件包名称
  • 使用软件包
html 复制代码
/**
 * 目标:使用 npm 下载 dayjs 软件包来格式化日期时间
 *  1. (可选)初始化项目清单文件,命令:npm init -y
 *  2. 下载软件包到当前项目,命令:npm i 软件包名称
 *  3. 使用软件包
 */
// 3. 使用软件包
const dayjs = require('dayjs')
const nowDateStr = dayjs().format('YYYY-MM-DD')
console.log(nowDateStr)
  • 使用流程图:

npm全局软件包-nodemon

  1. 本地软件包:只在当前项目内使用,存在于 node_modules
  2. 全局软件包:本机所有项目使用,存在于系统设置的位置
  3. nodemon 作用:替代 node 命令,检测代码更改,自动重启程序
  4. 使用:
  • 安装:npm i nodemon -g (-g 代表安装到全局环境中)
  • 运行:nodemon 待执行的目标 js 文件

express

基本知识

  • 就是一个 npm上的第三方包,提供了快速创建Web服务器的便捷方法
  • 相较于http,express是基于内置的 http模块进一步封装出来的,开发效率更高

1.安装:

html 复制代码
npm i express@4.17.1

2.创建基本的Web 服务器

3...监听 GET 、POST请求

4.把内容响应给客户端 res.send()

5.获取URL 中携带的查询参数:通过 req.query 对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数

6.获取URL 中的动态参数:通过 req.params 对象,可以访问到URL中,通过:匹配到的动态参数

html 复制代码
// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

// 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
  res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
  res.send('请求成功')
})
app.get('/', (req, res) => {
  // 通过 req.query 可以获取到客户端发送过来的 查询参数
  // 注意:默认情况下,req.query 是一个空对象
  console.log(req.query)
  res.send(req.query)
})
// 注意:这里的 :id 是一个动态的参数
app.get('/user/:ids/:username', (req, res) => {
  // req.params 是动态匹配到的 URL 参数,默认也是一个空对象
  console.log(req.params)
  res.send(req.params)
})

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

express路由

  • 在 Express中,路由指的是客户端的请求与服务器处理函数之间的映射关系
  • 由3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数

1.路由匹配过程:

  • 每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数

用法:

1)创建路由模块对应的 .js文件

2)调用 express.Router()函数创建路由对象

3)向路由对象上挂载具体的路由

4)使用 module.exports 向外共享路由对象

html 复制代码
var express = require('express')     //1.导入express
var router = express.Router()        //2.创建路由对象

router.get('/user/list', function (req,res) {  //3.挂载获取用户列表的路由
res.send('Get user list')
})
router.post('/user/add', function (req,res) {  //4.挂载添加用户的路由
res.send('Add new user')
})

moudle.export = router                          //5.向外导出路由对象

5)使用app.use()函数注册路由模块

html 复制代码
//1.导入路由模块
const userRouter = require('./router/user.js')
//2.使用app.use()注册路由模块,并添加统一的访问前缀 /api
app.use('/api',userRouter)

express中间件

  • 当一个请求到达 Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
html 复制代码
//包含 req, res, next 三个参数,next() 参数把流转关系交给下一个中间件或路由
const mw = function(req, res, next){
	next()
}
html 复制代码
const express = require('express')
const app = express()

// // 定义一个最简单的中间件函数
// const mw = function (req, res, next) {
//   console.log('这是最简单的中间件函数')
//   // 把流转关系,转交给下一个中间件或路由
//   next()
// }

// // 将 mw 注册为全局生效的中间件
// app.use(mw)

// 这是定义全局中间件的简化形式
app.use((req, res, next) => {
  console.log('这是最简单的中间件函数')
  next()
})

app.get('/', (req, res) => {
  console.log('调用了 / 这个路由')
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  console.log('调用了 /user 这个路由')
  res.send('User page.')
})

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

使用express写接口

html 复制代码
// 导入 express
const express = require('express')
// 创建服务器实例
const app = express()

// 配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false }))

// 必须在配置 cors 中间件之前,配置 JSONP 的接口
app.get('/api/jsonp', (req, res) => {
  // TODO: 定义 JSONP 接口具体的实现过程
  // 1. 得到函数的名称
  const funcName = req.query.callback
  // 2. 定义要发送到客户端的数据对象
  const data = { name: 'zs', age: 22 }
  // 3. 拼接出一个函数的调用
  const scriptStr = `${funcName}(${JSON.stringify(data)})`
  // 4. 把拼接的字符串,响应给客户端
  res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')
app.use(cors())

// 导入路由模块
const router = require('./16.apiRouter')
// 把路由模块,注册到 app 上
app.use('/api', router)

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

数据库

  • 数据库(database)是用来组织、存储和管理数据的仓库
  • MySQL是目前使用最广泛、流行度最高的开源免费数据库
  • SQL 是一门数据库编程语言,能够让我们以编程的形式,操作数据库里面的数据。

基本操作

1.连接数据库

2.了解主界面组成部分

3.创建数据库

4.创建数据表

5.向表中写入数据

使用SQL管理数据库

  • 掌握使用SQL从数据表中:查询数据(select)、插入数据(insertinto)、更新数据(update)、删除数据(delete)
html 复制代码
//获取数据表
select * from users

//从user表中获取username和password的内容
select username, password from user
  • 插入数据
  • update修改数据

把 users表中id为7的用户密码,更新为888888

  • 删除数据

从 users表中,删除id 为4的用户,示例如下

  • where语句
html 复制代码
//1.查询status为1的所有用户
SELECT * FROM use  WHERE status=1
//2.查询id大于4的所有用户
OM use  WHERE status>4

在项目中操作MySQL

1.安装 mysql 模块

html 复制代码
npm i mysql

2.配置mysql

html 复制代码
const mysql = require('mysql')

const db = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: 'root',
    database: 'test',
})

3.检测是否能正常工作

html 复制代码
db.query('select 1', (err, results) => {
   if (err) return console.log(err.message)
   console.log(results)
})

4.使用 mysql 模块操作 MySQL 数据库

  • 查询数据
html 复制代码
// 查询 users 表中所有的数据
/* const sqlStr = 'select * from users'
db.query(sqlStr, (err, results) => {
  // 查询数据失败
  if (err) return console.log(err.message)
  // 查询数据成功
  // 注意:如果执行的是 select 查询语句,则执行的结果是数组
  console.log(results)
}) */
  • 插入数据
html 复制代码
// 向 users 表中,新增一条数据,其中 username 的值为 Spider-Man,password 的值为 pcc123
/* const user = { username: 'Spider-Man', password: 'pcc123' }
// 定义待执行的 SQL 语句
const sqlStr = 'insert into users (username, password) values (?, ?)'
// 执行 SQL 语句
db.query(sqlStr, [user.username, user.password], (err, results) => {
  // 执行 SQL 语句失败了
  if (err) return console.log(err.message)
  // 成功了
  // 注意:如果执行的是 insert into 插入语句,则 results 是一个对象
  // 可以通过 affectedRows 属性,来判断是否插入数据成功
  if (results.affectedRows === 1) {
    console.log('插入数据成功!')
  }
}) */
------------------------------------------------------------------
//插入数据便捷方式
/* const user = { username: 'Spider-Man2', password: 'pcc4321' }
// 定义待执行的 SQL 语句
const sqlStr = 'insert into users set ?'
// 执行 SQL 语句
db.query(sqlStr, user, (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('插入数据成功')
  }
}) */
  • 更新数据
html 复制代码
// 演示如何更新用户的信息
/* const user = { id: 6, username: 'aaa', password: '000' }
// 定义 SQL 语句
const sqlStr = 'update users set username=?, password=? where id=?'
// 执行 SQL 语句
db.query(sqlStr, [user.username, user.password, user.id], (err, results) => {
  if (err) return console.log(err.message)
  // 注意:执行了 update 语句之后,执行的结果,也是一个对象,可以通过 affectedRows 判断是否更新成功
  if (results.affectedRows === 1) {
    console.log('更新成功')
  }
}) */
-----------------------------------------------------------------------------
// 演示更新数据的便捷方式
/* const user = { id: 6, username: 'aaaa', password: '0000' }
// 定义 SQL 语句
const sqlStr = 'update users set ? where id=?'
// 执行 SQL 语句
db.query(sqlStr, [user, user.id], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('更新数据成功')
  }
}) */
  • 删除数据:
html 复制代码
const sql = 'delete from users where id=?'
//4代表user.id
//若SQL语句中有多个占位符,则必须使用数组为每个占位符指定具体的值
//若SQL语句中只有一个占位符,则可以省略
db.query(sql, 4, (err, results) => {
  	if (err) return console.log(err.message)
    if (results.affectedRows === 1) console.log('删除数据成功')
})
  • 标记删除:

由于使用 delete 语句会真正删除数据,保险起见,使用标记删除的形式,模拟删除的动作。即在表中设置状态status字段,标记当前的数据是否被删除

html 复制代码
const sqlStr = 'update users set status=? where id=?'
db.query(sqlStr, [1, 6], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('标记删除成功')
  }
})

前后端的身份认证

Web开发模式

目前主流的有两类:基于服务端渲染 的传统Web开发模式、基于前后端分离的新型Web开发模式

1)服务端渲染的传统Web开发模式:服务器发送给客户端的 HTML 页面,是在服务器通过字符串的拼接动态生成的→客户端不需要使用 Ajax 额外请求页面的数据

利:前端耗时短;有利于SEO

缺点:占用服务器资源;不利于前后的分离

html 复制代码
app.get('/index.html', (req, res) => {
//1.要渲染的数据
  const user = { name: 'Bruce', age: 29 }
//2.服务器端通过字符串的拼接,动态生成HTML内容
  const html = `<h1>username:${user.name}, age:${user.age}</h1>`
//3.把生成好的页面内容响应给客户端→故客户端拿到的是带有真实数据的HTML页面
  res.send(html)
})

2)前后端分离的 Web 开发模式:即后端只负责提供API 接口,前端使用 Ajax 调用接口的开发模式

  • 利:前端专注页面开发,后端专注接口开发;页面局部刷新,无需重新请求页面
  • 不利:不利于 SEO。完整的 HTML 页面在浏览器拼接完成,因此爬虫无法爬取页面的有效信息。→利用Vue、React等前端框架的SSR(serverside render)技术能够很好的解决SEO问题

3)应用场景:

  • 企业级网站,主要功能为展示,无复杂交互且需要良好的SEO,故采用服务器端渲染;
  • 后台管理项目,交互性较强,不需要考虑SEO→前后端分离的 Web 开发模式

身份认证

  • 身份认证又称为鉴权,通过一定的手段,完成对用户身份的确认。
  • 服务端渲染推荐使用session认证机制;前后端分离推荐使用JWT认证机制
session认证机制
  • 工作原理:

  • 安装express-session中间件

html 复制代码
npm install express-session
  • 配置中间件:需要通过 app.use()来注册 session 中间件
html 复制代码
const session = require('express-session')
app.use(
	session({
		secret: '做一只猫', 		// secret 属性的值为任意字符串
		resave: false,			//固定写法
		saveUninitalized: true	//固定写法
  })
)
  • 向sessin中存数据:通过req.session访问session对象,存储用户信息
html 复制代码
app.post('/api/login', (req, res) => {
	//判断用户提交的登录信息是否正确
	if(req.body.username !== 'admin' || req.body.password !== '000000'){
		return res.send({status: 1, msg: '登录失败'})
	}
	req.session.user = req.body	//将用户的信息存储到S
	req.session.isLogin = true

 	res.send({ status: 0, msg: 'login done' })
})
  • 从session中取数据
html 复制代码
app.get('/api/username', (req, res) => {
	//判断用户是否登录
 	if (!req.session.isLogin) {
    	return res.send({ status: 1, msg: 'fail' })
  	}
  	res.send({ status: 0, msg: 'success', username: req.session.user.username })
})
  • 清空数据
html 复制代码
app.post('/api/logout', (req, res) => {
 	// 清空当前客户端的session信息
	req.session.destroy()
	res.send({ status: 0, msg: '退出登录成功' })
})
  • 局限性:Session 认证机制需要配合 Cookie 才能实现。由于Cookie默认不支持跨域访问→当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域 Session认证
JWT认证机制
  • 当前端需要跨域请求后端接口的时候,推荐使用JWT认证机制

  • 工作原理:

  • JWT组成部分:Header(头部)、Payload(有效荷载)、Signature(签名),三者使用.分隔

  • 使用方法:把 JWT 放在 HTTP 请求头的 Authorization 字段中

html 复制代码
Authorization: Bearer <token>

Express 使用 JWT

1)安装JWT相关的包

ljsonwebtoken 用于生成 JWT 字符串

express-jwt用于将 JWT 字符串解析还原成JSON 对象

html 复制代码
//安装多个包中间用空格隔开
npm install jsonwebtoken express-jwt

2)导入 JWT 相关的包:使用 require() 函数,分别导入 JWT相关的两个包

html 复制代码
//1.导入用于生成字符串的包
const jwt = require('jsonwebtoken')
//2.导入用于将客户端发送过来的IWT字符串,解析还原称JSON对象的包
const expressJWT = require('express-jwt')

3)定义secret 密钥:

为保证 JWT 字符串安全性,需定义一个用于加密和解密的secret密钥

html 复制代码
/ 密钥可以为任意字符串
const secretKey = 'dimple'

4)在登录成功后生成 JWT 字符串

调用 jsonwebtoken 包提供的sign()方法,将用户的信息加密成JWT字符串,响应给客户端

html 复制代码
app.post('/api/login', (req, res) => {
 //用户登录成功后,生成JWT字符串,通过token属性响应给客户端
  res.send({
    status: 200,
    message: '登录成功',
    // 调用jwt.sign() 生成 JWT 字符串,三个参数分别是用户信息对象,加密密钥,配置对象
    token: jwt.sign({username: userInfo.username}, secretKey, {expiresIn: '30s'})
  })
})

5)将JWT 字符串还原为 JSON 对象

html 复制代码
// unless({ path: [/^\/api\//] }) 指定哪些接口无需访问权限
app.use(expressJWT({ 
	secret: secretKey
}).unless({ path: [/^\/api\//] }))

6)使用req.user 获取用户信息

html 复制代码
app.get('/admin/getinfo', (req, res) => {
  console.log(req.user)
  res.send({
    status: 200,
    message: '获取信息成功',
    //data: req.user
    //6.0版本后改用req.auth
    data: req.auth
  })
})

7)捕获解析JWT 失败后产生的错误

html 复制代码
app.use((err, req, res, next) => {
//token解析失败导致的错误
  if (err.name === 'UnauthorizedError') {
    return res.send({ status: 401, message: 'Invalid token' })
  }
//其它原因导致的错误
  res.send({ status: 500, message: 'Unknown error' })
})
相关推荐
凄凄迷人3 分钟前
如何调试 chrome 崩溃日志(MAC)
前端·chrome·macos·crash
蒙特网站7 分钟前
网站布局编辑器前端开发:设计要点与关键考量
前端·javascript·学习·html
yun_shuo8 分钟前
文件内容扫描工具
electron·node.js·vue
理想不理想v9 分钟前
前端开发工程师需要学什么?
java·前端·vue.js·webpack·node.js
fhf23 分钟前
感觉根本等不到35岁AI就把我裁了
前端·人工智能·程序员
hummhumm23 分钟前
第 36 章 - Go语言 服务网格
java·运维·前端·后端·python·golang·java-ee
鸿·蒙27 分钟前
【PTA】【数据库】【SQL命令】编程题2
数据库·sql·pta
daqinzl33 分钟前
node.js @ffmpeg-installer/ffmpeg 桌面推流
ffmpeg·node.js·installe·桌面推流
蒜蓉大猩猩1 小时前
Vue.js - 组件化编程
开发语言·前端·javascript·vue.js·前端框架·ecmascript
对酒当歌丶人生几何1 小时前
Mybatis控制台打印SQL执行信息(执行方法、执行SQL、执行时间)
java·数据库·sql·mybatis