Nodejs--Express框架使用

目录

一.概念

二.项目目录结构

 三.app.js

四.项目需要的中间件

五.Mysql连接

六.日志配置

七.实体模型配置

 八.统一结果封装

九.app.js的详细配置

十.自定义登录拦截器

十一.route路由配置

十二.controller处理

十二:静态页面:

十三:总结


一.概念

Express是一个使用Node.js编写的灵活且最受欢迎的Web应用程序框架。它提供了一组用于构建Web应用程序和API的工具和功能,使开发者能够轻松地处理路由、请求和响应、中间件、模板引擎等。

以下是一些Express框架的特点和用法:

  1. 快速搭建Web应用程序:Express提供了一个简洁的API,使您能够快速搭建一个完整的Web应用程序。通过使用Express,您可以轻松地定义路由、处理HTTP请求和响应、设置和使用中间件等。

  2. 简化的路由功能:Express提供了一种简单而强大的方式来定义和处理路由。您可以使用Express的路由功能来定义不同URL路径的处理函数,并将它们链接在一起以构建完整的Web应用程序。

  3. 中间件支持:Express使用中间件来处理请求和响应。中间件是一个函数,它可以在请求到达目标处理函数之前或之后执行,并对请求或响应进行处理。Express提供了许多内置的中间件,也支持使用第三方中间件。

  4. 数据库集成:Express与多个数据库提供商(如MongoDB、MySQL等)兼容,并提供了方便的数据库集成。您可以使用适当的数据库驱动程序和中间件来连接和操作数据库。

  5. 模板引擎支持:Express支持多种模板引擎,如EJS、Pug等。模板引擎允许您在服务器端生成HTML,并将动态数据注入到模板中。

总的来说,Express是一个简单而强大的Web应用程序框架,它使开发者能够快速构建可靠的Web应用程序和API。无论是构建小型项目还是大型应用程序,Express都是一个理想的选择。

二.项目目录结构

 

说明:

 1.app.js : 该文件是启动服务器的主文件,类似于Springboot中的Appliction,

2.routes/ :该目录进行了路由的相关配置

3.public/ :该目录是静态文件目录,页面放在该目录下

4.config/ :该目录放我们项目的一些配置文件

5.models/ : 该目录放实体类模型

6.controller/ :该目录类似java的controller,mvc模式

7.interceptor/ :该目录放一些拦截器的相关配置

8.logs/ :该目录放日志文件

9.package.json :该文件是我们项目的说明和依赖,类似于pom.xml

 三.app.js

express基于nodejs标准库中的http模块构建,下面我们看一下app.js文件

 我们先看一下最核心最简单的配置:

const express = require('express')

//构建应用对象
const app = express()

app.get('/',(req,res)=>{
   res.send("hello,world")
})

//启动服务器
app.listen(8081,()=>{
    console.log("访问地址: http://localhost:8081");
})

 当我们访问8081这个端口时,就能返回hello,world,

四.项目需要的中间件

我们的项目需要满足一些基本的要求,例如:连接mysql,会话管理,静态资源解析,等,下面我们看看我们需要安装哪些中间件:

{
  "name": "untitled",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "body-parser": "^1.20.2",
    "cookie-parser": "~1.4.4",
    "cors": "^2.8.5",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "express-session": "^1.17.3",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "pug": "2.0.0-beta11",
    "sequelize": "^6.35.0",
    "session-memory-store": "^1.0.0",
    "static": "^2.0.0",
    "winston": "^3.11.0"
  }
}

 我们来解释一下:

  1.axios : 这个不用多说了,就是发请求的

  2.body-parser: 这个是用来解析请求体的,

  3.cookie-parser: 这个是用来解析cookie获取的

 4.cors: 这个是用来配置跨域的

5.debug: express自带的

6.express-session: 负责session管理

7.sequelize: 这个是orm框架,类似于mybatis

8.session-memory-store: 这个是用来将session保存到内存中

9.static: 这个是负责解析静态资源目录的

10.winston: 这个是日志框架,类似于log4j,slf4j等

五.Mysql连接

  在config/目录下创建db.js文件

const Sequelize = require('sequelize')

const sequelize = new Sequelize('mybatis','root','123456',{
    host: 'localhost',
    dialect: 'mysql',
    timezone: '+08:00',     // 这里是东八区,默认为0时区
    // 使用连接池
    pool: {
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000,
    },
})


module.exports = sequelize;

 创建sequelize对象,前三个参数分别是:数据库名称用户名密码, 然后是地址类型

 时区,以及连接池配置

最后不要忘记吧对象导出

六.日志配置

在config/目录下创建log.js文件

const winston = require('winston')
const path = require('path');
//上一级目录
const dirname = path.dirname(__dirname)
// 设置日志文件输出位置
const logFilePath = path.join(dirname, 'logs', 'logs.txt');

const util = require('util');


// 创建日志记录器
const logger = winston.createLogger({
    level: 'info', // 设置日志级别(可选)
    //format: winston.format.json(), // 设置日志格式(可选)
    format: winston.format.combine(
        winston.format.timestamp({
            format: 'YYYY-MM-DD HH:mm:ss' // 设置时间格式
        }),
        winston.format.printf(info => {
            // 检查是否传递了user参数
            if (info.message && info.user) {
                return `${info.timestamp} ${info.level}: ${info.message} ${info}`;
            }
            return `${info.timestamp} ${info.level}: ${info.message}`;
        })
    ),
    transports: [
        new winston.transports.Console(), // 将日志输出到控制台
        new winston.transports.File({ filename: logFilePath }) // 将日志输出到文件
    ]
});


function logInfo(...args){
    logger.info(getStr(args))
}
function logError(...args){
    logger.error(getStr(args))
}

function getStr(...args){
    var str = ''
    for(let i=0;i<args.length;i++){
        var s = util.inspect(args[i])
        str += s
    }
    return str;
}

module.exports = {logInfo,logError};

我这里使用了util模块的inspect()方法,他可以吧任意类型的值转化为字符串

七.实体模型配置

我们先看一下数据库:

tb_user表:

tb_student表:

 

然后我们分别在models/目录下创建User.jsStudent.js文件

 

const {Model,DataTypes} = require('sequelize')

const sequelize = require('../config/db')

/**
 * 创建user模型,指定表为tb_user
 */
const User = sequelize.define('User',{
    id:{
        type:DataTypes.INTEGER,
        primaryKey:true,
        autoIncrement:true
    } ,
    username: DataTypes.STRING,
    password: DataTypes.STRING
},{
    tableName:"tb_user",
    timestamps: false // 关闭自动插入 timestamps 字段
})

module.exports = User;
const {Model,DataTypes} = require('sequelize')

const sequelize = require('../config/db')


/**
 * 创建user模型,指定表为tb_user
 */
const Student = sequelize.define('Student',{
    id:{
        type:DataTypes.INTEGER,
        primaryKey:true,
        autoIncrement:true
    } ,
    stuid:DataTypes.INTEGER,
    stuname:DataTypes.STRING,
    sex:DataTypes.STRING,
    myClass:DataTypes.STRING,
    address:DataTypes.STRING,
    tel:DataTypes.STRING,
    sorce:DataTypes.INTEGER

},{
    tableName:"tb_student",
    timestamps: false // 关闭自动插入 timestamps 字段
})

module.exports = Student;

说明一下:

 每个字段可以规定为mysql的那种类型,type:指定类型,primaryKey:指定主键,autoIncremnt:指定自增等...后面我会在出一期详细介绍sequlize框架的文章

 八.统一结果封装

 像java中那样封装结果:code,msg,data三个:

在models/目录下创建Result.js文件


const httpStatus = require('./HttpStatus')

class Result {
    constructor(code, msg, data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 默认的成功返回方法

     */
    static ok(httpStatus,data) {
        return new Result(httpStatus.code,httpStatus.msg,data)
    }

    /**
     * 默认的失败返回方法
     * @returns {Result}
     * @param httpStatus
     */
    static error(httpStatus) {
        return new Result(httpStatus.code,httpStatus.msg,null);
    }
}

module.exports = Result

然后在创建HttpStatus.js文件

const HttpStatus = {
    OK: { code: 200, msg: "success" },
    ERROR: { code: 500, msg: "failure" }
};


module.exports = HttpStatus;

这是要给字面量对象,我们可以使用它来模拟java中的枚举类型

九.app.js的详细配置

const express = require('express')
const bodyParser = require('body-parser')
//导入用户路由
const userRoutes = require('./routes/user')
const stuRoutes = require('./routes/student')
//导入会话管理
const session = require('express-session')
const MemoryStore = require('session-memory-store')(session);
//导入拦截器
const {checkRequest} = require('./intercepter/intercepter')
//导入cookie解析器
const cookieParser = require('cookie-parser');
//导入跨域配置
const cors = require('cors')
//导入static静态资源模块
const static = require('static')


//构建应用对象
const app = express()
//设置跨域
app.use(cors())
//启用static模块
app.use(express.static('public'))

//解析请求体
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extend: true }))


//设置会话中间件
app.use(session({
  sotre: new MemoryStore(), //使用内存管理会话
  secret: 'ikun123',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true,maxAge: 1800000 } //30分钟
}))

//使用cookie解析器
app.use(cookieParser())

//使用拦截器
app.use(checkRequest)

//使用路由
app.use('/user',userRoutes)
app.use('/stu',stuRoutes)



//启动服务器
app.listen(8080,()=>{
  console.log("访问地址: http://localhost:8080");
})

我们通过以上配置可以基本实现一些主要的功能

十.自定义登录拦截器

 我们可以写一个类似springmvc那样的拦截器,来判断是否登录

在interceptor/目录下创建intercerptor.js文件:

// AuthMiddleware.js
const whitelist = ['/user/login','/user/register'];
//const blacklist = ['/user/list','/user/logout','/user/add'];
//导入会话管理
const session = require('express-session')
const MemoryStore = require('session-memory-store')(session);

const checkRequest = (req, res, next) => {
    const url = req.originalUrl;

    if (whitelist.includes(url)) {
        next();
    }else{
        //如果不是白名单,那么就需要验证了
        console.log("黑名单拦截...");

        //  console.log(req.cookies.sessionID);

        //黑名单
        if(req.cookies.sessionID != null){
            const cookieSessionID = req.cookies.sessionID
            const acticeSessions = req.sessionStore.sessions;

            //  console.log(acticeSessions);

            for(let sessionID in acticeSessions){
                // console.log(sessionID);

                //比较二者值
                if(sessionID === cookieSessionID){
                    //相等,放行,跟新session时间
                    acticeSessions[sessionID].validity = 30*60
                    console.log("放行...");
                    return next()
                }
            }
            //遍历完没有找到seesionID,说明回话过期
            return res.status(401).json({message:'会话过期!,请重新登录'})
        }else{
            return res.status(401).json({message:'未登录!'})
        }
    }
};

module.exports = {
    checkRequest
};

这里我们先创建了一个白名单,来默认放行不需要拦截的路径,然后其他的路径需要拦截,

 我们可以看到它传入三个参数:req,res.next,这个next它是express框架内置的一个用来负责函数执行顺序的,也就是自带的,我们可以在任何函数中使用它,当放行之后,我们使用next()方法来继续执行下一个函数,

 我们先尝试获取请求头中的cookie中的sessionID,如果有,我们拿着这个sessionID和我们服务端保存的session集合中遍历,对比是否有相等的,如果有,就放行,没有,返回会话过期提示

为什么是遍历呢?因为我们的服务端保存了很多用户的session,不可能是单个session,所以要遍历对比

十一.route路由配置

我们在route/目录下分别创建user.js和student.js,

const express = require('express')
const UserController = require('../controller/UserController')

const router = express.Router()

//GET /user/login
router.post('/login',UserController.login)

//GET /user/list --获取用户列表
router.get('/list',UserController.list)

//POST /user --添加用户
router.post('/add',UserController.addUser)

//GET /user/test 测试路径
router.get('/test',UserController.test)

//GET /user/logout 退出登录
router.post('/logout',UserController.logout)

module.exports = router
const express = require('express')
const StuController = require('../controller/StuController')

const router = express.Router()


router.get('/list',StuController.list)

router.get('/byid/:id',StuController.searchByid)


module.exports = router

类似于vue中的路由配置,

十二.controller处理

我们在controller/目录下分别创建UserController.js和StutController.js

const User = require('../models/User')
const {logInfo,logError} = require('../config/log')
//事务需要用
const Sequelize = require('../config/db')
const Result = require("../models/Result");
const HttpStatus = require("../models/HttpStatus");

//导入类型约束



module.exports = {

    //登录
    async login(req,res){
        try {

            //避免重复登录
            const sinId = req.cookies.sessionID
            if(sinId !=null){

                //获取所有sessions
                const acticeSessions = req.sessionStore.sessions;
                //遍历
                for(let sID in acticeSessions){
                    if(sID === sinId){
                        //说明有sessionID,返回重复登录错误
                        return res.status(200).json({message:'重复登录!'})

                    }
                }
            }
            //都没有说明可以继续登录了
            const {username,password} = req.body;
            //假设
            if(username === 'lisi' && password === '123'){


                //服务端设置session
                req.session.username = username;
                //设置cookie
                res.cookie('sessionID', req.sessionID, { httpOnly: true, maxAge: 3600000 });

                //   res.cookie('username', username, {
                //     expires: new Date(Date.now() + 1800000), // 设置 cookie 过期时间
                //     httpOnly: true, // 禁止客户端 javascript 访问 cookie
                //     secure: false, // 如果使用 HTTPS,请设置为 true
                // });
                //返回响应
                logInfo('用户登录:',{username})
                //res.status(200).json({message:'登录成功!'})
                res.status(200).json(Result.ok(HttpStatus.OK,username))
            }else{

                res.status(401).json({messge:'用户名或者密码错误'})
            }

        } catch (err) {
            logError('登录错误:',{err})
            res.status(500).json({msg:'服务器错误'+err})
        }

    },


    //查询所有用户
    async list(req,res){
        try {
            const users = await User.findAll()
            return res.json(users)
        } catch (error) {
            res.status(500).json({msg:'服务器错误'})
        }
    },

    /**
     *  添加用户
     */
    async addUser(req,res){
        const { username,password } = req.body;
        try {
            await Sequelize.transaction(async (t)=>{
                await User.create({username,password},{transaction:t})
                //记录日志
                logInfo('添加用户:',username,password)
                res.status(200).json({msg:'添加成功'})
            }).then(()=>{
                console.log("事务已经提交");
            })
        } catch (err) {
            logError('添加用户失败',{err})
            res.status(500).json({msg:'服务器错误'})
        }
    },

    /**
     * //退出登录
     */
    async logout(req,rese){
        console.log("退出登录。。。。");
        try {
            //将session销毁
            var sessionID =  req.cookies.sessionID
            //获取所有sessions
            const acticeSessions = req.sessionStore.sessions;
            //遍历
            for(let sID in acticeSessions){
                if(sID == sessionID){
                    //销毁session
                    sessionStore.destroy(sID, (err) => {
                        if (err) {
                            console.error('Failed to destroy session:', err);
                            res.status(500).json({message:err})
                        } else {
                            console.log('Session destroyed successfully.');
                            //销毁cookie
                            req.clearCookie('sessionID')
                            res.status(200).json({message:'退出成功'})
                        }
                    });
                }
            }

        } catch (error) {
            res.status(500).json({msg:'服务器错误'})
        }
    },


    //测试
    async test(req,res){
        try {
            console.log("测试....");
            res.json({test:"测试"})
        } catch (error) {
            res.status(500).json({msg:'服务器错误'})
        }
    }



}

读者自行看上面的代码和注释思考登录和注销的流程

注意:我们在添加用户时开启了事务,当成功添加后提交事务

StuController.js


const Student = require('../models/Student')
const {logInfo,logError} = require('../config/log')
//事务需要用
const Sequelize = require('../config/db')

module.exports = {

    //查询所有学生
    async list(req,res) {
        try {

            const stuList = await Student.findAll()
            //   console.log(stuList);
            res.status(200).json(stuList)
        } catch (error) {
            res.status(500).json({msg: '服务器错误'})
        }
    },
    //根据id查询学生
    async searchByid(req,res){
        const id = req.params.id
        console.log(id)
        console.log("hhhh")
        try{
            const stu = await  Student.findOne({
                where:{id:id}
            })
           if(stu){
               res.status(200).json(stu)
           }else {
               res.status(200).json({message:"无此用户"})
           }
        }catch (error){
            res.status(500).json({msg: '服务器错误'})
        }

    }
}




十二:静态页面:

下面看一下我们的静态页面:

public/目录下的index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>


    <div id="app">

        <div>账号:<input type="text" v-model="username"></div>
        <div>密码:<input type="text" v-model="password"></div>
        <button @click="login">登录</button>
    </div>
 
 
    <script src="js/vue.js"></script>
    <script src="js/axios.js"></script>
    <script>
       new Vue({
         el:"#app",
         data:{
            return(){
                username:""
                password:""
            }
         },
         methods:{
              //登录
              login(){
                axios.post('http://localhost:8080/user/login',
                {
                    "username":this.username,
                    "password":this.password
                }).then(res=>{
                    if(res.data.code===200){
                        alert("登录成功")
                        location.href = './html/home.html'
                    }
                })
              }

         }
       })
       

    </script>


<body>
    
</body>
</html>

public/html/下的home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>系统</title>
    <link href="../css/home.css" rel="stylesheet" type="text/css">
</head>
<body>
    
    <div id="app">
         <h1>学生管理</h1>

        <input type="text" v-model="id"><button @click="search">搜索</button>
         <table>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>性别</th>
                <th>班级</th>
                <th>地址</th>
                <th>电话</th>
                <th>分数</th>
                <th>操作</th>
            </tr>
            <tr v-for="(item,index) in students" :key="index" class="stu">
                <th>{{ item.stuid }}</th>
                <th>{{item.stuname}}</th>
                <th>{{item.sex}}</th>
                <th>{{item.myClass}}</th>
                <th>{{item.address}}</th>
                <th>{{item.tel}}</th>
                <th>{{item.sorce}}</th>
                <th><a href="javascript:;" class="edit">编辑</a>
                    <a  href="javascript:;" class="del">删除</a></th>
                
            </tr>
         </table>
         

         <div>hello</div>
    </div>

    <script src="../js/axios.js"></script>
    <script src="../js/vue.js"></script>
    <script src="../js/config.js"></script>
     <script>
        
        new Vue({
            el:"#app",
            data(){
                return{
                    students:[],
                    id:''
                }
            },
            created(){
                this.getStuList()
            },
            methods:{
                //查询所有学生
                getStuList(){
                    axios.get(url + '/stu/list').then(res=>{
                        this.students = res.data;
                    })
                },
                //根据id查询学生
                search(){
                    axios.get(url+`/stu/byid/${this.id}`).then(res=>{
                        this.students = res.data
                    })
                }
            },
            watch:{
                students:function (newVal,oldVal){
                    this.students =
                }
            }
            
        })
     </script>


</body>
</html>

下面我们运行一下项目:

可以看到我们项目成功启动了!

我们先访问一下home.html中的/user/list看看如果不登录会咋样:

 

可以看到为登录,下面我们先登录, 

这里返回的格式两个不一样因为我写的不完善,没有每一个都是三个那种Result格式的,请见谅!

可以看到,登录成功了,下面我们在访问一下/user/list接口:

 

可以看到成功查询到了学生列表!,

下面我们来新增一个学生:

 

可以看到添加成功了!

看一下控制台输出:

Executing (072a3295-6d06-424e-915d-8aa19e702c03): INSERT INTO `tb_user` (`id`,`username`,`password`) VALUES (DEFAULT,?,?);
2023-11-19 21:46:16 info: [ '添加用户:', 'jjh', '123' ]
Executing (072a3295-6d06-424e-915d-8aa19e702c03): COMMIT;
事务已经提交

 看到事务已经提交!

再看一下日志:

2023-11-19 21:44:01 info: [ '用户登录:', { username: 'lisi' } ]
2023-11-19 21:46:16 info: [ '添加用户:', 'jjh', '123' ]

可以看到日志已经成功记录了!

下面我们看一下前端页面:

可以看到成功登录!

如果我们继续访问该接口:

 

可以看到重复登录!!!

登录成功后页面会跳转到home.html:

 

可以看到学生成功的查询出来了!

十三:总结

 好了,以上就是nodejs的express框架的基本使用了,读者可以在此基础上实现根据id查询用户,分页查询,批量增加删除用户等功能,我们下期再见!

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

男子遗失30万天价VERTU唐卡手机,警察2小时“光速”寻回

今天&#xff0c;一则“男子丢失30万元手机女子捡到一位老年机”的新闻迅速冲上热搜第一&#xff0c;引发全网热议。据宿城公安消息&#xff1a;近日&#xff0c;江苏省宿迁市市民王先生在购物时不慎失落了一部价值30万元的全球知名奢侈品VERTU手机&#xff0c;被民警2个多小时…

基于springboot实现家政服务管理平台项目【项目源码+论文说明】计算机毕业设计

摘要 随着家政服务行业的不断发展&#xff0c;家政服务在现实生活中的使用和普及&#xff0c;家政服务行业成为近年内出现的一个新行业&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计家政服务管理平台的目的就是借助计算机让复杂的销售操作变简单&#xff0c;…

链表的增删改查(python实现)

链表的增删改查 使用python实现链表的增删改查 增 add(val)&#xff1a;在头结点处增加&#xff0c;左插入append(val)&#xff1a;在尾结点处增加&#xff0c;右插入 删 remove_single(target)&#xff1a;删除值为target的第一个节点remove_all(target)&#xff1a;删除值为…

Linux僵尸进程

Linux僵尸进程 一、僵尸进程简介二、僵尸进程的危害三、避免僵尸进程的方法 一、僵尸进程简介 如果父进程比子进程先退出&#xff0c;子进程将被1号进程托管&#xff08;这也是一种让程序在后台运行的方法&#xff09;。如果子进程比父进程先退出&#xff0c;而父进程没有处理…

基于SSM的“鲜花”电子商务平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

通过汇编理解cortex-m3:第0章

第0章&#xff1a;准备工作 基本想法&#xff1a;利用汇编和gdb调试&#xff0c;来学习cortex-m3汇编指令&#xff0c;以及一些寄存器的功能。 软件和硬件&#xff1a; 硬件&#xff1a;韦东山瑞士军刀中的最小核心板&#xff08;STM32F103C8T6&#xff09; STLINK-V2&#…

基于java web个人财务管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

PyCharm:PyCharm新建.py文件时自动带出指定内容

在pycharm中加上指定内容&#xff0c;每次新建.py文件都会自动带出指定内容 操作&#xff1a; File—Setting—Editor----File and Code Templates--Python Script 在右侧窗口中加上如下信息 # encoding: utf-8 # author: Jeffrey # file: ${NAME}.py # time: ${DATE} ${TI…

【Java SE】循环一些基本练习

判定一个数字是否是素数 public class Test {public static int is_sushu(int n) {if(n 1) {return 0;}int i ;for (i 2; i < Math.sqrt(n); i) {if(n % i 0 ) {break;}}if (i > n) {return 1;}return 0;}public static void main(String[] args) {Scanner scanner …

kafka 磁盘扩容与数据均衡实在操作讲解

文章目录 一、概述1&#xff09;Kafka 磁盘扩容概述2&#xff09;Kafka 数据均衡概述 二、K8s 集群部署三、kafka on k8s 环境部署1&#xff09;安装 helm2&#xff09;安装 zookeeper1、添加源并下载部署包2、修改配置3、开始安装 zookeeper4、测试验证5、卸载 3&#xff09;安…

uview-plus中二级菜单左右联动更改为uni-app+vue3+vite写法

uview-plus3.0重磅发布&#xff0c;全面的Vue3移动组件库 该插件使用的vue2写法&#xff0c;但支持vue3引用&#xff0c;在此基础上修改为uni-appvue3vite; <template><view class"u-wrap mainClass"><!-- <back-header :title"pageTitle&quo…

【Linux】-进程间通信-命名管道文件(没有关系的进程间进行通信),以及写一个日志模板

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

mysql数据库【进阶篇】

1.存储引擎 1.1 mysql的体系结构 连接层&#xff1a;最上层是一些客户端和链接服务&#xff0c;主要完成- -些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。服务层&#xff1a;第二层架构主要完成大多数的核心服务功…

【教学类-06-06】20231118 (55格版)X以内加法、减法、加减混合题

背景需求 1、长期做手工制作&#xff0c;常规管理难以控制 优势&#xff1a; 1、幼儿创作热情高涨&#xff0c;发明的新玩具多 2、互助观摩&#xff0c;进一步模仿、创作作品 3、互动游戏兴趣浓厚&#xff0c;语言交流踊跃&#xff0c; 劣势&#xff1a; 1、纸条碎片多&…

深入流行推荐引擎3:Spotify音乐推荐系统

深入流行推荐引擎3&#xff1a;Spotify音乐推荐系统 Spotify音乐推荐系统通过矩阵分解发现每周&#xff08;Discover Weekly via Matrix Factorization&#xff09;Discover Weekly 如何运作&#xff1f;&#xff08;How Discover Weekly Works?&#xff09;矩阵分解&#xff…

【IPC】 共享内存

1、概述 共享内存允许两个或者多个进程共享给定的存储区域。 共享内存的特点 1、 共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了数据&#xff0c;共享这个内存区域的所有进程就可以立刻看到 其中的内容。 2、使用共享内存要注意的是多个进程…

使用持久卷部署 WordPress 和 MySQL

&#x1f5d3;️实验环境 OS名称Microsoft Windows 11 家庭中文版系统类型x64-based PCDocker版本Docker version 24.0.6, build ed223bcminikube版本v1.32.0 &#x1f587;️创建 kustomization.yaml 你可以通过 kustomization.yaml 中的生成器创建一个 Secret存储密码或密…

Android问题笔记四十六:解决open failed: EACCES (Permission denied) 问题

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC &#x1f449;关于作者 专…

Jmeter性能实战之分布式压测

JMeter分布式执行原理 1、JMeter分布式测试时&#xff0c;选择其中一台作为调度机(master)&#xff0c;其它机器作为执行机(slave)。 2、执行时&#xff0c;master会把脚本发送到每台slave上&#xff0c;slave 拿到脚本后就开始执行&#xff0c;slave执行时不需要启动GUI&…

深度学习YOLO抽烟行为检测 - python opencv 计算机竞赛

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…
最新文章