当前位置: 首页 > news >正文

【Node.JS】koa

文章目录

  • 概述
  • koa和express对比
  • koa下载安装
  • 使用
    • 1.创建koa项目文件目录
    • 2. 创建koa服务
    • 3. 添加路由 koa-router
    • 4. 数据库服务 mongodb
    • 5. 添加请求参数json处理 koa-bodyparser
    • 6. 用户接口举例
    • 7.引入koa一些常用插件
    • 8.用户登录验证 koa-jwt
    • 9.webpack生产打包
  • 来源

概述

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

koa和express对比

  • Koa采用洋葱模型

通常都会说Koa是洋葱模型,这重点在于中间件的设计。但是按照上面的分析,会发现Express也是类似的,不同的是Express中间件机制使用了Callback 实现,这样如果出现异步则可能会使你在执行顺序上感到困惑,因此如果我们想做接口耗时统计、错误处理Koa的这种中间件模式处理起来更方便些。最后一点响应机制也很重要,
Koa不是立即响应,是整个中间件处理完成在最外层进行了响应,而Express则是立即响应。

  • Koa更轻量

koa不提供内置的中间件;
koa不提供路由,而是把路由这个库分离出来了(koa/router)

  • Context对象

koa增加了一个Context的对象,作为这次请求的上下文对象(在koa2中作为中间件的第一个参数传入)。同时Context上也挂载了Request和Response两个对象。Express类似, 这两个对象都提供了大量的便捷方法辅助开发这样的话对于在保存一些公有的参 数的话变得更加合情合理。

  • 异步流程控制

express采用callback来处理异步,koa采用async/await。
async/await使用同步的写法来处理异步,明显好于callback和promise,

  • 中间件模型

express基于connect中间件,线性模型;
koa中间件采用洋葱模型(对于每个中间件,在完成了-些事情后,可以非常优雅的将控制权传递给下一个中间件,并能够等待它完成,当后续的中间件完成处理后,控制权又回到了自己)
在这里插入图片描述
同步代码
同步方法没有什么区别:

  • 01-express-同步.js
const express = require("express")
const app = express()app.use((req, res, next) => {console.log("111111")next()console.log("333333")res.send("hello world")
})app.use((req, res, next) => {// 同步操作console.log("22222")
})app.listen(3000)

运行输出

111111
22222
333333
  • 01-koa-同步 .js
const Koa = require("koa")
const app = new Koa()app.use((ctx, next) => {console.log("111111")next()console.log("333333")ctx.body("hello world")
})app.use((ctx, next) => {// 同步操作console.log("22222")
})app.listen(3000)

运行输出:

111111
22222
333333

异步代码
next()表示可以执行下一个中间件,当下一个中间件执行完成之后,如果上一个中间件没有执行完,再返回上一个中间件继续执行。

  • 01-express-异步.js
const express = require("express")
const app = express()app.use(async (req, res, next) => {console.log("111111")await next()console.log("444444")res.send("hello world")
})app.use(async (req, res, next) => {console.log("22222")// 异步操作await delay(1000)console.log("33333")
})function delay(time) {return new Promise((resolve, reject) => {setTimeout(resolve,time)})
}app.listen(3000)

运行输出:

111111
22222
444444
33333

由于next()返回的不是promise对象因此await不起作用,所以输出不会像我们所想输出

  • 01-koa-异步.js
const Koa = require("koa")
const app = new Koa()app.use((ctx, next) => {console.log("111111")next()console.log("444444")
})app.use((ctx, next) => {console.log("22222")// 异步操作delay(1000)console.log("33333")
})function delay(time) {return new Promise((resolve, reject) => {setTimeout(resolve,time)})
}
app.listen(3000)

运行输出:

111111
22222
33333
444444

koa洋葱模型,正常执行。

koa下载安装

npm init
npm i koa

Koa基本框架

const Koa = require("koa")const app = new Koa()// ctx=context 相当于res和req的合并
app.use((ctx, next) => {})app.listen(3000)

使用

1.创建koa项目文件目录

我们学习的第一步就是先搭好项目目录,这里会有我们项目中使用到的任何东西。

// 创建项目文件夹  也可手动创建
mkdir  koa-app// 进入项目文件
cd  koa-app// 添加koa依赖    
// 根据自己的包管理器执行自己的命令 我这里以yarn举例
yarn add koa -S// 新建入口文件
echo >index.js// 创建变量管理目录   constmkdir const// 创建数据库管理目录   databasemkdir database// 创建中间件管理目录   middlewaresmkdir middlewares// 创建路由管理目录   routermkdir router// 创建静态资源管理目录   staticmkdir static// 创建工具类管理目录   utilsmkdir utils// 创建html文件管理目录   view
// 主要用于测试自己接口
mkdir const// 创建webpack打包文件echo >webpack.config.js

这时候我们生成的目录结构大致如下

--koa-app--const--database--middlewares--router--static--utils--view-- index.js-- packjson.js-- webpack.config.js

2. 创建koa服务

这时候我们就可以创建koa服务,启动后就可以访问服务器目录了。

// index.jsconst Koa = require("koa");const app = new Koa();app.use(async ctx => {ctx.body = "hellO  欢迎使用koa"
})app.listen(3000);// 启动koa服务node  index.js// 访问服务在浏览器地址栏输入  localhost:3000

启动服务后我们打开浏览器就能看到"hellO 欢迎使用koa"说明我们koa程序运行成功。

3. 添加路由 koa-router

我们后台服务已经搭建好了,那下一步必不可少的就是路由管理了,这里我们使用koa-router插件

//  /router/index.js// 引入koa-router
const  Router = require('koa-router');
// 引入user路由对象
const user = require('./user/index.js');
const view = require('./view/index.js')
const goods = require('./goods/index.js');
const category = require('./category/index.js');
const upload = require('./upload/index.js')
const rule = require('./rule/index.js')
const menu = require('./menu/index.js')
const role = require('./role/index.js')
const managerUser = require('./managerUser/index.js')
const attribute = require('./attribute/index.js')// 生成新的router对象
let router = new Router();// 添加路由管理
router.use('/api/user', user.routes())
router.use('/view', view.routes())
router.use('/api/goods', goods.routes())
router.use('/api/category', category.routes())
router.use('/api/upload', upload.routes())
router.use('/api/rule', rule.routes())
router.use('/api/menu', menu.routes())
router.use('/api/role', role.routes())
router.use('/api/managerUser', managerUser.routes())
router.use('/api/attribute', attribute.routes())// 导出路由
module.exports = router

这里我是以自己写好的项目文件直接复制了,如果是测试的话不需要导入那么多路由对象,导入一个自己已经写好的就行了。

接下来我们就需要修改index.js文件与编写user路由

// /router/user/index.jsrouter.get('/list', async (ctx) => {ctx.body =  {code: 200,message: '访问成功'}
})// index.jsconst Koa = require("koa");
const router = require("./router/index.js"); // 路由
const app = new Koa();// 添加路由中间件
app.use(router.routes()).use(router.allowedMethods());
app.use(async ctx => {ctx.body = "hellO  欢迎使用koa"
})app.listen(3000);

这时候我们重新启动koa服务后,访问localhost/3000/api/user/list 就能获取ctx.body的内容了。 做到这里我们已经实现了自己的第一个接口了。剩下就是去数据库里面获取数据就形成了后台数据服务了。 是不是很棒呢!

4. 数据库服务 mongodb

这里因为学习的是mongodb数据库,所以例子都会是以mongodb数据库为例。其实用mysql的同学也可以自己去看一下mysql的引。

数据库的引入主要是做了2个步骤, 第一连接数据库,第二创建数据model对象,并执行数据库操作。 mongodb使用的是mdb语句去做的查询,mysql则是使用的sql语句。

当然每个数据库特性都不一样,在什么项目中使用什么数据库都需要在搭建项目目录的时候考虑到的,比如mysql, oracle 都是关系型的,在做一些数据关联性强的一些网站上更加适用比如电商,金融,证券,医疗等。 而非关系型的mongodb数据因为数据结构更加多变,适用与一些日记管理,博客,官网等

话不多说,我们来创建我们的数据库服务吧

添加依赖

// 添加依赖
yarn add glob mongoose  -S

创建mongosse文件

// 添加mongoose文件   /database/index.js
// 添加mongosse
const mongoose = require('mongoose')
// 数据库访问地址
const db = "mongodb://127.0.0.1/waimai"
// glob :提供匹配文件路径的方法,可以快速地找 到需要读取的文件
const glob  = require('glob');
const { resolve } = require('path')// 初始化文档模式
exports.initSchemas = async () => {await  glob.sync(resolve(__dirname, './schema', './*.js')).forEach((v) => {require(v)})
}exports.connect = () => {// 连接数据库mongoose.connect(db)return new Promise((resolve, reject) => {// 添加数据库断开监听事件mongoose.connection.on('disconnected', () => {console.log('数据库断开---------------')mongoose.connect(db)})// 添加数据库启动监听事件mongoose.connection.on('open', () => {console.log('数据库连接---------------1')mongoose.connect(db)resolve();})})
}// index.js   引入mongoose文件// moogose初始化
const { connect, initSchemas } = require("./database/index");(async () => {await connect();await initSchemas();
})();

我们重启服务后就能连接到mongodb数据库了, 在conosle里面我们能看到 数据库连接字样

5. 添加请求参数json处理 koa-bodyparser

添加新依赖

yarn add koa-bodyparser -D

更新index.js

const bodyParser = require("koa-bodyparser"); // requeast请求app.use(bodyParser());

6. 用户接口举例

添加新依赖

yarn add bcrypt -D

创建mongoose.model模型

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let ObjectId = Schema.Types.ObjectId;
// const bcrypt = require('bcrypt');const SALT_WORK_FACTOR = 10;// 前台用户表接口
const userSchema = new Schema({UserId: ObjectId,userName: {unique: true,type: String},passWord: String,avator: String,hashPassword: String,nikeName: String,address: String,isBlack: Boolean,sex: String,createAt: {type: Date,default: Date.now(),},lastLoginAt: {type: Date,default: Date.now(),},
})// 每次存储时都要执行,加盐加密
userSchema.pre('save', function (next){bcrypt.genSalt(SALT_WORK_FACTOR,(err,salt)=>{if(err) return next(err)bcrypt.hash(this.passWord,salt,(err,hash)=>{if(err) return next(err)this.hashPassword = hashnext()})})
})// 添加自定义方法
userSchema.methods = {// 对比密码一致性comparePassword: (_password, hashPassword) => {return new Promise((resolve, reject) => {// 对比密码方法bcrypt.compare(_password, hashPassword, (err, isMatch) => {if(!err) resolve(isMatch);reject(err)})}) }
}
// 发布模型
module.exports = mongoose.model('User', userSchema)

添加用户接口

const Router  = require('koa-router');
const mongoose = require('mongoose')
let router = new Router();
const User = require('../../database/schema/User')// 用户注册
router.post('/register', async (ctx) => {const userName = ctx.request.body.userName;const passWord = ctx.request.body.passWord;let newUser = new User({userName,passWord,}).save().then((res) => {ctx.body = {code: 200,message: "添加用户成功",};}).catch((err) => {ctx.body = {code: 500,message: "添加失败" + err,};});;
})router.get('/list', async (ctx) => {// 引入user模型// const User  = mongoose.model('User');const uid  = ctx.request.query.uid || '';//  分页 pagelet page = ctx.request.body.page || 1;//  分页每页数量let limit = ctx.request.body.limit || 8;// 上一次获取位置const start =(page - 1)*limit;// console.log( userName, User, 'User')const result =  await User.find().exec()console.log(result, 'result')ctx.body = {code: 200,data: result.slice((page-1)*limit, page*limit),page: {page: page,limit,total: result.length ,lastPage: parseInt(result.length / limit)}}// ctx.body = ctx.request.body;
})module.exports = router;

这时候我们就已经写好了用户添加接口与用户列表接口。因为用户的密码需要保密,我们在这里用了bcrypt去做了加盐加密,考虑到了bcrypt的加密是不可逆的所以我们这里用了passWord对原密码做了保存。

这里我们使用了schema的自定义方法与 schema的钩子函数

  • userSchema.methods

向由该 schema 编译的 model 构造的 document 添加一个实例方法.

  • userSchema.pre

给 schema 定义一个前置钩子 (pre hook)

7.引入koa一些常用插件

处理跨域问题 koa2-cors

yarn add koa2-cors -D// index,js
const koa2cors = require("koa2-cors"); // 配置跨域app.use(koa2cors({origin: "*",maxAge: 5,allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));

添加静态文件目录 koa-static

yarn add koa-static -D// index.jsconst koaStatic = require("koa-static"); // 静态目录
app.use(koaStatic("./"));

添加websokit服务 koa-websocket

yanr add  koa-websocket -S// index.jsconst websocket = require("koa-websocket"); // socket// 这时候app需用被websoket包裹
const app = websocket(new Koa());// 建立socket连接
app.ws.use(async (ctx) => {// the websocket is added to the context as `ctx.websocket`.ctx.websocket.send("我是服务器");ctx.websocket.on("message", function (message) {// do somethingconst msg = message.toString("utf-8");console.log("客户端发来消息", msg);});
});

添加xss防御

yarn add xss -S// index.js
const xss = require('./middlewares/xss.js') // xssapp.use(xss())// /middlewares/xss.jsconst xss = require("xss"); // 需要 npm install xss -Sconst xssHandler = () => {return async (ctx, next) => {try {const body = ctx.request.body;for (const key in body) {if (typeof body[key] === "string") {body[key] = xss(body[key]);}}// 一定要添加awaitawait next();} catch (error) {// console.error(error)throw error;}};
};module.exports = xssHandler;

图片文件处理 koa-multer

yarn add koa-multer -D//  /router/upload/index.js
const Router  = require('koa-router');
let router = new Router();
const multer = require('koa-multer');//配置
const storage = multer.diskStorage({//配置图片上传的目录destination: function (req, file, cb) {console.log('destination')cb(null, 'static/images/'); //注意路径必须存在},//图片上传完成重命名filename: function (req, file, cb) {console.log('filename')// 获取后缀名var fileFormat = file.originalname.split('.');cb(null, Date.now() + '.' + fileFormat[fileFormat.length - 1]);},
});
const upload = multer({ storage: storage });
router.post('/img', upload.single('file'), async ctx => {console.log(ctx.req.file, 'ctx.req.file')ctx.body = {code: 200, data: {filename: ctx.req.file.filename,//返回文件名 path: ctx.req.file.destination + ctx.req.file.filename}} 
})module.exports = router;

请求参数验证 Joi

访问接口时会先校验参数是否传对,如果对继续后面的逻辑,如果参数校验不对则会直接返回错误信息给前端。

yarn add Joi -D// /router/user/index.jsconst Joi = require("joi");
const validateSchemaJoi = require("../../middlewares/validateSchemaJoi");
const userSchema = Joi.object({userName: Joi.string().min(1).required(),
});// 用户注册
router.post('/register', validateSchemaJoi("post", userSchema), async (ctx) => {// 注册流程
})// /middlewares/validateSchemaJoi
function validateSchemaJoi(method, schema) {async function validateSchema (ctx, next) {let data = undefined;if (method === 'get') {data = ctx.request.query;} else {data = ctx.request.body;}const { value, error } = schema.validate(data);if (error) {ctx.body = {code: 400,error};} else {next();}}return validateSchema;}module.exports =  validateSchemaJoi;

8.用户登录验证 koa-jwt

用户验证有3种方式

1。cookie 2. session 3. token

这里我们就以token来做用户验证。

添加依赖

yarn add koa-jwt jsonwebtoken -S

用户登录添加token返回

//  /router/user/index.jsvar jwt = require('jsonwebtoken');router.post('/login', async (ctx) => {const userName = ctx.request.body.userName;const passWord = ctx.request.body.passWord;// 查询用户是否存在await User.findOne({ userName: userName }).exec().then(async result => {// 如果用户名存在if(result) {let newUser = new User();// 校验用户密码await newUser.comparePassword(passWord, result.hashPassword).then(isMatch => {// 如果用户校验成功if(isMatch) {// 生成tokenconst token = jwt.sign({userName: result.userName}, 'secret', { expiresIn: '2h' });// 返回给前端ctx.body = {code: 200,message: isMatch,data: {token: token,uid: result._id}}}else {ctx.body = {code: 500,message: isMatch}}})}else {ctx.body = {code: 500,message: '用户名不存在!'}}}).catch(err => {// console.log('result----err')ctx.body = {code: 500,message: err,}})})

添加token白名单 不拦截请求

const { jwtWhiteList } = require("./const/jwtWhiteList"); // token白名单// /const/jwtWhiteList.jsconst jwtWhiteList  = [/^\/api\/user\/login/,/^\/view/,/^\/static/,"/api/managerUser/login","/api/goods/getGoodsDetailsInfo","/api/upload/img"
]
module.exports = {jwtWhiteList
}

添加路由token验证拦截

token路由拦截主要做了以下这几件事

1.koa-jwt对每个请求头部信息进行token校验,如果用户校验失败就返回401,过滤掉白名单的请求。

2.在路由中间件上面添加中间件,当用户token失效后我们就会走401步骤 返回用户token失效信息,让前端去重定向到登录页

3.用户token都是有时效性的,当然时效性越短越好,因为没用数据库去存储token所以在项目重启后可能会有失效问题,没验证过。我这默认是2小时,当小于一半的失效时间时我就会生成新的token交予前端重新生成。也就是所谓的token续存机制。

// index.jsconst jwt = require("koa-jwt"); // token验证
const jwtToken = require('jsonwebtoken');// 路由拦截器中间件
app.use(function (ctx, next) {// console.log("ce0", ctx.header.authorization)if (ctx.header && ctx.header.authorization) {const parts = ctx.header.authorization.split(" ");if (parts.length === 2) {//取出tokenconst scheme = parts[0];const token = parts[1];if (/^Bearer$/i.test(scheme)) {try {const decoded = jwtToken.verify(token, 'secret',{ complete: true });// iat: 签发时间  exp: 过期时间const { iat, exp, userName  } = decoded.payload;const nowTime = new Date().getTime()/1000;const lastTime  = (exp - nowTime)/60;// 当前事件离过期时间还剩一半的时候更新token 如果过期就走401if(decoded && 0 < lastTime &&  lastTime< ((exp-iat)/60)/2) {// console.log('更新token0')const newToken = jwtToken.sign({userName: userName}, 'secret', { expiresIn: '2h' });// console.log('更新token1', newToken)ctx.res.setHeader('Authorization', newToken)}} catch (error) {console.log("ce3")//token过期 }}}}return next().catch((err) => {if (401 == err.status || err.status === 301) {ctx.status = 401;ctx.body = {code: err.status,message: "token已经失效!!!!"};// ctx.body = {error: err.originalError ? err.originalError.message : err.message};} else {throw err;}});
});// 添加token中间件
app.use(jwt({ secret: "secret" }).unless({ path: jwtWhiteList }));

9.webpack生产打包

这里就做了简单的js打包,打包后的文件体积会变小,因为webpack设置mode为生产环境后默认就做了许多处理。

// webpack.config.js
const webpack = require("webpack");const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const nodeExternals = require("webpack-node-externals");// const MinifyPlugin = require('babel-minify-webpack-plugin');const CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = {entry: "./index.js",mode: "production",output: {path: path.resolve(__dirname, "./dist"),filename: "[name].js",},target: "node",externals: [nodeExternals()], //node 打包可去除一些警告module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: [{loader: "babel-loader",options: {presets: ["@babel/preset-env"], //兼容es6,并添加.babelrc},},],},],},plugins: [// 清楚distnew CleanWebpackPlugin(),// js压缩// split切片// 复制静态目录new CopyWebpackPlugin({patterns: [{from: path.resolve(__dirname, './static'),to: path.resolve(__dirname, './dist/static')}]})// new MinifyPlugin() //压缩js],};// packjson.js  添加启动指令"build": "webpack --progress  --config webpack.config.js",
"prd_server": "node ./dist/main.js"

来源

你需要的koa入门教学
koa框架

相关文章:

【Node.JS】koa

文章目录 概述koa和express对比koa下载安装使用1.创建koa项目文件目录2. 创建koa服务3. 添加路由 koa-router4. 数据库服务 mongodb5. 添加请求参数json处理 koa-bodyparser6. 用户接口举例7.引入koa一些常用插件8.用户登录验证 koa-jwt9.webpack生产打包 来源 概述 Koa 是一个…...

工作日志- 不定期更新

1. protobuf中使用import引用其他proto文件&#xff0c;生成后在go语言的go modules中import 包名报错问题。 public.proto文件 //protoc --go_outpluginsgrpc:. public.proto syntax "proto3";package public;option go_package "self/game-service/msg/pu…...

Qt使用opencv打开摄像头

1.效果图 2.代码 #include "widget.h"#include <QApplication>#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>#include <QImage> #include <QLabel> #incl…...

Redis的Hash数据结构中100万对field和value,field是自增时如何优化?优化Hash结构。

ZipList使用是有条件的&#xff0c;当entry数据量太大时就会启用哈希结构&#xff0c;占用内存空间 1.设置bigkey的上限 在redis.config中设置 2.拆分为string类型 String底层结果没有太多优化&#xff0c;占用内存多 想要批量获取数据麻烦 3.拆分为小的hash 将id/100作为…...

二十四种设计模式与六大设计原则(一):【策略模式、代理模式、单例模式、多例模式、工厂方法模式、抽象工厂模式】的定义、举例说明、核心思想、适用场景和优缺点

目录 策略模式【Strategy Pattern】 定义 举例说明 核心思想 适用场景 优缺点 代理模式【Proxy Pattern】 定义 举例说明 核心思想 适用场景 优缺点 单例模式【Singleton Pattern】 定义 举例说明 核心思想 适用场景 优缺点 多例模式【Multition Pattern】…...

mac怎么删除python

mac 默认安装了python2&#xff1b;自己后面又安装了python3&#xff1b;为了方便&#xff0c;现在想将python3换成Anaconda3。 Anaconda是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。 Python3安装之后&#xff0c;在系统中不同目…...

【笔记】Android U RILJ 中与运营商名称SPN显示相关的日志分析

源码阅读&#xff1a;AOSPXRef 常用日志关键字 Note&#xff1a;">"下发MD&#xff0c;"<"MD上报&#xff0c;[]中的id有请求和返回的对应关系 KEYComment> OPERATOR下发MD&#xff0c;请求运营商信息< OPERATORMD上报运营商注册信息> DA…...

蓝桥杯【奇怪的捐赠】c语言

我会将这题的解题的核心思路解为将10进制转化成7进制&#xff0c;毕竟题目上说的很清楚7的几次方 然后附上我认为的最优解 #include<stdio.h> int main() {int n 1000000;int sum 0;while (n ! 0){int a;a n % 7;n n / 7;sum a ;}printf("%d", sum);retu…...

【3月比赛合集】5场可报名的「创新应用」、「数据分析」和「程序设计」大奖赛,任君挑选!

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 创新应用赛&#xff08;2场比赛&#xff09;数据分析赛&#…...

vue3 视频播放功能整体复盘梳理

回顾工作中对视频的处理&#xff0c;让工作中处理的问题的经验固化成成果&#xff0c;不仅仅是完成任务&#xff0c;还能解答任务的知识点。 遇到的问题 1、如何隐藏下载按钮&#xff1f; video 标签中的controlslist属性是可以用来控制播放器上空间的显示&#xff0c;在原来默…...

vue-ueditor-wrap上传图片报错:后端配置项没有正常加载,上传插件不能正常使用

如图所示&#xff0c;今天接收一个项目其中富文本编辑器报错 此项目为vue2项目&#xff0c;富文本编辑器为直接下载好的资源存放在public目录下的 经过排查发现报错的函数在ueditor.all.min.js文件内&#xff0c;但是ueditor.all.min.js文件夹是经过压缩的 所以直接&#xff…...

数据仓库的发展历程

数据仓库的概念可以追溯到20世纪60年代,但真正形成理论并被企业广泛应用还需要一个较长的发展过程。大致可以分为以下几个阶段: 决策支持系统(DSS)时期(1960s-1970s) 这一时期,随着管理信息系统(MIS)和电子计算机的兴起,企业开始尝试构建面向决策的数据处理系统。最初的决策支…...

MySQL开窗函数

测试环境&#xff1a;mysql8.0.18 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/window-functions.html 一、窗口函数介绍二、语法结构三、自定义窗口1.rows&#xff08;重点&#xff09;2.range3.默认窗口 四、常用窗口函数示例1.row_number & rank &…...

Java学习笔记(23)

多线程 并发 并行 多线程实现方式 1.继承Thread类 自己创建一个类extends thread类 Start方法开启线程&#xff0c;自动执行重写之后的run方法 2.实现runable接口 自己创建一个类implements runnable Myrun不能直接使用getname方法&#xff0c;因为这个方法是thread类的方法…...

nodejs下载安装以及npm、yarn安装及配置教程

1、nodejs下载安装 ​ 1.1、使用nodejs版本管理工具下载安装&#xff0c;可一键安装、切换不同nodejs版本&#xff0c; nvm-setup.zip&#xff1a;安装版&#xff0c;推荐使用 本次演示的是安装版。 1、双击安装文件 nvm-setup.exe 选择nvm安装路径 例如&#xff1a;E:\Soft…...

Playwright库page.evaluate()方法执行JavaScript 表达式

page.evaluate() 方法是 Playwright 中常用的方法之一&#xff0c;用于在页面上下文中执行 JavaScript 代码。它允许在浏览器环境中执行各种操作&#xff0c;如操作 DOM 元素、获取页面数据、执行复杂的计算等&#xff0c;并将结果返回到 Node.js 或 Python 代码中。 在 Playw…...

【微服务】OpenFeign+Sentinel集中处理远程调用异常

文章目录 1.微服务基本环境调整1.对10004模块的application.yml调整2.启动nacos以及一个消费者两个提供者3.测试1.输入http://localhost:8848/nacos/index.html 来查看注册情况2.浏览器访问 http://localhost:81/member/nacos/consumer/get/13.结果 2.使用OpenFeign实现微服务模…...

集合嵌套,Collections,斗地主案例,日志框架

文章目录 集合嵌套List嵌套ListList嵌套MapMap嵌套Map Collections类方法排序 sort 乱序 shuffle 斗地主案例需求思路代码 日志框架介绍优势体系结构Logback概述快速入门配置详解 集合嵌套 List嵌套List public static void main(String[] args){//一个年级有许多班级&#xf…...

maven pom relativePath属性的作用

maven pom relativePath属性的作用 文章目录 maven pom relativePath属性的作用一、relativePath出现的地方二、relativePath默认值三、四、<relativePath>一个pom路径 一、relativePath出现的地方 搭建maven项目&#xff0c;子模块指定父模块试&#xff0c;经常会在par…...

【STM32 HAL库SPI/QSPI协议学习,基于外部Flash读取。】

1、SPI协议 简介 SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface)&#xff0c;即串行外围设备接口&#xff0c;是 一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间&#xff0c;要求通讯速率 较高的场合。 SPI 物理层 SPI 通讯…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...