当前位置:   article > 正文

nodejs fs http express express-session jwt mysql mongoose

nodejs fs http express express-session jwt mysql mongoose

文件fs模块

读取文件内容

fs.readFile('./file/fs-01.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err)
    return
  }
  console.log(data)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

写入内容到文件

const fs = require('fs');

const filePath = "./file/output.txt";

fs.writeFile(filePath, "Hello World", {mode: 0o666,flag: 'a'},(err) => {
    if (err) {
        console.log(err);
    } else {
        console.log("File written successfully");
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

path模块使用


const path = require("path");
const fs = require("fs");

let absolutPath = path.join(__dirname,"file","output.txt");
// 绝对路径
console.log(absolutPath);
// 文件名 output.txt
console.log(path.basename(absolutPath));
// 扩展名 .txt
console.log(path.extname(absolutPath));

fs.readFile(absolutPath,{encoding:'utf-8'},
     (err,data) => {
    if (err){
        console.log('read fail')
        return 0;
    }
    console.log('read success:',data);

    const split = data.split(" ");
    if (split.length < 0){
        return 0;
    }

    let arr = [];
    split.forEach(item=>{
        arr.push(item.replace("=",":"));
    });

    let join = arr.join("\r\n");
    console.log(join);

});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

正则表达式匹配

// \s 匹配任意空白字符 \S 匹配任意非空白字符
let styleReg = /<style>[\s\S]*<\/style>/;
  • 1
  • 2

http模块

const http = require("http");
const fs = require("fs");
const path = require("path");

let server = http.createServer();
server.on("request",(req,res) => {
    // 设置响应头
    res.setHeader("Content-Type","text/html;charset=utf-8");
    // 响应内容变量
    let content = "<h1>404</h1>";
    // 获取客户端请求的URL地址
    let url = req.url;

    if ("/favicon.ico" === url){
        return 0;
    }else if ("/" === url){
        url = "/index.html";
    }

    const fPath = path.join(__dirname,"file",url);
    console.log(fPath);

    fs.readFile(fPath,"utf-8",(err,data) => {
        if (err){
            console.log("request err:",err);
            res.end(content);
        }else {
            content = data;
            res.end(content);
        }
    })
});

server.listen(8080,() => {
    console.log("server start http://localhost:8080")
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

module使用

定义

console.log("我是m1模块");
// console.log(module);

function sum(a,b){
    return a+b;
}

function sayHello(){
    console.log("sayHello...");
    return 1;
}

const uname= "我是妹妹";

// 暴露模块,最终共享的结果以module.exports为准
module.exports = {
    sum,
    uname,
    sayHello
}
// module.exports.uname = "我是妹妹";

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

使用

const m1 = require("./m1");

console.log(m1.sum(1,2));
m1.sayHello();
console.log(m1.uname);
  • 1
  • 2
  • 3
  • 4
  • 5

image.png
最终共享的结果以module.exports为准
image.png

CommonJS规范

image.png

npm和包

image.png

安装cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 1

安装

// 安装最新
npm i/install moment
// 安装指定版本
// 查看版本
// npm view 包名 versions
npm view moment versions
[
  '1.0.0',  '1.0.1',  '1.1.0',  '1.1.1',  '1.2.0',
  '1.3.0',  '1.4.0',  '1.5.0',  '1.5.1',  '1.6.0',
  '1.6.1',  '1.6.2',  '1.7.0',  '1.7.1',  '1.7.2',
  '2.0.0',  '2.1.0',  '2.2.1',  '2.3.0',  '2.3.1',
  '2.4.0',  '2.5.0',  '2.5.1',  '2.6.0',  '2.7.0',
  '2.8.1',  '2.8.2',  '2.8.3',  '2.8.4',  '2.9.0',
  '2.10.2', '2.10.3', '2.10.5', '2.10.6', '2.11.0',
  '2.11.1', '2.11.2', '2.12.0', '2.13.0', '2.14.0',
  '2.14.1', '2.15.0', '2.15.1', '2.15.2', '2.16.0',
  '2.17.0', '2.17.1', '2.18.0', '2.18.1', '2.19.0',
  '2.19.1', '2.19.2', '2.19.3', '2.19.4', '2.20.0',
  '2.20.1', '2.21.0', '2.22.0', '2.22.1', '2.22.2',
  '2.23.0', '2.24.0', '2.25.0', '2.25.1', '2.25.2',
  '2.25.3', '2.26.0', '2.27.0', '2.28.0', '2.29.0',
  '2.29.1', '2.29.2', '2.29.3', '2.29.4', '2.30.0',
  '2.30.1'
]

npm i moment@2.30.0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

image.png

解决包下载慢问题

image.png

开发自己的包

image.png

发布包到npm

要将包发布到 npm ,可以按照以下步骤进行操作:

  1. 确保你已经注册了 npm 账号。
  2. 创建一个具有适当结构和功能的包。
  3. 在项目根目录下运行 npm login 命令,使用你的 npm 账号登录。
  4. 编辑 package.json 文件,确保其中包含必要的信息,如包的名称、描述、版本等。
  5. 在命令行中进入项目根目录。
  6. 运行 npm publish 命令来发布包。
  7. 等待发布过程完成。

发布包到 npm 后,其他开发者就可以通过 npm install 命令安装你的包了。

在发布之前,还需要注意以下几点:

  • 确保包的质量和稳定性。
  • 遵循 npm 的最佳实践和规范。
  • 仔细阅读 npm 的文档,了解相关的规定和限制。
  • 对包进行充分的测试。

模块加载机制

image.png

express框架

托管静态资源

image.png

const express = require("express");
const path = require("path");

const app = express();

// 托管静态资源
app.use(express.static(path.join(__dirname,"../../public")));

const server = app.listen(8080,()=>{
    let address = server.address().address;
    let port = server.address().port;

    console.log("server express : http://127.0.0.1:%s",port);
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

托管多个静态资源

image.png
image.png

nodemon

Nodemon 是一个用于开发 Node.js 应用程序的实用工具。它的主要功能是在代码更改时自动重新启动 Node.js 服务器,以便你能够实时看到代码更改的效果。

以下是使用 Nodemon 的一般步骤:

  1. 安装 Nodemon:可以使用包管理工具(如 npm)进行安装。
npm install nodemon
  • 1
  1. 在命令行中使用 Nodemon 启动你的 Node.js 应用程序。
nodemon your_script.js
  • 1

其中 your_script.js 是你的 Node.js 脚本文件。

  1. Nodemon 会监控你的代码文件更改,并在保存时自动重新启动服务器。

使用 Nodemon 的好处包括:

  • 实时反馈:你可以立即看到代码更改的效果,无需手动重新启动服务器。
  • 提高开发效率:减少了手动重新启动服务器的时间和麻烦。
  • 方便调试:能够快速发现和解决问题。

请注意,Nodemon 还有许多其他配置选项,可以根据你的具体需求进行调整。

模块化路由

image.png

router.js

let express = require("express");

let router = express.Router();

router.get('/user',function (req,res){
    res.send("user");
});

router.post("/about",function (req,res){
    res.send("about");
});

module.exports = router;
// module.exports = {
//     router
// }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

index.js

const express = require("express");
const router = require("./router");

const app = express();

//注册路由
app.use(router);
//注册路由,加访问前缀
// app.use("/api",router);

app.listen(8080,()=>{
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

路由加前缀

image.png

中间件

const express = require("express");
const moment = require("moment");

const router = require("./router");

const app = express();

// 中间件
const requestTime = function (req,res,next){
    req.requestTime = moment(new Date()).format("YYYY-MM-DD HH:mm:ss")
    next()
}
app.use(requestTime)
//注册路由
app.use("/api",router);

app.listen(8080,()=>{
    console.log(moment(new Date()).format("YYYY-MM-DD HH:mm:ss"))
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
let express = require("express");

let router = express.Router();

router.get('/user',function (req,res){
    // 打印中间件参数
    console.log("requestTime:",req.requestTime)
    res.send("user");
});

router.post("/about",function (req,res){
    res.send("about");
});

module.exports = router;
// module.exports = {
//     router
// }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

中间件全局生效

image.png

中间件局部生效

image.png

router.get('/middleware',function (req,res,next){
    console.log("局部中间件");
    next();
},function (req,res){
    res.send("middleware");
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

image.png
image.png

中间件的分类

image.png

应用级别

绑定在app身上

路由级别

绑定在路由router身上

错误级别

// 错误中间件必须注册在路由之后
image.png

const express = require("express");
const app = express();

app.get('/',(req,res)=>{
    throw new Error("发送错误");
})

app.get('/user',(req,res)=>{
    res.send("user page");
})
// 错误中间件必须注册在路由之后
app.use(function (err,req,res,next){
    console.log("异常级别中间件");
    if (err){
        res.send('err:'+err.message);
        next();
    }
});

app.listen(8080,()=>{
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

express内置中间件

image.png

const express = require("express");
const app = express();

//中间件
// 用来解析application/json表单的中间件
app.use(express.json())
// 用来解析x-www-from-urlencoded表单的中间件
app.use(express.urlencoded())

app.post('/user',(req,res)=>{
    let body = req.body;// 如果没有配置解析表单的中间件,body是undefined
    console.log(body)
    res.send("user page");
})


app.listen(8080,()=>{
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

第三方中间件

image.png

const express = require("express");
// const path = require("path");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}))

app.post('/index',function (req,res){
    console.log(req.body);
    res.send("index");
});

app.listen(8080,()=>{
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

自定义中间件

image.png

监听req的data事件

image.png
image.png

完整代码
const express = require("express");
const querystring= require("querystring");

const app = express();

// 解析表单数据的中间件
app.use(function (req,res,next){
    let formData= "";

    req.on("data",(chunk)=>{
        formData += chunk;
    })

    req.on("end",()=>{
        console.log(formData);
        let body = querystring.parse(formData);
        console.log(body);
        req.body = body;
        next();
    })
})

app.post('/index',function (req,res){
    console.log(req.body);
    console.log(req.body.bookname);
    res.send("index");
});

app.listen(8080,()=>{
    console.log("server express : http://127.0.0.1:8080");
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

练习

apiRouter.js
index.js

cors问题

image.png

cnpm install cors
const cors = require('cors')
app.use(cors())
  • 1
  • 2
  • 3

cors三个响应头

image.png
image.png
image.png
image.png
image.png

jsonp解决跨越

image.png
JSONP 是 JSON 的一种使用模式,全称为 JSON with Padding,即“带回调的 JSON”。它可以绕过浏览器的同源策略,进行跨域请求。
JSONP 利用了

express-session会话

// 安装session
// cnpm install express-session

const express = require("express");
// 导入 session
const session = require("express-session");

const app = express();

app.use(express.json())
app.use(express.urlencoded({extended: false}))

// 配置 session
app.use(session({
  secret: 'test123',//任意
  resave: true,//固定
  saveUninitialized: true //固定
}))

app.post('/api/login',(req,res)=>{
  // 验证登录
  if (req.body.username !== 'admin' || req.body.password !== '000000'){
    return res.send({status: 1,msg: "登录失败"});
  }
  // 存储会话
  // 配置了express-session,可以存储session
  req.session.user = req.body;
  req.session.isLogin = true;

  return res.send({status: 0,msg: "登录成功"});
})

app.get('/api/username',(req,res)=>{
  if (!req.session.isLogin){
    return res.send({status: 1,msg: "没有登录"});
  }
  return res.send({
    status: 0,
    msg: "获取成功",
    data: req.session.user.username
  });
})

app.get('/api/logout',(req,res)=>{
  if (!req.session.isLogin){
    return res.send({status: 1,msg: "没有登录"});
  }
  // 清空session
  req.session.destroy();
  return res.send({status: 0,msg: "ok"});
})

app.listen(8080,()=>{
  console.log("server start:http://localhost:8080");
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

jwt认证

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

const crypto = require("crypto");
module.exports = {
    MD5_SUFFIX: "tangzhenhua",
    md5: pwd => {
        let md5 = crypto.createHash("md5");
        return md5.update(pwd).digest("hex");
    },
    secretKey: "tangzhenhua",
};
const { secretKey } = require("./salt");
const jwt = require("jsonwebtoken");
const {expressjwt} = require("express-jwt");
// 生成 token
const createToken = payload => jwt.sign(payload, secretKey, { expiresIn: 60 * 60 * 240 });
// 验证 token
const jwtAuth = expressjwt({
    secret: secretKey,
    algorithms: ["HS256"],
    credentialsRequired: true,
});
// 不需要校验的路径
jwtAuth.unless({ path:("/api/login") });

module.exports = { jwtAuth, createToken };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
// cnpm install jsonwebtoken express-jwt

const express = require("express");
// jwt相关
let { jwtAuth,createToken } = require("./util");

const app = express();

app.use(jwtAuth);
app.use(express.json())
app.use(express.urlencoded({extended: false}))

app.post('/api/login',(req,res)=>{
    // 验证登录
    if (req.body.username !== 'admin' || req.body.password !== '000000'){
        return res.send({status: 1,msg: "登录失败"});
    }

    let token = createToken({username: req.body.username})
    console.log("token=",token)

    return res.send({
        status: 0,
        msg: "登录成功",
        token: token
    });
})

app.get('/admin/getUserInfo',(req,res)=>{
    let userInfo = req.user;
    return res.send({
        status: 0,
        msg: "获取成功",
        data: userInfo
    });
})

// 错误处理中间件,处理 JWT 鉴权失败
app.use((err, req, res, next) => {
    if (err.name === 'UnauthorizedError') {
        res.status(401).json({error: 'Invalid token'});
    }
});

app.listen(8080,()=>{
    console.log("server start:http://localhost:8080");
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

MySQL模块

安装mysql

cnpm install mysql
  • 1
const mysql = require('mysql');
const connection = mysql.createConnection({
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: 'root',
    database: 'test'
});

connection.connect((err) => {
    if (err) throw err;
    console.log('Connected!');

    // 查询
    connection.query('SELECT * FROM users', (err, rows) => {
        if (err) throw err;
        console.log('Data received from MySQL:', rows);
    });

    // 新增
    // let sql = 'insert into users(username, password) values (?,?)';
    // let inserts = ['test', '123456'];
    // sql = mysql.format(sql, inserts);
    // console.log("sql=>",sql);
    // connection.query(sql,function (err,result){
    //     if (err) throw err;
    //     console.log('--------------------------INSERT----------------------------');
    //     console.log('INSERT ID:',result);
    //     console.log('------------------------------------------------------------\n\n');
    // })

    // 更新
    // let updateSql = "update users set username = ? ,password = ? where id = 3";
    // let updateSqlParams = ['crazyfur','654321'];
    // connection.query(updateSql,updateSqlParams,function (err,result){
    //     if (err) throw err;
    //     console.log('--------------------------UPDATE----------------------------');
    //     console.log('UPDATE affectedRows',result.affectedRows);
    //     console.log('------------------------------------------------------------\n\n');
    // })

    // 删除
    let delSql = "delete from users where id = 3";
    connection.query(delSql,(err,result)=>{
        if (err) throw err;
        console.log('--------------------------DELETE----------------------------');
        console.log('DELETE affectedRows',result.affectedRows);
        console.log('------------------------------------------------------------\n\n');
    })

    // 关闭连接
    connection.end((err) => {
        if (err) {
            console.error('Error occurred while closing the connection:', err);
        } else {
            console.log('Connection closed successfully.');
        }
    });
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

image.png

项目实战

表单校验

npm install joi
npm i @escook/express-joi
https://blog.csdn.net/doiido/article/details/131967068

定义

const joi = require("joi");

/**
 * string() 值必须是字符串
 * alphanum() 值只能是包含 a-zA-Z0-9 的字符串
 * min(length) 最小长度
 * max(length) 最大长度
 * required() 值是必填项,不能为 undefined
 * pattern( 正则表达式 ) 值必须符合正则表达式的规则
 */


// 用户名的验证规则
const username = joi.string().alphanum().min ( 1 ). max ( 10 ).required ()
// 密码的验证规则
const password = joi.string().pattern( /^\S{6,12}$/ ).required ()
// 注册和登录表单的验证规则对象
exports.reg_login_schema = {
    // 表示需要对 req.body 中的数据进行验证
    body : {
        username ,
        password ,
    },
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

使用

const express = require("express")

const router = express.Router()

const userHandler = require("../router_handler/user")

// 1. 导入验证表单数据的中间件
const expressJoi = require ( '@escook/express-joi' )
// 2. 导入需要的验证规则对象
const { reg_login_schema } = require ( '../schema/user' )
// 3. 使用规则
router.post("/register",expressJoi(reg_login_schema),userHandler.userRegister)
router.post("/login",userHandler.userLogin)

module.exports = router;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

mongoose

npm install mongoose
  • 1
let mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test').then(()=>{
    console.log("ok")
}).catch(err=>{
    console.log(err);
});

//监听数据库连接状态
mongoose.connection.once('open',()=>{
    console.log('数据库连接成功……')

    const Schema = mongoose.Schema;
    //创建Schema对象(约束)
    let stuSchema = new Schema({
        name: String,
        age: Number,
        gender:{
            type: String,
            default:'male',
            required: true
        },
        addr: String,
    },{timestamps:true})

    //将stuSchema映射到一个MongoDB collection并定义这个文档的构成
    let StuModule = mongoose.model('student',stuSchema);

    new StuModule({
        name: '小明',
        age: 18,
        addr: '北京'
    }).save().then((result)=>{
        console.log(result)
    }).catch(err=>{
        console.log(err);
    })

})

mongoose.connection.once('close',()=>{
    console.log('数据库断开……')
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/433759
推荐阅读
相关标签
  

闽ICP备14008679号