mongo记录day1

const koa =require('koa') 
const bodyParser =require('koa-bodyparser')
const Router =require('koa-router')
const mongodb =require('mongodb')

let dbc,company=null
mongodb.MongoClient.connect('mongodb://localhost:27017/',(err,db)=>{
    if(err)throw err
    console.log('数据库连接成功')
    dbc=db
    company=dbc.db('company')
})

const user=new Router()
const router=new Router()

user
.get('/name',async (ctx,next)=>{
    let oQuery=ctx.request.query
    if(oQuery.name){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                company.collection('workmate').find({name:oQuery.name}).toArray((err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
   
    await next()
})
//查找嵌入式文档 db.workmate.find({"skill.skillOne":"HTML+CSS"})
.get('/namebyskill',async (ctx,next)=>{
    let oQuery=ctx.request.query
    if(oQuery){
        let persons=await (()=>{
            let skill=JSON.parse(oQuery.skill)
            let keys=Object.keys(skill)
            let w=`skill.${keys[0]}`
            return new Promise((resolve,reject)=>{
                //结果显示 修改无效
                company.collection('workmate').find({[w]:skill[keys[0]]},{name:true,age:true,'skill.skill1':true}).toArray((err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        delete res[0]._id
                        delete res[0].register
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
   
    await next()
})
//查找嵌入式文档 db.workmate.find({"skill.skillOne":"HTML+CSS"})
.get('/range',async (ctx,next)=>{
    let oq=ctx.request.query
    if(oq.min&&oq.max){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                //结果显示 修改无效
                company.collection('workmate').find({age:{$lte:Number(oq.max),$gte:Number(oq.min)}},{name:true,age:true,'skill.skill1':true}).toArray((err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
   
    await next()
})
//更新部分对象下的数据数据
.put('/skill',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.skill!=0&&bodyData.name){
        let persons=await (()=>{
            let skill={}
            return new Promise((resolve,reject)=>{
                company.collection('workmate').find({name:bodyData.name}).toArray((err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        skill=res[0].skill
                        skill=Object.assign(skill,JSON.parse(bodyData.skill))
                        console.log(skill)
                        
                        company.collection('workmate').updateOne({name:bodyData.name},{$set:{skill}},(err,res)=>{
                            if(err){
                                reject(err)
                            }else{
                                resolve(res)
                            }
                        })
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
.delete('/age',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.key&&bodyData.name){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                // $unset 删除某个属性 只在乎key值  $unset:{key:""}
                company.collection('workmate').updateOne({name:bodyData.name},{$unset:{[bodyData.key]:''}},(err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
//添加和修改键值对
.post('/key',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.key&&bodyData.name){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                company.collection('workmate').updateOne({name:bodyData.name},{$set:JSON.parse(bodyData.key)},(err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
//全部添加key值
.post('/keys',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.key){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                console.log(bodyData.key)
                company.collection('workmate').updateMany({},{$set:JSON.parse(bodyData.key)},{multi:true},(err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
//全部添加key值 同上面啊的效果是一样的
.post('/keys2',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.key){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                console.log(bodyData.key)
                company.collection('workmate').updateMany({},{$set:JSON.parse(bodyData.key)},(err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
// {$set:{age:20}},{upsert:true}   修改数据 没有就添加
//$inc  修改相对 加减
.put('/age',async (ctx,next)=>{
    let bodyData=ctx.request.body

    if(bodyData.ageAmount&&bodyData.name){
        let persons=await (()=>{
            return new Promise((resolve,reject)=>{
                company.collection('workmate').updateOne({name:bodyData.name},{$inc:{age:Number(bodyData.ageAmount)}},(err,res)=>{
                    if(err){
                        reject(err)
                    }else{
                        resolve(res)
                    }
                })
            })
        })()
        ctx.body=persons
    }else{
        ctx.status=400
        ctx.body={success:false,message:'参数错误'}
    }
    await next()
})
//数组 $push:{interest:'game'}添加  是否存在 interest:{$ne:'game'}
// db.workmate.update({name:'xiaoWang',"interest":{$ne:'playGame'}},{$push:{interest:'Game'}}) 前面查找 后面是添加 如果不存在再执行操作,存在就不执行
// db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:"readBook"}})它是$ne的升级版本(查找是否存在,不存在就push上去
// var newInterset=["Sing","Dance","Code"];
// db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:{$each:newInterset}}})
// db.workmate.update({name:'xiaoWang'},{$pop:{interest:1}})    1:从数组末端进行删除 -1:从数组开端进行删除
.get('/lists',async (ctx,next)=>{
    let oQuery=ctx.request.query
    if(!oQuery.page){
        ctx.status=400
        ctx.body={success:false,message:'请传入page'}
    }
    let skipTip=Number(oQuery.page)*8
    let persons=await (()=>{
        return new Promise((resolve,reject)=>{
            company.collection('workmate').find().sort({name:-1}).skip(skipTip).limit(8).toArray((err,res)=>{
                if(err){
                    reject(err)
                }else{
                    resolve(res)
                }
            })
        })
    })()
    ctx.body=persons
    await next()
})
.post('/lists',async(ctx,next)=>{
    let d=[]
    for(let i=0;i<49;i++){
        let data={
            "name":"王榕"+i,
            "skill":{
                "skill1":"ppt"
            },
            "register":1530088530369,
            "age":23
        }
        d.push(data)
    }
    let persons=await (()=>{
        return new Promise((resolve,reject)=>{
            company.collection('workmate').insertMany(d,(err,res)=>{
                if(err){
                    reject(err)
                }else{
                    resolve(res)
                }
            })
        })
    })()
    ctx.body=persons
    await next()
})
/* 

db.workmate.find(
    {
        $or:[
            {age:{
                $in:[27,28]
            }},
            {name:'王榕22'}
        ]
    },
    {
        _id:0,
        name:1,
        age:1
    }
)
{ "name" : "王榕22", "age" : 27 }
{ "name" : "王榕24", "age" : 28 }
{ "name" : "王榕22", "age" : 23 } 

数组 完全匹配
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "fe", "f" ] }
> db.wokers.find({interest:['fe','a']})
> db.wokers.find({interest:['fe','f','a']})
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c0cc44e54f67115895b"), "name" : "we4", "interest" : [ "fe", "f", "a" ] }

单项查询 存在即匹配
> db.wokers.find({interest:'fe'})
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "fe", "f" ] }
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c0cc44e54f67115895b"), "name" : "we4", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c19c44e54f67115895c"), "name" : "we3", "interest" : [ "fe", "b", "a" ] }

数组部分匹配 包含都有
> db.wokers.find({interest:{$all:['a','b']}})
{ "_id" : ObjectId("5b347c19c44e54f67115895c"), "name" : "we3", "interest" : [ "fe", "b", "a" ] }

数组部分 包含 其中一个 
> db.wokers.find({interest:{$in:['a','b']}})
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c0cc44e54f67115895b"), "name" : "we4", "interest" : [ "fe", "f", "a" ] }
{ "_id" : ObjectId("5b347c19c44e54f67115895c"), "name" : "we3", "interest" : [ "fe", "b", "a" ] }

数组长度 定数2
> db.wokers.find({interest:{$size:2}})
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "fe", "f" ] }

结果数组处理  $slice  1:正数 -1:倒数 数组 第0个到2个 第一个是1不包含开始 
> db.wokers.find({interest:{$size:2}},{interest:{$slice:[0,2]}})
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "fe", "f" ] }
> db.wokers.find({interest:{$size:2}},{interest:{$slice:1}})
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "fe" ] }
> db.wokers.find({interest:{$size:2}},{interest:{$slice:-1}})
{ "_id" : ObjectId("5b347bf2c44e54f671158958"), "name" : "we", "interest" : [ "f" ] }

// 参数1 条件 参数2 显示结果 limit()限制条目 skip()跳过条目sort排序  整数正序  负数 倒序
> db.wokers.find({},{name:1,age:1}).limit(2).skip(0).sort({age:-1})
{ "_id" : ObjectId("5b347c0cc44e54f67115895b"), "name" : "we4", "age" : 36 }
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "age" : 26 }

// 参数1 条件 参数2 显示结果 limit()限制条目 skip()跳过条目sort排序  整数正序  负数 倒序
> db.wokers.find({},{name:1,age:1}).limit(2).skip(2).sort({age:-1})
{ "_id" : ObjectId("5b347c19c44e54f67115895c"), "name" : "we5", "age" : 26 }
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "age" : 25 }

*/
/* 
> db.workmate.find({$and:[{age:{$in:[27,28]}},{name:'王榕22'}]},{_id:0,name:1,age:1})
{ "name" : "王榕22", "age" : 27 }

索引:构造百万级数据

快,但是消耗内存和硬盘

//获取 workers 集合 详情
> db.wokers.stats()
{
        "ns" : "company.wokers",
        "size" : 450,
        "count" : 5,
        "avgObjSize" : 90,
        "storageSize" : 36864,
        "capped" : false,


索引:只有一条索引  _id  自动生成  很少使用
    
    1.数据不超过万条
    2.查询数据超过30%,不要索引 不快反而慢  性别 技术工种 
    3.数字索引比字符串索引快
    4.把你经常查询的数据做成一个内嵌数据(对象型的数据),然后集体进行索引。


只有64 个索引 mongo
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "company.wokers"
        }
]
// 建立索引

> db.wokers.ensureIndex({name:1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
// 两个索引
> db.wokers.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "company.wokers"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1
                },
                "name" : "name_1",
                "ns" : "company.wokers"
        }
]

复合索引:
在建一个索引
> db.wokers.ensureIndex({idNum:1})
    索引顺序 
    按获取的索引 顺序下来  以前是数字  再 字母

    hint方法 指明优先使用的索引
    > db.wokers.find({name:'we3',idNum:'idofe90'}).hint({idNum:1})
    { "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ], "age" : 26, "idNum" : "idofe90" }

删除索引
 db.wokers.dropIndex('idNum_1') //使用的是索引对应的name属性
    { "nIndexesWas" : 3, "ok" : 1 }
    > db.wokers.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_",
                    "ns" : "company.wokers"
            },
            {
                    "v" : 2,
                    "key" : {
                            "name" : 1
                    },
                    "name" : "name_1",
                    "ns" : "company.wokers"
            }
    ]



    全文索引:
        1.建立全文索引
        > db.wokers.ensureIndex({contentinfo:'text'})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "ok" : 1
}
        2.
                {
                "v" : 2,
                "key" : {
                        "_fts" : "text",
                        "_ftsx" : 1
                },
                "name" : "contentinfo_text",//name 不一样的
                "ns" : "company.wokers",
                "weights" : {
                        "contentinfo" : 1
                },
                "default_language" : "english",
                "language_override" : "language",
                "textIndexVersion" : 3
        }

全文索引查找
        为什么只能找英文
        > db.wokers.find({$text:{$search:'btr'}})
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ], "age" : 26, "idNum" : "idofe90", "contentinfo" : "few wefw fwewe f i am btr ambtr" }


> db.wokers.find({$text:{$search:'wefw'}})
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ], "age" : 26, "idNum" : "idofe90", "contentinfo" : "few wefw fwewe f i am btr ambtr" }
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ], "age" : 25, "idNum" : "idofe90", "contentinfo" : "aw wefw fwewe f i am btr ambtr" }
> db.wokers.find({$text:{$search:'few'}})// 不知道为什么找不到这里
> db.wokers.find({$text:{$search:'wefw -aw'}})  - 表示排除
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ], "age" : 26, "idNum" : "idofe90", "contentinfo" : "few wefw fwewe f i am btr ambtr" }

> db.wokers.find({$text:{$search:'wefw aw'}}) 空格表示或的关系
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ], "age" : 25, "idNum" : "idofe90", "contentinfo" : "aw wefw fwewe f i am btr ambtr" }
{ "_id" : ObjectId("5b347c06c44e54f67115895a"), "name" : "we3", "interest" : [ "fe", "f", "a" ], "age" : 26, "idNum" : "idofe90", "contentinfo" : "few wefw fwewe f i am btr ambtr" }
>

转义字符 
> db.wokers.find({$text:{$search:'\"aw wefw\"'}})
{ "_id" : ObjectId("5b347bffc44e54f671158959"), "name" : "we2", "interest" : [ "fe", "f", "a" ], "age" : 25, "idNum" : "idofe90", "contentinfo" : "aw wefw fwewe f i am btr ambtr" }
得到混合的 连着的字符串查找 而不是 两个单独的 单词





用户权限部分:

我们默认开了一个最高管理权限方便我们管理数据库

能用mongo表示最高权限用户

用户的数据库
> use admin
switched to db admin
> show collections
system.version

创建角色:
        db.createUser({
            user:'useradmin',//用户名
            pwd:'123456',//密码
            customData:{//管理员信息
                name:'user管理',
                email:'[email protected]',
                age:12
            },
            roles:[{//用户对于不同数据的 权限
                role:'readWrite',//read readWrite
                db:'user'
            },
            'read'//其他数据库
        ]
        })



Successfully added user: {
        "user" : "useradmin",
        "customData" : {
                "name" : "user管理",
                "email" : "[email protected]",
                "age" : 12
        },
        "roles" : [
                {
                        "role" : "readWrite",
                        "db" : "user"
                },
                "read"
        ]
}

> show collections
system.users//添加了用户就有的集合
system.version
> db
admin
> db.system.users.find()
{ "_id" : "admin.useradmin", "user" : "useradmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "mCJGHoxiiPFWACspHUtUkg==", "storedKey" : "NJZktblBzkMvSRpYNCNIHzHNxH4=", "serverKey" : "gTGUAyyUVKGoXy/gwApbmo2Zx2M=" } }, "customData" : { "name" : "user管理", "email" : "[email protected]", "age" : 12 }, "roles" : [ { "role" : "readWrite", "db" : "user" }, { "role" : "read", "db" : "admin" } ] }

删除用户
> db.system.users.remove({user:'useradmin'})
WriteResult({ "nRemoved" : 1 })

建权:

用户登录 不再直接 通过 mongo 连接 最高权限 而是通过一个 有设定权限的账号
> db.auth('useradmin','123456')  账号密码 登录 
1//成功

重启服务》数据库服务  表示需要权限了
C:\data>mongod --auth

再试试用 mongo 连接 
C:\Users\admin>mongo
MongoDB shell version v3.6.5
connecting to: mongodb://127.0.0.1:27017 //为啥还是能连接到数据库呢 不是强制关闭么
MongoDB server version: 3.6.5 
> show dbs  //命令返回没有权限  
2018-06-29T09:20:21.375+0800 E QUERY    [thread1] Error: listDatabases failed:{
        "ok" : 0,
        "errmsg" : "not authorized on admin to execute command { listDatabases: 1.0, $db: \"admin\" }",
        "code" : 13,
        "codeName" : "Unauthorized"
} :

使用鉴权用户登录
就是我们之前建立的账户

    C:\Users\admin>mongo -u useradmin -p 123456 127.0.0.1:27017/admin
    MongoDB shell version v3.6.5
    connecting to: mongodb://127.0.0.1:27017/admin
    MongoDB server version: 3.6.5

错误
    C:\Users\admin>mongo -u useramdin 123456 127.0.0.1:27017/admin
    MongoDB shell version v3.6.5
    Enter password:
    connecting to: mongodb://127.0.0.1:27017/123456
    MongoDB server version: 3.6.5
    2018-06-29T09:25:53.983+0800 E QUERY    [thread1] Error: Authentication failed. :
    DB.prototype._authOrThrow@src/mongo/shell/db.js:1608:20
    @(auth):6:1
    @(auth):1:2
    exception: login failed

有权限 正常操作    
    > use user
    switched to db user
    > show collections
    user
    > db.user.find()
    { "_id" : ObjectId("5b31ffa5868b4e3aa9ead2ff"), "name" : "few" }

无权限 报 13

    > use company
    switched to db company
    > show collections
    2018-06-29T09:28:02.262+0800 E QUERY    [thread1] Error: listCollections failed: {
            "ok" : 0,
            "errmsg" : "not authorized on company to execute command { listCollections: 1.0, filter: {}, $db: \"company\" }",
            "code" : 13,
            "codeName" : "Unauthorized"
    } :
    _getErrorWithCode@src/mongo/shell/utils.js:25:13
    DB.prototype._getCollectionInfosCommand@src/mongo/shell/db.js:941:1
    DB.prototype.getCollectionInfos@src/mongo/shell/db.js:953:19
    DB.prototype.getCollectionNames@src/mongo/shell/db.js:964:16
    shellHelper.show@src/mongo/shell/utils.js:842:9
    shellHelper@src/mongo/shell/utils.js:739:15
    @(shellhelp2):1:1

    数据库备份
    没有备份权限
    C:\Users\admin>mongodump --host 127.0.0.1 --port 27017 --out D:/backup/ --collection user --db user --username useradmin --password 123456
    2018-06-29T09:53:44.495+0800    Failed: error connecting to db server: server returned error on SASL authentication step: Authentication failed.
    
重启服务  使用 最高权限

    mongod 

    C:\Users\admin>mongodump --host 127.0.0.1 --port 27017 --out D:/backup/
    2018-06-29T09:56:44.501+0800    writing admin.system.users to
    2018-06-29T09:56:44.572+0800    done dumping admin.system.users (1 document)
    2018-06-29T09:56:44.572+0800    writing admin.system.version to
    2018-06-29T09:56:44.576+0800    done dumping admin.system.version (2 documents)
    2018-06-29T09:56:44.576+0800    writing log.test to
    2018-06-29T09:56:44.576+0800    writing log.login to
    2018-06-29T09:56:44.577+0800    writing company.workmate to
    2018-06-29T09:56:44.577+0800    writing company.wokers to
    2018-06-29T09:56:44.584+0800    done dumping log.login (2 documents)
    2018-06-29T09:56:44.584+0800    writing user.user to
    2018-06-29T09:56:44.592+0800    done dumping company.workmate (101 documents)
    2018-06-29T09:56:44.593+0800    done dumping log.test (1000 documents)
    2018-06-29T09:56:44.593+0800    done dumping company.wokers (6 documents)
    2018-06-29T09:56:44.593+0800    done dumping user.user (1 document)    

    输出备份文件中  json后缀是描述 bson是数据


恢复文件

    C:\Users\admin>mongorestore --host 127.0.0.1 --port 27017 D:/backup/
    > show dbs
    admin    0.000GB
    company  0.000GB
    config   0.000GB
    local    0.000GB
    log      0.000GB
    user     0.000GB

    数据库已经恢复

图形化界面

    https://robomongo.org/download
    
*/

const app=new koa()

router
    .use('/user',user.routes(),user.allowedMethods())
app
    .use(bodyParser())
    .use(router.routes())
    .use(router.allowedMethods())

app.listen(3002,()=>{
    console.log('run')
})



猜你喜欢

转载自blog.csdn.net/qq_33269443/article/details/80837730