9、Node.js---Mongodb

目录

Mongodb是什么?

数据库是什么 ?

数据库的作用

数据库管理数据特点

 为什么选择 Mongodb

 Mongodb核心概念

Mongodb的下载与安装

配置步骤如下:

数据库命令

1. 显示所有的数据库

2. 切换到指定的数据库,如果数据库不存在会自动创建数据库

3. 显示当前所在的数据库

4. 删除当前数据库

集合命令

1. 创建集合

2. 显示当前数据库中的所有集合

3. 删除某个集合

4. 重命名集合

文档命令

1. 插入文档

2. 查询文档

3. 更新文档  

4. 删除文档

应用场景

 Mongoose

 使用流程:

Mongoose插入文档

Mongoose字段类型

字段值验证

必填项 

默认值

 枚举值

唯一值

Mongoose删除文档

增加

删除

Mongoose更新文档

更新一条数据

批量更新数据

 Mongoose读取(查询)文档

查询一条数据

批量查询数据

 Mongoose条件控制

运算符

逻辑运算

正则匹配

Mongoose个性化读取

字段筛选

数据排序

数据截取

Mongoose代码模块化

Mongodb图形化工具 Robo 3T

记账本案例优化


Mongodb是什么?

MongoDB 是一个基于分布式文件存储的数据库,官方地址 MongoDB: The Developer Data Platform | MongoDB
https://www.mongodb.com/

数据库是什么 ?

数据库(DataBase)是按照数据结构来组织、存储和管理数据的 应用程序

数据库的作用

数据库的主要作用就是 管理数据 ,对数据进行 增(c)、删(d)、改(u)、查(r 

数据库管理数据特点

相比于纯文件管理数据,数据库管理数据有如下特点:
1. 速度更快
2. 扩展性更强
3. 安全性更强

 为什么选择 Mongodb

操作语法与 JavaScript 类似,容易上手,学习成本低  

 Mongodb核心概念

  • 数据库database) 数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存 放很多集合
  • 集合(collection) 集合类似于 JS 中的数组,在集合中可以存放很多文档
  • 文档(document) 文档是数据库中的最小单位,类似于 JS 中的对象

 JSON 文件示例:

{
"accounts": [
{
"id": "3-YLju5f3",
"title": "买电脑",
"time": "2023-02-08",
"type": "-1",
"account": "5500",
"remarks": "为了上网课"
},
{
"id": "3-YLju5f4",
"title": "请女朋友吃饭",
"time": "2023-02-08",
"type": "-1",
"account": "214",
"remarks": "情人节聚餐"
},
{
"id": "mRQiD4s3K",
"title": "发工资",
"time": "2023-02-19",
"type": "1",
"account": "4396",
"remarks": "终于发工资啦!~~"
}
],
"users":[
{
"id": 1,
"name": "zhangsan",
"age": 18
},
{
"id": 2,
"name": "lisi",
"age": 20
},
{
"id": 3,
"name": "wangwu",
"age": 22
}
]
}

一个json文件就相当于一个数据库,accounts和users就相当于是collection,accounts和users里面的对象就相当于是doucument,对象中的属性(如name、id等称之为字段)

  • 一个 JSON 文件 好比是一个 数据库 ,一个 Mongodb 服务下可以有 N 个数据库
  • JSON 文件中的 一级属性的数组值 好比是 集合
  • 数组中的对象好比是 文档
  • 对象中的属性有时也称之为 字段

一般情况下

一个项目使用一个数据库
一个集合会存储同一种类型的数据

Mongodb的下载与安装

下载地址: https://www.mongodb.com/try/download/community

 建议选择 zip 类型, 通用性更强

配置步骤如下:

  1.  将压缩包移动到 你喜欢的盘下,然后解压
  2.  创建 E:\data\db 目录,mongodb 会将数据默认保存在这个文件夹
  3.  mongodb bin 目录作为工作目录,启动命令行
  4. 运行命令 mongod

 看到最后的 waiting for connections 则表明服务 已经启动成功

然后可以使用 mongo 命令连接本机的 mongodb 服务

注意:
为了方便后续方便使用 mongod 命令,可以将 bin 目录配置到环境变量 Path
千万不要选中服务端窗口的内容 ,选中会停止服务,可以 敲回车 取消选中

数据库命令

1. 显示所有的数据库

show dbs

2. 切换到指定的数据库,如果数据库不存在会自动创建数据库

use 数据库名

3. 显示当前所在的数据库

db

4. 删除当前数据库

use 库名
db.dropDatabase()

集合命令

1. 创建集合

db.createCollection('集合名称')

2. 显示当前数据库中的所有集合

show collections

3. 删除某个集合

db.集合名.drop()

4. 重命名集合

db.集合名.renameCollection('newName')

文档命令

1. 插入文档

db.集合名.insert(文档对象);

//例如
db.user.insert({name:'森树',age:30})

2. 查询文档

db.集合名.find(查询条件)

//例如

db.user.find()
 db.user.find({age:30})
_id mongodb 自动生成的唯一编号,用来唯一标识文档

3. 更新文档  

db.集合名.update(查询条件,新的文档)
db.集合名.update({name:'张三'},{$set:{age:19}})

4. 删除文档

db.集合名.remove(查询条件)

应用场景

新增
  • 用户注册
  • 发布视频
  • 发布商品
  • 发朋友圈
  • 发评论
  • 发微博
  • 发弹幕
  • .......
删除
  • 删除评论
  • 删除商品
  • 删除文章
  • 删除视频
  • 删除微博
  • ......
更新
  • 更新个人信息
  • 修改商品价格
  • 修改文章内容
  • ......
查询
  • 商品列表
  • 视频列表
  • 朋友圈列表
  • 微博列表
  • 搜索功能
  • ......

 Mongoose

Mongoose 是一个对象文档模型库,官网 http://www.mongoosejs.net/
作用:
方便使用代码操作 mongodb 数据库

 使用流程:

连接数据库:

//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');

//3、连接mongodb服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/books');

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    console.log('连接成功');
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    console.log('连接失败');
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

//关闭mongodb的连接
setTimeout(()=>{
    mongoose.disconnect();
},2000)

注意:官方建议把on换成once

Mongoose插入文档

//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');

//3、连接mongodb服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/books');

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    // console.log('连接成功');
    //5、创建文档中的结构对象
    //设置集合中的文档属性以及属性值的类型
    let BookSchma=new mongoose.Schema({
        name:String,
        author:String,
        price:Number
    });

    //6、创建模型对象,对文档操作的封装对象
    let BookModel=mongoose.model('books',BookSchma);

    //新增
    BookModel.create({
        name:'西游记',
        author:'吴承恩',
        price:19.9
    },(err,data)=>{
        //判断是否有错误
        if(err){
            console.log(err);
            return;
        }

        //如果没有出错,则输出插入后文档对象
        console.log(data);
        //8、关闭数据库连接(项目运行过程中,不会添加改代码)
        mongoose.disconnect();
    });
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    console.log('连接失败');
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

  

注意:7版本的会报错:

throw new MongooseError('Model.create() no longer accepts a callback');

原因:从6.0.0版开始,Mongoose中的方法不再接受回调作为最后一个参数,而是返回一个promise。2您应该更新代码,使用promise来处理create()方法的结果

或者手动下载6版本即可。

npm install mongoose@6.0.0

Mongoose字段类型

类型描述
String字符串
Number数字
Boolean布尔值
Array数组,也可以使用[ ]来标识
Date日期
BufferBuffer对象
Mixed
任意类型,需要使用 mongoose.Schema.Types.Mixed 指定
ObjectId
对象 ID ,需要使用 mongoose.Schema.Types.ObjectId 指定,文档ID,相当于外键,用于联合文档查询用
Decimal128
高精度数字,需要使用 mongoose.Schema.Types.Decimal128 指定
//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');

//3、连接mongodb服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/books');

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    // console.log('连接成功');
    //5、创建文档中的结构对象
    //设置集合中的文档属性以及属性值的类型
    let BookSchma=new mongoose.Schema({
        name:String,
        author:String,
        price:Number,
        is_hot:Boolean,
        tags:Array,
        publish_time:Date,
        test:mongoose.Schema.Types.Mixed,
        test2:mongoose.Schema.Types.ObjectId,  //文档ID,相当于外键,用于联合文档查询用
    });

    //6、创建模型对象,对文档操作的封装对象
    let BookModel=mongoose.model('books',BookSchma);

    //新增
    BookModel.create({
        name:'西游记',
        author:'吴承恩',
        price:19.9,
        is_hot:true,
        tags:['鬼怪','励致','社会'],
        publish_time:new Date(),
        test:123  //test可以随意给值
       
        
    },(err,data)=>{
        //判断是否有错误
        if(err){
            console.log(err);
            return;
        }

        //如果没有出错,则输出插入后文档对象
        console.log(data);
        //8、关闭数据库连接(项目运行过程中,不会添加改代码)
        mongoose.disconnect();
    });
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    console.log('连接失败');
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

字段值验证

文档属性的值校验,Mongoose 有一些内建验证器,可以对字段值进行验证

必填项 

title: {
type: String,
required: true // 设置必填项
},

默认值

author: {
type: String,
default: '匿名' //默认值
},

 枚举值

gender: {
type: String,
enum: ['男','女'] //设置的值必须是数组中的
},

唯一值

username: {
type: String,
unique: true
},
注意:
unique 需要 重建集合 才能有效果(把原来的数据删除,在新建)
永远不要相信用户的输入
//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');

//3、连接mongodb服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/books');

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    // console.log('连接成功');
    //5、创建文档中的结构对象
    //设置集合中的文档属性以及属性值的类型
    let BookSchma=new mongoose.Schema({
        name:{
            type:String,
            require:true, //表明该属性必须不为空
            unique:true //设置为独一无二的
        },
        author:{
            type:String,
            default:'匿名'
        },
        //类型
        types:{
            type:String,
            //枚举
            enum:['言情','志怪','城市','恐怖']
        },
        price:Number,
        is_hot:Boolean,
        tags:Array,
        publish_time:Date,
        test:mongoose.Schema.Types.Mixed,
        test2:mongoose.Schema.Types.ObjectId,  //文档ID,相当于外键,用于联合文档查询用
    });

    //6、创建模型对象,对文档操作的封装对象
    let BookModel=mongoose.model('books',BookSchma);

    //新增
    BookModel.create({
        name:'西游记',
        // author:'吴承恩',
        types:'志怪',
        price:19.9,
        is_hot:true,
        tags:['鬼怪','励致','社会'],
        publish_time:new Date(),
        test:123  //test可以随意给值
       
        
    },(err,data)=>{
        //判断是否有错误
        if(err){
            console.log(err);
            return;
        }

        //如果没有出错,则输出插入后文档对象
        console.log(data);
        //8、关闭数据库连接(项目运行过程中,不会添加改代码)
        mongoose.disconnect();
    });
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    console.log('连接失败');
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

Mongoose删除文档

CURD
数据库的基本操作包括四个,增加(create),删除(delete),修改(update),查(read)

增加

 插入一条

SongModel.create({
    title:'给我一首歌的时间',
    author: 'Jay'
}, function(err, data){
    //错误
    console.log(err);
    //插入后的数据对象
    console.log(data);
});
批量插入
//1.引入mongoose
const mongoose = require('mongoose');
//2.链接mongodb数据库 connect 连接
mongoose.connect('mongodb://127.0.0.1:27017/project');
//3.设置连接的回调
mongoose.connection.on('open',()=>{
    //4.声明文档结构
    const PhoneSchema = new mongoose.Schema({
    brand:String,
    color:String,
    price:Number,
    tags:Array
})
//6.创建模型对象
const PhoneModel = mongoose.model('phone',PhoneSchema);
PhoneModel.insertMany([
{
    brand:'华为',
    color:'灰色',
    price:2399,
    tags:['电量大','屏幕大','信号好']
},
{
    brand:'小米',
    color:'白色',
    price:2099,
    tags:['电量大','屏幕大','信号好']
}
],(err,data)=>{
    if(err) throw err;
    console.log('写入成功');
    mongoose.connection.close();
})
})

删除

删除一条数据
SongModel.deleteOne({_id:'5dd65f32be6401035cb5b1ed'}, function(err){
    if(err) throw err;
    console.log('删除成功');
    mongoose.connection.close();
});
批量删除
SongModel.deleteMany({author:'Jay'}, function(err){
    if(err) throw err;
    console.log('删除成功');
    mongoose.connection.close();
});

案例

//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');

//3、连接mongodb服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/books');

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    // console.log('连接成功');
    //5、创建文档中的结构对象
    //设置集合中的文档属性以及属性值的类型
    let BookSchma=new mongoose.Schema({
        name:{
            type:String,
            require:true, //表明该属性必须不为空
            unique:true //设置为独一无二的
        },
        author:{
            type:String,
            default:'匿名'
        },
        //类型
        types:{
            type:String,
            //枚举
            enum:['言情','志怪','城市','恐怖']
        },
        price:Number,
        is_hot:Boolean,
        tags:Array,
        publish_time:Date,
        test:mongoose.Schema.Types.Mixed,
        test2:mongoose.Schema.Types.ObjectId,  //文档ID,相当于外键,用于联合文档查询用
    });

    //6、创建模型对象,对文档操作的封装对象
    let BookModel=mongoose.model('novel',BookSchma);
    

  //删除一条
  BookModel.deleteOne({_id:'643b6af31798c9cfab91aae6'},(err,data)=>{
    //判断
    if(err){
      console.log(err);
      return;
    }
    //输出data
    console.log(data);
  });

  //批量删除
  BookModel.deleteMany({is_hot:false},(err,data)=>{
    //判断
    if(err){
      console.log(err);
      return;
    }
    //输出data
    console.log(data);
  });
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    console.log('连接失败');
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

Mongoose更新文档

更新一条数据

SongModel.updateOne({author: 'JJ Lin'}, {author: '林俊杰'}, function (err) {
    if(err) throw err;
    mongoose.connection.close();
});

批量更新数据

SongModel.updateMany({author: 'Leehom Wang'}, {author: '王力宏'}, function (err) {
    if(err) throw err;
    mongoose.connection.close();
});

案例:

 //7.更新文档 更新一条   (条件,新的内容,回调函数)
    BookModel.updateOne({name:'红楼梦'},{price:9.9},(err,data)=>{
        if(err){
            console.log('更新失败');
            return;
        }
        //输出data
        console.log(data);
    });

    //批量更新
    BookModel.updateMany({author:'余华'},{is_hot:false},(err,data)=>{
        if(err){
            console.log('更新失败');
            return;
        }
        //输出data
        console.log(data);
    });

 Mongoose读取(查询)文档

查询一条数据

SongModel.findOne({author: '王力宏'}, function(err, data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});
//根据 id 查询数据
SongModel.findById('5dd662b5381fc316b44ce167',function(err, data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});

批量查询数据

//不加条件查询
SongModel.find(function(err, data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});
//加条件查询
SongModel.find({author: '王力宏'}, function(err, data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});

 Mongoose条件控制

运算符

mongodb 不能 > < >= <= !== 等运算符,需要使用替代符号
  • > 使用 $gt
  • < 使用 $lt
  • >= 使用 $gte
  • <= 使用 $lte
  • !== 使用 $ne
db.students.find({id:{$gt:3}}); id号比3大的所有的记录
//价格小于20的书
   BookModel.find({price:{$lt:20}},(err,data)=>{
    if(err){
        console.log('读取失败');
        return;

    }
    console.log(data);
   });

逻辑运算

$or 逻辑或的情况
db.students.find({$or:[{age:18},{age:24}]});
 //曹雪芹或余华的书
   BookModel.find({$or:[{author:'曹雪芹'},{author:'余华'}]},(err,data)=>{
    if(err){
        console.log('读取失败');
        return;

    }
    console.log(data);
   });
$and 逻辑与的情况
db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]});
//    价格大于30且小于70
   BookModel.find({$and:[{price:{$gt:30}},{price:{$lt:70}}]},(err,data)=>{
    if(err){
        console.log('读取失败');
        return;

    }
    console.log(data);
   });

正则匹配

条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询
db.students.find({name:/imissyou/});
 //正则表达式   搜索书名中带“三”的书籍
   BookModel.find({name:/三/},(err,data)=>{
    if(err){
        console.log('读取失败');
        return;

    }
    console.log(data);
   });


   //正则另一种方式
   BookModel.find({name:new RegExp('三')},(err,data)=>{
    if(err){
        console.log('读取失败');
        return;

    }
    console.log(data);
   });
});

Mongoose个性化读取

字段筛选

//0:不要的字段
//1:要的字段
SongModel.find().select({_id:0,title:1}).exec(function(err,data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});
//7.设置字段
   BookModel.find().select({name:1,author:1,_id:0}).exec((err,data)=>{
    if(err){
        console.log('查询失败');
        return;
    }
    console.log(data);
   });

数据排序

//sort 排序
//1:升序
//-1:倒序
SongModel.find().sort({hot:1}).exec(function(err,data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});
//数据排序
   BookModel.find().select({name:1,price:1,_id:0}).sort({price:1}).exec((err,data)=>{
    if(err){
        console.log('查询失败');
        return;
    }
    console.log(data);
   });

数据截取

//skip 跳过 limit 限定
SongModel.find().skip(10).limit(10).exec(function(err,data){
    if(err) throw err;
    console.log(data);
    mongoose.connection.close();
});
//数据的截取
   //取前三
   BookModel.find().select({name:1,price:1,_id:0}).sort({price:1}).limit(3).exec((err,data)=>{
    if(err){
        console.log('查询失败');
        return;
    }
    console.log(data);
   });

   //取4-6,跳过123
   BookModel.find()
   .select({name:1,price:1,_id:0})
   .sort({price:1})
   .skip(3)
   .limit(3)
   .exec((err,data)=>{
    if(err){
        console.log('查询失败');
        return;
    }
    console.log(data);
   });

Mongoose代码模块化

详情见‘08_mongoose模块化’文件

案例:

文件分配:

 index.js

//导入db文件
const db=require('./db/db');
//导入mongoose
const mongoose=require('mongoose');
//导入BookModel
const BookModel=require('./models/BookModel');
//调用回调函数
db(()=>{
     // console.log('连接成功');
   
    //新增
    BookModel.create({
        name:'中国文化',
        author:'吴承恩',
        price:19.9,
        is_hot:true,
        tags:['鬼怪','励致','社会'],
        publish_time:new Date(),
        test:123  //test可以随意给值
       
        
    },(err,data)=>{
        //判断是否有错误
        if(err){
            console.log(err);
            return;
        }

        //如果没有出错,则输出插入后文档对象
        console.log(data);
        //8、关闭数据库连接(项目运行过程中,不会添加改代码)
        mongoose.disconnect();
    });

},()=>{
    console.log('连接失败')
})   

BookModel.js(在models文件夹下存放)

 //导入模块
 const mongoose=require('mongoose');
 //创建文档中的结构对象
//设置集合中的文档属性以及属性值的类型
let BookSchma=new mongoose.Schema({
        name:String,
        author:String,
        price:Number,
        is_hot:Boolean,
        tags:Array,
        publish_time:Date,
        test:mongoose.Schema.Types.Mixed,
        test2:mongoose.Schema.Types.ObjectId,  //文档ID,相当于外键,用于联合文档查询用
});

//创建模型对象,对文档操作的封装对象
let BookModel=mongoose.model('books',BookSchma);

//暴露模型对象
module.exports = BookModel;

db.js(连接数据库操作,在db文件下存放)

//success:数据成功的回调,error数据失败的回调
module.exports=function(success,error){
    //判断error为其设置默认值
    if(typeof error !== 'function'){
        error=()=>{
            console.log('连接失败')
        }
    }


//1、安装mongoose
//2、导入mongoose
const mongoose = require('mongoose');
//导入配置文件   ,解构赋值
const {DBHOST,DBPORT,DBNAME}=require('../config/config');

//3、连接mongodb服务                      数据库名称
mongoose.connect(`mongodb://${DBHOST}:${DBPORT}/${DBNAME}`);

//4、设置回调
//设置连接成功的回调
mongoose.connection.on('open',()=>{
    success();
});

//设置连接错误的回调
mongoose.connection.on('error',()=>{
    error();
});

//设置连接关闭的回调
mongoose.connection.on('close',()=>{
    console.log('连接关闭');

});

}

config.js(配置文件,在config文件下存放)方便以后修改服务器名,端口号,数据库名

//配置文件
module.exports={
    DBHOST:'127.0.0.1',
    DBPORT:'27017',
    DBNAME:'books'
}

写代码基本流程:db.js --> index.js --> BookModel.js --> config.js

Mongodb图形化工具 Robo 3T

我们可以使用图形化的管理工具来对 Mongodb 进行交互,这里演示两个图形化工具

1、R obo 3T 免费 https://github.com/Studio3T/robomongo/releases

     

  要先开启mongod服务器,才能连接。

2、Navicat  收费 https://www.navicat.com.cn/

 要先开启mongod服务器,然后双击mongodb数据库。

新建数据快捷键:tab键。

=========================================================================

记账本案例优化

结合数据库

1、项目目录结构:

  

2、编辑www.js文件

  

创建模型文件

 AccountModel.js

 //导入模块
 const mongoose=require('mongoose');
 //创建文档中的结构对象
//设置集合中的文档属性以及属性值的类型
let AccountSchema=new mongoose.Schema({
    //标题
    title:{
        type:String,
        required:true
    },
    //时间
    time:Date,
    //类型
    type:{
        type:Number,
        default:-1
    },
    //金额
    account:{
        type:Number,
        required:true
    },
    //备注
    remarks:{
        type:String
    }

});

//创建模型对象,对文档操作的封装对象
let AccountModel=mongoose.model('accounts',AccountSchema);

//暴露模型对象
module.exports = AccountModel;

插入数据库

注意:时间是一个字符串要转换成对象Object,再转换成时间Date(借助moment工具包)

Moment.js 中文网

  

   

npm i moment

  

 index.js里新增如下代码

  

     

成功!

 读取数据库

index.js新增如下代码

  

 删除数据

list.ejs新增代码:

     

index.js新增代码: 

    

list.ejs新增代码:

 

跳转到这里来 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值