摘要:數(shù)據(jù)庫的命名應(yīng)該遵守操作系統(tǒng)的文件命名規(guī)范。使用命令檢查當(dāng)前選定的數(shù)據(jù)庫。假如,第一個(gè)是,每頁條,所以當(dāng)前頁的查詢語句數(shù)據(jù)總數(shù)在中,找尋數(shù)據(jù)總數(shù)獲得總數(shù)需要向上取整。常用于版本校驗(yàn)。建立索引表示的是正向。損失的插入的時(shí)間。
基本使用 概念
SQL和NoSQL
文檔 Document
文檔就是鍵值對(duì)的一個(gè)集合,實(shí)際上表達(dá)方式和JSON一樣
文檔就是JSON,但是要比JSON多了一些限制:
每個(gè)文檔必須有一個(gè)特殊的鍵 _id, 這個(gè)鍵在集合中必須是保證唯一性.
文檔中鍵的命名,不能含有.和$
文檔中值的額類型,比原生JavaScript更多, 比如:日期,ObjectId(),正則表達(dá)式
文檔是給用戶看的,是JSON的表示模式,但實(shí)際存儲(chǔ)的時(shí)候,是BSON方式(用二進(jìn)制方式存儲(chǔ))
集合 Collections
集合就是一組文檔(document),相當(dāng)于“表”
集合中可以存儲(chǔ)完全不同的結(jié)構(gòu)的文檔
數(shù)據(jù)庫 DataBase
數(shù)據(jù)庫中存儲(chǔ)眾多的集合
數(shù)據(jù)庫最終會(huì)變成文件系統(tǒng)里的文件,而數(shù)據(jù)庫名字就是相應(yīng)的文件名。數(shù)據(jù)庫的命名應(yīng)該遵守操作系統(tǒng)的文件命名規(guī)范。
數(shù)據(jù)庫命名不能是admin,local,config
mongodmongo 使用數(shù)據(jù)庫
mongod 開機(jī)
mongoimport 導(dǎo)入數(shù)據(jù)
mongod --dbpath c:mongodata // --dbpath 參數(shù),表示數(shù)據(jù)庫的存放位置,文件夾必須事先創(chuàng)建 // mongoDB 有真實(shí)的物理文件,對(duì)應(yīng)一個(gè)個(gè)數(shù)據(jù)庫。
db.help(); // 在 mongodb 客戶端中獲得幫助
db.stats(); 顯示數(shù)據(jù)庫名稱、集合數(shù)目,以及數(shù)據(jù)庫中的文檔
MongoDB數(shù)據(jù)模型MongoDB 中的數(shù)據(jù)模式非常靈活。同一集合中的文檔不需要具有同一字段或結(jié)構(gòu),集合文檔的公用字段可能包含不同類型的數(shù)據(jù)。
設(shè)計(jì) MongoDB 模式注意問題根據(jù)用戶需求來設(shè)計(jì)模式。
如果想一起使用對(duì)象,請(qǐng)將這些對(duì)象合并到一個(gè)文檔中,否則要將它們分開(但是要確保不需要連接)。
經(jīng)常復(fù)制數(shù)據(jù)(但要有一定限度),因?yàn)榕c計(jì)算時(shí)間相比,硬盤空間顯得非常便宜。
在寫入時(shí)進(jìn)行連接,而不能在讀取時(shí)連接。
針對(duì)經(jīng)常發(fā)生的用例來設(shè)計(jì)模式。
在模式中實(shí)現(xiàn)復(fù)雜的聚合。
數(shù)據(jù)庫中存儲(chǔ)眾多集合。
數(shù)據(jù)庫最終會(huì)變?yōu)槲募到y(tǒng)里面的文件,而數(shù)據(jù)庫名字就是相應(yīng)的文件名,所以數(shù)據(jù)庫的命名,應(yīng)該遵守操作系統(tǒng)的文件名命名規(guī)范。
數(shù)據(jù)庫命名不能是admin、local、config
基本命令行操作列出所有數(shù)據(jù)庫
show dbs;
使用某個(gè)數(shù)據(jù)庫
use students; // 如果想新建,也是use, use一個(gè)不存在的庫名,就是創(chuàng)建一個(gè)數(shù)據(jù)庫。
查看當(dāng)前所在庫
db
集合沒有查看,需要插入數(shù)據(jù)之后,能夠看到。 如果真的想創(chuàng)建剛才未存在的數(shù)據(jù)庫,那么必須插入一個(gè)數(shù)據(jù)。不需要?jiǎng)?chuàng)建集合。
例如:
db.student.insert({"name": "xiaoming", "age": 23}); //student就是所謂的集合(collections)。集合中存儲(chǔ)著很多json(document)。 //db. 一個(gè)未知的集合名字,這個(gè)集合將自動(dòng)創(chuàng)建。mongodb增刪改查 創(chuàng)建數(shù)據(jù)庫
用 use + 數(shù)據(jù)庫名稱 的方式來創(chuàng)建數(shù)據(jù)庫。use 會(huì)創(chuàng)建一個(gè)新的數(shù)據(jù)庫,如果該數(shù)據(jù)庫存在,則返回這個(gè)數(shù)據(jù)庫。
use mydb
使用命令 db 檢查當(dāng)前選定的數(shù)據(jù)庫。
db
使用命令 show dbs 來檢查數(shù)據(jù)庫列表。
show dbs
剛創(chuàng)建的數(shù)據(jù)庫(mydb)沒有出現(xiàn)在列表中。為了讓數(shù)據(jù)庫顯示出來,至少應(yīng)該插入一個(gè)文檔。
刪除數(shù)據(jù)庫db.dropDatabase(); // 刪除當(dāng)前所在的數(shù)據(jù)庫導(dǎo)入外部數(shù)據(jù)
mongoimport --db test --collection restaurants --dorp --file ffffd.json // --db test 想往那個(gè)數(shù)據(jù)庫中導(dǎo)入 // --collection restaurants 想往那個(gè)集合中導(dǎo)入 // --dorp 把集合清空 表示數(shù)據(jù)庫中有默認(rèn)數(shù)據(jù),覆蓋原有數(shù)據(jù)。 // --file ffffd.json 使用的是哪個(gè)文件. mongoimport --db student --collection class1 --dorp --file a.json創(chuàng)建集合(表)
db.class1 //如果集合不存在,幫你創(chuàng)建集合
使用 show collections 來查看創(chuàng)建了的集合。
show collections // 沒有數(shù)據(jù),剛創(chuàng)建的 集合 并不顯示出來。插入數(shù)據(jù)
db.class1.insert({"name": "ting","age": 21});查看數(shù)據(jù)(文檔)
db.class1.find({}); //db.class1.find(); //find() 方法會(huì)以非結(jié)構(gòu)化的方式來顯示所有文檔。 db.class1.find().pretty(); //用格式化方式顯示結(jié)果 //在 find() 方法中,如果傳入多個(gè)鍵,并用逗號(hào)(,)分隔它們,那么 MongoDB 會(huì)把它看成是 AND 條件。 db.class1.find({"key1": "val1", "key2": "val2"}); //若基于 OR 條件來查詢文檔,可以使用關(guān)鍵字 $or。 //或 的條件 db.class1.find({$or: [{key1: val1, key2: val2}]});排序
db.class.find().sort({"sex": 1}); //1 升序修改數(shù)據(jù)
// update暗含查找,修改誰,修改結(jié)果 update默認(rèn)只會(huì)修改第一個(gè)document,需要第三個(gè)參數(shù)支持: {"multi": true} db.class1.update({"name": "xiaoming"},{$set: {"age": 16}}); // 批量修改 db.class1.update({"score.math": "60"},{$set: {"age": 20}}, {"multi": true}); db.class1.update({},{$set: {"age": 20}},{"multi": true}); //第一個(gè)參數(shù)為空,表示全部數(shù)據(jù)修改。 // 替換document, 沒有使用$set關(guān)鍵字,完整替換 db.class1.uodate({"name": "xiaoming"},{"age": 12});刪除數(shù)據(jù)
db.student1.drop(); // 刪除集合 (籃子都刪除) db.studnet1.remove({}) //刪除全部 (籃子還存在) db.student1.remove({"score.math": 80}); //會(huì)刪除全部匹配得到的 db.student1.remove({"score.math": 80},{justOne: true}); //刪除匹配的第一個(gè)nodeJs 使用 mongodb
// 安裝 mongodb npm install mongodbnodejs 操作 mongodb
// mongo db 驅(qū)動(dòng) va r MongoClient = require("mongodb").MongoClient; //數(shù)據(jù)庫的地址 /student 表示數(shù)據(jù)庫 // 假如數(shù)據(jù)庫不存在,沒有關(guān)系,程序會(huì)自動(dòng)創(chuàng)建數(shù)據(jù)庫 var url = "mongodb://localhsot:27017/student"; // 建立連接 MongoClient.connect(url,function( err,db ){ // db 參數(shù)就是連接上數(shù)據(jù)庫 實(shí)體 所有數(shù)據(jù)庫操作都建立在 實(shí)體上。 if( err ){ console.log("數(shù)據(jù)庫連接失敗"); return ; } console.log("數(shù)據(jù)庫成功連接"); db.collection("student").insertOne({ "name": "mlln", "age": 23 },function( err,result ){ if (err) { console.log("插入失敗"); return ; } console.log(result); res.send("1"); db.close(); }); }); // cmd 中查看數(shù)據(jù) 比較多 可以使用 it 查看下一頁插入數(shù)據(jù)
db.collection("class1").isnertOne({"name": "xiaoming", "age": 21},function( err,result ){ if( err ) console.log("數(shù)據(jù)插入失敗"); console.log("數(shù)據(jù)插入成功"); });查詢數(shù)據(jù)
var cousor = db.collection("class1").find({}); // find({}) //可以輸出查詢條件。find({"score.math": 70}); // 遍歷游標(biāo) cousor.each(function( err,doc ){ if( doc != null ){ console.log(doc); // 輸出每條記錄 } }); var cursor = db.collection("class1").find({"score.math": {$gt: 30}}); var cursor = db.collection("class1").find({ "score.math": {$gt: 20} , "score.cha": {$lt : 70}}); var cursor = db.collection("class1").find({ $or: [ {"score.math": {$gt: 50}}, {"scror.cha": {$lt: 70}} ] }); // 排序 // 1 正序 , -1 反序 var cursor = db.collection("class1").find({}).sort({"score.math": 1});更新
覆蓋匹配的記錄 //updateOne();
db.collection("class1").updateOne({"name": "mm"}, {"age": 23},function( err,result ){ if( err ) console.log("修改失敗"); console.log("修改成功"); });
修改字段中的值
db.collection.("class1").updateOne({"name": "mlln"}, { $set: {"age": 24} }, function( err,result ){ if ( err ) console.log("修改失敗"); console.log("修改成功"); });
替換記錄 //replaceOne();
db.collection("class1").replaceOne({"name": "mlln"}, {"name": "m1", "age": 20});刪除數(shù)據(jù)
db.collection("class1").deleteMany({"age",25},function( err,reslut ){ if( err ) console.log("刪除失敗"); console.log("數(shù)據(jù)刪除成功"); });DAO層封裝
mongooose 對(duì)象與數(shù)據(jù)對(duì)應(yīng),產(chǎn)生ODM思想 , 一個(gè)對(duì)象new出來之后,數(shù)據(jù)庫中就存在。
// db模塊封裝了所有對(duì)數(shù)據(jù)庫的常用操作 var MongoClient = require("mongodb").MongoClient; var setting = require("../settings"); // 連接數(shù)據(jù)庫 function _connectDB(callback) { var url = setting.dburl; // 配置文件中讀取 MongoClient.connect(url, function (err, db) { callback(err, db); }); } // 插入數(shù)據(jù) // 往那個(gè)集合中增加,增加什么,增加之后的事情。 exports.insertOne = function (collectionName, json, callback) { _connectDB(function (err, db) { if (err) { callback(err, null); db.close(); // 關(guān)閉數(shù)據(jù)庫 return; } db.collection(collectionName).insertOne(json, function (err, result) { callback(err, result); db.close(); // 關(guān)閉數(shù)據(jù)庫 }); }); }; // 查找數(shù)據(jù) // 在那個(gè)集合查找,查什么,分頁設(shè)置,查完之后做什么 exports.find = function (collectionName, json, args, callback) { if (arguments.length == 3) { callback = args; args = { "pageamount": 0, "page": 0 } } else if (arguments.length == 4) { } else { throw new Error("find參數(shù)是3個(gè)或者四個(gè)"); } var result = []; // 應(yīng)該省略的條數(shù) var skipNum = args.pageamount * args.page; // 數(shù)目限制 var limitNum = args.pageamount; _connectDB(function (err, db) { var cursor = db.collection(collectionName).find(json).skip(skipNum).limit(limitNum); cursor.each(function (err, doc) { // each 遍歷的時(shí)候存在問題,callback 匹配到一條,就執(zhí)行一次, // callback 意義上是只執(zhí)行一次,使用數(shù)組解決 if (err) { callback(err, null); db.close(); // 關(guān)閉數(shù)據(jù)庫 return; } if (doc != null) { result.push(doc); //放入結(jié)果數(shù)組 } else { // 遍歷結(jié)束,沒有更多文檔 callback(null, result); db.close(); // 關(guān)閉數(shù)據(jù)庫 } }); }); }; // 刪除 exports.deleteMany = function (collectionName, json, callback) { _connectDB(function (err, db) { db.collection(collectionName).deleteMany(json, function (err, result) { callback(err, result); db.close(); // 關(guān)閉數(shù)據(jù)庫 }); }); }; // 修改 exports.updateMany = function (collectionName, json1, json2, callback) { _connectDB(function (err, db) { if (err) { callback(err, null); return false; } db.collection(collectionName).updateMany(json1, json2, function (err, result) { callback(err, result); db.close(); }); }); };mongoDB分頁
// limit() 表示讀取的條數(shù) // skip() 表示略過的條數(shù)
limit和skip配合使用就是分頁查詢。
假如,第一個(gè)是page=0,每頁10條,所以當(dāng)前頁的查詢語句
db.student.find().limit(10).skip(page*10);
數(shù)據(jù)總數(shù)
在shell中,找尋數(shù)據(jù)總數(shù)
db.student.stats().count; // 獲得collections總數(shù) // 需要向上取整。 db.student.find().count(); // find() ,有分頁邏輯 exports.find = function( collectionName,json,args,callback ){ if ( arguments.length == 3 ) { callback = args; args = {"pageamount": 0, "page": 0} } else if ( arguments.length == 4 ) { } else { throw new Error("find參數(shù)是3個(gè)或者四個(gè)"); return false; } // 應(yīng)該省略的條數(shù) var skipNum = args.pageamount * args.page; //數(shù)目限制 var limitNum = args.pageamount; _connectDB(function ( err,db ) { var cursor = db.collection(collectionName).find(json).skip(skipNum).limit(limitNum); cursor.each(function ( err,doc ) { // each 遍歷的時(shí)候存在問題,callback 匹配到一條,就執(zhí)行一次, // callback 意義上是只執(zhí)行一次,使用數(shù)組解決 if ( err ) { callback(err,null); return ; } if ( doc != null ) { result.push( doc ); //放入結(jié)果數(shù)組 } else { //遍歷結(jié)束,沒有更多文檔 callback(null,result); } }); }); };cookie & session cookie
需要cookie-parser中間件支持
HTTP是無狀態(tài)協(xié)議。簡(jiǎn)單地說,當(dāng)你瀏覽了一個(gè)頁面,然后轉(zhuǎn)到同一個(gè)網(wǎng)站的另一個(gè)頁面,服務(wù)器無法認(rèn)識(shí)到,這是同一個(gè)瀏覽器在訪問同一個(gè)網(wǎng)站。每一次的訪問,都是沒有任何關(guān)系的。
Cookie是一個(gè)簡(jiǎn)單到爆的想法:當(dāng)訪問一個(gè)頁面的時(shí)候,服務(wù)器在下行HTTP報(bào)文中,命令瀏覽器存儲(chǔ)一個(gè)字符串;瀏覽器再訪問同一個(gè)域的時(shí)候,將把這個(gè)字符串?dāng)y帶到上行HTTP請(qǐng)求中。
第一次訪問一個(gè)服務(wù)器,不可能攜帶cookie。 必須是服務(wù)器得到這次請(qǐng)求,在下行響應(yīng)報(bào)頭中,攜帶cookie信息,此后每一次瀏覽器往這個(gè)服務(wù)器發(fā)出的請(qǐng)求,都會(huì)攜帶這個(gè)cookie。
特點(diǎn)
cookie是不加密的,用戶可以自由看到;
用戶可以刪除cookie,或者禁用它
cookie可以被篡改
cookie可以用于攻擊
cookie存儲(chǔ)量很小。未來實(shí)際上要被localStorage替代,但是后者IE9兼容。
作用:
記錄用戶的信息,購買習(xí)慣,猜你喜歡。
express中的cookie, res負(fù)責(zé)設(shè)置cookie, req負(fù)責(zé)識(shí)別cookie。
cookie是沒有跨域限制
cookie使用
var express = require("express"); var cookieParser = require("cookie-parser"); var app = express(); app.use(cookieParser()); app.get("/",function ( req,res ) { // maxAge 在express 是以毫秒為單位 res.cookie("xihao","tfboys",{ "maxAge": 9000, httpOnly: true }); res.send(req.cookies); }); app.listen(80);猜你喜歡
頁面中獲取原先的值,push到數(shù)組中,然后再次設(shè)置回來。供首頁訪問。
var express = require("express"); var cookieParser = require("cookie-parser"); var app = express(); app.use(cookieParser()); app.get("/",function ( req,res ) { // maxAge 在express 是以毫秒為單位 res.send("猜你喜歡" + req.cookies.mudidi ); }); app.get("/gonglve",function ( req,res ) { var mudidi = req.query.mudidi; //記錄用戶的喜好 //讀取用戶的喜好,然后把新的數(shù)據(jù)push設(shè)置新的數(shù)據(jù) var mudidiArr = req.cookies.mudidi || []; mudidiArr.push( mudidi ); res.cookie("mudidi",mudidiArr,{ "maxAge": 9000, httpOnly: true }); res.send(mudidi + "旅游攻略"); }); app.listen(80);session
需要express-session中間件支持
會(huì)話,session并不是天生的就有的技術(shù),而是依賴cookie。
用于登陸。當(dāng)一個(gè)瀏覽器禁用cookie的時(shí)候,登陸效果消失,或者用戶清除了cookie,登陸也消失。
session比cookie不一樣的地方,session下發(fā)的是亂碼,并且服務(wù)器自己緩存一些東西。下次瀏覽器的請(qǐng)求,帶著亂碼上來。此時(shí)與緩存(緩存是存在服務(wù)器內(nèi)存中,一旦服務(wù)器關(guān)了,緩存就消失)進(jìn)行比較,看看匹配的是哪一個(gè)。
所以,一個(gè)亂碼,可以對(duì)應(yīng)無限大的數(shù)據(jù)。(理論上),但是受內(nèi)存限制。
任何語言中,session的使用,是“機(jī)理透明”的,它幫你設(shè)置cookie的.
var express = require("express"); var app = express(); var session = require("express-session"); app.use(session({ secret: "keyboard cat", resave: false, saveUninitialized: true, cookie: { secure: true } })); app.get("/",function( req,res ){ if ( req.session.login == "1" ) { res.send( "歡迎"+ req.session.username +"的登陸" ); } else { res.send("沒有成功登陸"); } }); app.get("/login",function ( req,res ) { req.session.login = "1"; req.session.username = "mlln"; res.send("你已經(jīng)成功登陸"); }); app.listen(80)加密
md5 加密 是函數(shù)型加密。每次加密的結(jié)果相同,沒有隨機(jī)位 //永遠(yuǎn)不要用明文寫密碼。
特點(diǎn):
不管加密的文字,多長(zhǎng)多短,永遠(yuǎn)都是32位英語字母、數(shù)字混合。
那怕只改一個(gè)字,密文都會(huì)大變。
MD5沒有反函數(shù)的可能。 網(wǎng)上的破解工具,都是字典模式,通過列出明-密對(duì)應(yīng)的字典找到明碼。
MD5常用于版本校驗(yàn)。可以比對(duì)兩個(gè)文件、軟件是否完全一致。
node中,自帶了一個(gè)模塊 crypto模塊,負(fù)責(zé)加密。
//創(chuàng)建hash var md5 = crypto.createHash("md5"); //創(chuàng)建一個(gè)hash對(duì)應(yīng) //然后update 和 digest var password = md5.update(fields.password).digest("base64");
console.log( md52( md52("123123").slice(11,7) + md52("123123") ) ); function md52( mingma ) { var md5 = crypto.createHash("md5"); var password = md5.update(mingma).digest("base64"); return password; }GM圖像 gm軟件
只要服務(wù)器需要處理圖片,那么這個(gè)服務(wù)器就需要安裝graphicsmagick軟件 , 還有其它的圖像處理軟件。ImageMagick 。
GM軟件API
GM-API
nodejs 使用graphicsmagick。需要第三方npm的gm包
GM包運(yùn)行環(huán)境 鏈接描述
var fs = require("fs"); var gm = require("gm"); gm("./axin.jpg") .resize(50, 50,"!") .write("./axin.jpg", function (err) { if (err) { console.log(err); } });nodejs頭像裁切
gm("./axin.jpg").crop(141,96,152,181).write("./2.jpg",function(err){ //141 96 是寬高 。 152 181是坐標(biāo) });索引
index
數(shù)據(jù)庫中,根據(jù)一個(gè)字段的值,來尋找一個(gè)文檔,是很常見的操作。
查看檢索的過程
db.student.find({"name": "username33"}).explain(); // 過程顯示 { "cursor" : "BasicCursor", "isMultiKey" : false, "n" : 2, "nscannedObjects" : 19999, "nscanned" : 19999, "nscannedObjectsAllPlans" : 19999, "nscannedAllPlans" : 19999, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 16, "indexBounds" : { }, "server" : "YOS-01409231922:27017" }
為了快速進(jìn)行檢索,可以把唯一字段,建立成"索引".
每個(gè)collection是已經(jīng)有一個(gè)索引(默認(rèn)索引_id),再創(chuàng)建另外索引會(huì)具備兩條索引。
建立索引:
db.student.createIndex({ "name": 1 }); // 1 表示的是正向。
索引的優(yōu)缺點(diǎn):
好處:通過索引查詢的速度會(huì)更快,因?yàn)榭梢詮乃饕碇姓业?,?dāng)前個(gè)文檔。
壞處:當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)不存在的時(shí)候,已經(jīng)建立的索引會(huì)存在。以后插入的數(shù)據(jù)會(huì)變慢。 損失的插入的時(shí)間。得到的是查詢的時(shí)間。
復(fù)合索引
db.student.createIndex({ "name": 1, "address": -1 }); // 1 表示的是正向。 -1 表示負(fù)向
先以第一個(gè)條件排序,然后相同的時(shí)候以第二個(gè)條件再進(jìn)行排序。(插入數(shù)據(jù)之前是一條默認(rèn)的索引,索引建立之后是3條索引)
db.student.createIndex({ "name": 1 }, {unique: true}); // unique 所有的collection都不能相同,如果相同會(huì)報(bào)錯(cuò)。
適用范圍:網(wǎng)站并沒有大量插入的操作。(例如:同一時(shí)段并沒有大量的人在注冊(cè))
DAO層中添加init函數(shù)使用索引:
function init() { // 對(duì)數(shù)據(jù)庫進(jìn)行一個(gè)初始化 _connectDB(function (err, db) { if (err) { console.log(err); return; } // 建立索引 db.collection("users").createIndex( { "username": 1 }, null, function (err, results) { if (err) { console.log(err); return; } console.log("索引建立成功"); } ); }); }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86335.html
摘要:數(shù)據(jù)庫的命名應(yīng)該遵守操作系統(tǒng)的文件命名規(guī)范。使用命令檢查當(dāng)前選定的數(shù)據(jù)庫。假如,第一個(gè)是,每頁條,所以當(dāng)前頁的查詢語句數(shù)據(jù)總數(shù)在中,找尋數(shù)據(jù)總數(shù)獲得總數(shù)需要向上取整。常用于版本校驗(yàn)。建立索引表示的是正向。損失的插入的時(shí)間。 基本使用 概念 SQL和NoSQL showImg(https://segmentfault.com/img/bVzh2M?w=582&h=469); 文檔 Doc...
閱讀 1432·2021-11-09 09:45
閱讀 1797·2021-11-04 16:09
閱讀 1460·2021-10-14 09:43
閱讀 1829·2021-09-22 15:24
閱讀 1612·2021-09-07 10:06
閱讀 1605·2019-08-30 14:15
閱讀 993·2019-08-30 12:56
閱讀 1573·2019-08-29 17:22