【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框架

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/291180.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI发布Voice Engine模型!用AI合成你的声音!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

6_相机坐标系_相机4个坐标系详述

相机系列文章是用来记录使用opencv3来完成单目相机和6轴机械臂手眼标定。本人吃饭的主职是linux下6轴机械臂相关应用开发。但对于机械臂运动学、相机应用等都非常感兴趣&#xff0c;所以对一些线性代数基础薄弱又想深入了解机械臂内部运算的同志比较有体会。由于是探索性学习&a…

快速上手Spring Cloud 九:服务间通信与消息队列

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

新数字时代的启示:揭开Web3的秘密之路

在当今数字时代&#xff0c;随着区块链技术的不断发展&#xff0c;Web3作为下一代互联网的概念正逐渐引起人们的关注和探索。本文将深入探讨新数字时代的启示&#xff0c;揭开Web3的神秘之路&#xff0c;并探讨其在未来的发展前景。 1. Web3的定义与特点 Web3是对互联网未来发…

Discourse 最多允许有几个分类级别

和 DISCUZ 不同&#xff0c;DISCUZ 可以允许分类下面还有分类&#xff0c;再继续分类这种嵌套式分类。 Discourse 最多只允许有 2 个分类。 如果你在已有的分类下再继续分类的话&#xff0c;系统会提示错误&#xff1a; 意思就是子分类不能再分子分类。 Discourse 尽量采取了…

【linux课设】自主实现shell命令行解释器

shell和bash的关系 shell是命令解释器&#xff0c;它接收用户的命令并将其传递给内核去执行。bash,即GNU Bourne-Again Shell&#xff0c;是shell的一种实现方式&#xff0c;也是大多数linux系统下默认的shell。 bash的原理 大多数的指令进程&#xff08;除了内建命令&#…

窥探未来:Web3如何颠覆传统互联网

随着科技的迅速发展&#xff0c;Web3正逐渐成为人们关注的焦点。与传统的Web2相比&#xff0c;Web3代表了一种全新的互联网模式&#xff0c;其潜力和影响力引发了人们对未来的期待和探索。本文将深入探讨Web3如何颠覆传统互联网的各个方面&#xff0c;并展望其可能带来的未来变…

Docker搭建LNMP环境实战(08):安装php-fpm

1、编写php测试文件 在文件夹&#xff1a;/mnt/hgfs/dockers/test_site/www目录下创建文件&#xff1a;test.php&#xff0c;内容为&#xff1a; <?phpecho "hello world!!!!!! From test.php"; ?>2、编写php-fpm部署配置文件 在文件夹&#xff1a;/mnt/h…

基于单片机寻迹巡线避障智能小车系统设计

**单片机设计介绍&#xff0c;基于单片机寻迹巡线避障智能小车系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机寻迹巡线避障智能小车系统设计是一个结合了硬件与软件技术的综合性项目。该系统的目标是设计一款…

AMEYA360代理 | 江苏长晶科技FST2.0高性能 IGBT产品介绍

江苏长晶科技股份有限公司是一家专业从事半导体产品研发、生产和销售的企业。自2019年起&#xff0c;连续4年被中国半导体行业协会评为 “功率器件十强企业”。2021年开始自主研发有着“工业CPU”之称的IGBT&#xff0c;截至2023年Q3在家电/工业/新能源等行业实现8款产品市场应…

【MySQL】DML的表操作详解:添加数据&修改数据&删除数据(可cv例题语句)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

政安晨:【Keras机器学习实践要点】(九)—— 保存、序列化和导出模型

目录 介绍 如何保存和加载模型 保存一个Keras模型 装回模型 设置 保存 例子&#xff1a; 自定义对象 向 load_model() 传递自定义对象 使用自定义对象范围 模型序列化 APIs 内存模型克隆 任意对象序列化和反序列化 保存模型权重 内存中的权重传递接口 无状态层…

阿里云Salesforce CRM功能差异列表 - Winter‘24

阉割版的阿里云Salesforce由于技术和监管等因素与国际版的Salesforce差距很大&#xff01; 一、Winter‘ 24版差异概况&#xff1a; 1.1. 主要版本&#xff1a; 阿里云上的 Salesforce 提供两个版本&#xff0c;用于生产用途的 CN 版本&#xff08;CN Edition&#xff09;和用…

20240329-科技咨询:比亚迪第五代DMi;央视AI《周处除三害》;带屏幕苹果耳机爆火

一、比亚迪5月份即将推出第五代DMi技术 近日&#xff0c;比亚迪举行了2023年财报投资人沟通会。会议纪要显示&#xff0c;比亚迪董事长王传福在会上透露&#xff0c;今年5月将推出第五代DMI混动技术&#xff0c;预计馈电油耗将降至2.9升/百公里&#xff0c;而满油满电续航将达…

Matlab-写入mhd和raw医学图像处理格式文件

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 mhd和raw是什么&#xff1f; MHD&#xff08;MetaImage&#xff09;和RAW&#xff08;Raw Image Data&#xff09;是用于医学图像…

kubernetes-networkpolicies网络策略问题

kubernetes-networkpolicies网络策略问题 问题描述 重点重点重点&#xff0c;查看我的博客CKA考题&#xff0c;里面能找到解决方法 1.部署prometheus监控的时候&#xff0c;都部署成功&#xff0c;但是web访问503-504超时 2.添加ingress的时候也是访问不到&#xff0c;其他命…

HarmonyOS实战开发-如何实现一个简单的电子相册应用开发

介绍 本篇Codelab介绍了如何实现一个简单的电子相册应用的开发&#xff0c;主要功能包括&#xff1a; 实现首页顶部的轮播效果。实现页面跳转时共享元素的转场动画效果。实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。 相关概念 Swiper&#xff1a;滑块视图容…

Eclipse新建java类的操作流程

一、在左侧空白区域&#xff0c;点击鼠标右键。 二、点击new&#xff0c;选择Java Project &#xff08;由于这里不知道怎么截图&#xff0c;就用手机拍了一张&#xff0c;希望不要介意&#xff09; 三、 给project文件起个名字&#xff0c;其他都不用管&#xff0c;点击Finis…

YoloV8实战:使用YoloV8检测钢材表面缺陷

摘要 本文讲解一下实战,使用YoloV8检测钢材表面缺陷。起因是有粉丝搞不定这个数据集,检测的时候出现了不收敛的情况。所以,给大家讲讲如何去做。 不收敛的原因 一般遇到不收敛的情况,就是数据转化的时候出错了,大家可以打开runs下面的训练日志,观察一下是否正常。 如…

数据结构(六)——图

六、图 6.1 图的基本概念 图的定义 图&#xff1a;图G由顶点集V和边集E组成&#xff0c;记为G (V, E)&#xff0c;其中V(G)表示图G中顶点的有限非空集&#xff1b;E(G) 表示图G中顶点之间的关系&#xff08;边&#xff09;集合。若V {v1, v2, … , vn}&#xff0c;则用|V|…