[微精通:網頁設計Vue + Node.js + MySQL] 5.2.MySQL套件 (上)

接下來,我們將API與資料庫整合在一起,好讓API可以永久的保存資料在資料庫中。此為上半部。

 

image/svg+xml5.2. MySQL 套件 var mysql = require ( ' mysql ' ); var express = require( 'express' ); var api = express(); api.use(express.static( 'html' )); function getConnection () { var connection = mysql . createConnection ( { host : '127.0.0.1' , user : 'root' , password : '1234' , database : 'ZombieDB' } ); return connection ; } function testConnection () { let connection = getConnection (); connection . connect (); console.log( ' 連線成功 ! ' ); connection . end (); console.log( ' 斷線 !' ); } testConnection (); // 略過⼀些程式 // 略過⼀些程式 api. post ( '/api/ getZombies ' , function (req, res) { var result = { data: null , error: null } ; let connection = getConnection (); connection. connect (); connection. query ( ' SELECT * FROM Zombie , function ( err , rs ) { if ( err ){ result. error = err.message ; } else { rs = rs.map (x => { x. isVegetarian = x.isVegetarian == 1 ? true : false return x; }); result. data = rs ; } res.send (JSON.stringify( result )); connection . end (); } ); } ); // 略過⼀些程式 api.listen( 80 , function () { console.log( 'Zombie api listening on port 80!' ); }); // 略過⼀些程式 api.post( '/api/ addZombie ' , express.text(), function (req, res) { var result = { data: null , error: null } ; try { let zombie = JSON.parse ( req.body ); if ( typeof zombie.name != 'string' || zombie.name.trim() == "" ){ result.error = " 請輸入名字且必須為字串。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.age != 'number' ){ result.error = " 請輸入變異年份且必須為數值。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.isVegetarian != 'boolean' ){ result.error = " 請輸入是否為素食者且必須為布林值。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.typeImgSrc != 'string' || [ 'z1.png' , 'z2.png' , 'z3.png' , ‘z4.png' , 'z5.png' ].indexOf(zombie.typeImgSrc) == - 1 ){ result.error = " 請輸入類型圖片,且值必須為 z1.png z2.png z3.png z4.png z5.png " ; res.send(JSON.stringify(result)); return ; } let isVegetarian = zombie . isVegetarian == true ? 1 : 0 ; let connection = getConnection (); connection. connect (); connection. query ( " INSERT INTO Zombie (name, age, isVegetarian, typeImgSrc) VALUES (?, ?, ?, ?) ;” , [ zombie . name , zombie . age , isVegetarian , zombie . typeImgSrc ] , function (err, rs) { if ( err ){ result. error = err.message ; } else { zombie . id = rs . insertID ; result. data = zombie ; } res.send (JSON.stringify( result )); connection . end (); } ); } catch (e){ result.error = e.toString(); res.send(JSON.stringify(result)); } }); // 略過⼀些程式 api.listen( 80 , function () { console.log( 'Zombie api listening on port 80!' ); }); // 略過⼀些程式 api.post( '/api/ updateZombie ' , express.text(), function (req, res) { var result = { data: null , error: null } ; try { let zombie = JSON.parse ( req.body ); if ( typeof zombie.id != 'number' ){ result.error = " 請輸入有效的 id " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.name != 'string' || zombie.name.trim() == "" ){ result.error = " 請輸入名字且必須為字串。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.age != 'number' ){ result.error = " 請輸入變異年份且必須為數值。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.isVegetarian != 'boolean' ){ result.error = " 請輸入是否為素食者且必須為布林值。 " ; res.send(JSON.stringify(result)); return ; } if ( typeof zombie.typeImgSrc != 'string' || [ 'z1.png' , 'z2.png' , 'z3.png' , 'z4.png' , 'z5.png' ].indexOf(zombie.typeImgSrc) == - 1 ){ result.error = " 請輸入類型圖片,且值必須為 z1.png z2.png z3.png z4.png z5.png " ; res.send(JSON.stringify(result)); return ; } let isVegetarian = zombie . isVegetarian == true ? 1 : 0 ; let connection = getConnection (); connection. connect (); connection. query ( " UPDATE Zombie SET name= ? , age= ? , isVegetarian= ? , typeImgSrc= ? WHERE id= ? ;" , [ zombie . name , zombie . age , isVegetarian , zombie . typeImgSrc , zombie . id ] , function (err, rs) { if ( err ){ result.error = err.message ; } else { if ( rs . affectedRows == 0 ){ result. error = 請輸入有效的 id ' ; } else { result. data = zombie ; } } res.send (JSON.stringify( result )); connection . end (); } ); } catch (e){ result.error = e.toString(); res.send(JSON.stringify(result)); } }); // 略過⼀些程式 api.listen( 80 , function () { console.log( 'Zombie api listening on port 80!' ); }); // 略過⼀些程式 api.post( '/api/ deleteZombie ' , express.text(), function (req, res) { var result = { data: null , error: null } ; try { let zombie = JSON.parse ( req.body ); if ( typeof zombie.id != 'number' ){ result.error = " 請輸入有效的 id " ; res.send(JSON.stringify(result)); return ; } let connection = getConnection (); connection. connect (); connection. query ( " DELETE FROM Zombie WHERE id= ? ;" , [ zombie . id ], function (err, rs) { if ( err ){ result. error = err.message ; } else { if ( rs . affectedRows == 0 ){ result. error = 請輸入有效的 id ' ; } else { result. data = { 'result' : ' ok ' } ; } } res.send (JSON.stringify( result )); connection . end (); } ); } catch (e){ result.error = e.toString(); res.send(JSON.stringify(result)); } }); api.listen( 80 , function () { console.log( 'Zombie api listening on port 80!' ); }); 有了 SQL ,但怎麼整合⾄殭屍 API ? 1. 有了 SQL ,但怎麼讓 API 以使⽤這些 SQL ? w5_2_1 1. npm install API 安裝 mysql 套件 w5_2_2 1. 切換到 node 套件的⽬錄,在此以 w5_2_2 為例。然後執 npm install mysql --save 安裝 mysql 套件。 2. createConnection() + connect() ,連線⾄殭屍資料庫 w5_2_3 - server.js 1. 引⽤ mysql 套件,並放⾄ mysql 變數中。 2. 寫⼀個取得連線的函式 getConnection() ,它會傳回連線物件。 3. 呼叫 createConnection() 函式取得連線物件, 並放在 connection 變數中保存。 4. 在物件上給定連線的資訊, host 為連線 的主機 127.0.0.1 user 為使⽤者帳號在此 root password 帳號的密碼,在此為 12345678 ,最後是連線後要使⽤的資料庫 database ,在此指定為 ZombieDB 5. 建立後回傳這個連線物件。 6. 寫⼀個測試連結的函式來測試連線。 7. 透過剛寫的 getConnection() 函式取得連線物件。 8. 呼叫連線物件上的 connect() ⽅法進⾏連線, 若成功則會往下執⾏印出 ' 連線成功 !' 9. 呼叫連線物件上的 end() ⽅法進⾏斷線, 成功後印出 斷線 !' 10. 呼叫 testConnection() 函式進⾏連線測試。 11. 執⾏ node server.js 。在過程中會呼呼 testConnection() 式來測試是否可成功連上 MySQL 上的 ZombieDB 資料庫。接著 Console 控制台會出現 連線成功 !’ 斷線 !' 的字樣,表⽰連線成功。 3. 整合 SQL ⾄殭屍 API 'R' 殭屍資料的讀取 w5_2_4 - server.js 1. 修改 API getZombies ,讓它從 MySQL 中取得殭屍資料。 2. 使⽤與過去相同的回傳的資料結構。 3. 呼叫 getConnection() 函式取得連結 物件,並呼叫 connect() ⽅法進⾏連線。 4. 接著呼叫連結物件上的 query() ⽅法將 SQL 指令發出。 5. 1 個參數為要發出的 sql ,在此使⽤ SELECT FROM 查詢 Zombie 資料表中的所有資料。 6. 2 個參數是執 sql 後執⾏的函 式,它有 2 個參數, err 為錯誤時的物件 參數, rs 為查詢的 結果物件。 7. 當有錯誤時則將錯誤的訊息 message 設定在回傳資料結構的 error 屬性中。 8. 若無錯誤,執⾏ else 11. 與過去相同,轉為 JSON 字串 後呼叫 send() ⽅法回傳。 12. 最後中斷與 MySQL 的連結。 4. 整合 SQL ⾄殭屍 API 'C' 殭屍資料的建立 w5_2_5 - server.js 9. rs 回傳的也是 JavaScript 的陣列與 物件,直接使⽤ JSON.stringify() 換成 JSON 字串回傳就⾏。但因 isVegetarian 是否為素食者欄位在資 料庫是 tinyint(1) ,存放 1 0 ,因此 使⽤ map 1 轉為 true 0 轉為 false 轉換完存回 rs 變數。 1. 修改 API addZombie ,讓它從 MySQL 中建立新的殭屍資料。 2. 使⽤與過去相同的回傳的資料結構。 3. 同樣透過請求 request 物件上的內容 body 取得上傳的 JSON ,⽽後透遛 JSON.parse() 法轉成 JavaScript 的物件。 4. 同樣不變,檢查上傳的資料。 5. 將上傳的是否為素食者 isVegetarian 從布林值 true/false 轉為 1/0 ,原因是資料庫中的 isVegetarian tinyint(1) 型別,只能存整數。 6. 呼叫 getConnection() 函式取得連結 物件,並呼叫 connect() ⽅法進⾏連線。 7. 接著呼叫連結物件上的 query() ⽅法將 SQL 指令發出。 8. 1 個參數為要發出的 sql ,在此使⽤ INSERT INTO 新增殭屍資料⾄ Zombie 資料表。 11. 3 個參數是執⾏ sql 後執⾏的函 式,它有 2 個參數, err 為錯誤時的物 件參數, rs 為查詢的結果物件。 12. 當有錯誤時則將錯誤的訊息 message 設定在回傳資料結構的 error 屬性中。 9. 不同的是 VALUES 後⽅的⼩括號 (()) 的是 4 個佔位符 (?) query() ⽅法會收第 2 個參數中陣列的值依序的放入這些佔位符 (?) 中,好組成出最後的 SQL 以執⾏。 10. 注意,這裡使⽤我們轉換為 1 0 isVegetarian 13. 若無錯誤,執⾏ else 14. 新增後回傳的物件有個 insertID 屬性,會得到資料庫在 Zombie 資料⾃ 動新增的 ID 編號,如同我們先前在 SQL 'SELECT LAST_INSERT_ID()’ 得的 id 。將這 id 值動態新增⾄ zombie 變數中的殭屍物件的 id 屬性上。 15. 設定 zombie 變數中的物件作為回傳的 data 10. 設定 rs 變數中存放殭屍物 件的陣列⾄回傳的 data 中。 11. 與過去相同,轉為 JSON 字串 後呼叫 send() ⽅法回傳。 12. 最後中斷與 MySQL 的連結。 5. 整合 SQL ⾄殭屍 API 'U' 殭屍資料的更新 w5_2_6 - server.js 新增資料後,最好是透過回傳的 id 在去資料庫中查最新的資料回傳。在此為 了簡化程式,直接以上傳的資料回傳。 1. 修改 API addZombie ,讓它從 MySQL 中建立新的殭屍資料。 2. 使⽤與過去相同的回傳的資料結構。 3. 同樣透過請求 request 物件上的內容 body 取得上傳的 JSON ,⽽後透遛 JSON.parse() 法轉成 JavaScript 的物件。 5. 其餘檢查維持不變。 4. 修改⼀下對上傳 id 屬性值的檢查,只檢查 是否為數值,不檢查是否存在於資料庫中。 6. 將上傳的是否為素食者 isVegetarian 從布林值 true/false 轉為 1/0 ,原因是資料庫中的 isVegetarian tinyint(1) 型別,只能存整數。 7. 呼叫 getConnection() 函式取得連結 物件,並呼叫 connect() ⽅法進⾏連線。 8. 接著呼叫連結物件上的 query() ⽅法將 SQL 指令發出。 9. 1 個參數為要發出的 sql ,在此使⽤ UPDATE 新殭屍資料⾄ Zombie 資料表。 10. 在此同樣使⽤佔位符 (?) 依照第 2 參數中陣列的值進⾏取代。第 5 個佔位符 id=? ,是為了依照 id 值找到特定的殭屍 資料進⾏更新。 11. 3 個參數是執⾏ sql 後執⾏的函 式,它有 2 個參數, err 為錯誤時的物 件參數, rs 為查詢的結果物件。 12. 當有錯誤時則將錯誤的訊息 message 設定在回傳資料結構的 error 屬性中。 13. 若無錯誤,執⾏ else 14. 在此特別的是, affectedRows 屬性表⽰是指 令影響的筆數,若影響的筆數 0 表⽰找不到這筆資料更新, 因此就回傳錯誤資料。 15. affectedRows 屬性不 0 ,表⽰成功,這時則將更新 的殭屍物件存於 data 回傳。 16. 與過去相同,轉為 JSON 字串 後呼叫 send() ⽅法回傳。 17. 最後中斷與 MySQL 的連結。 6. 整合 SQL ⾄殭屍 API 'D' 殭屍資料的刪除 w5_2_7 - server.js 同樣的,更新資料後,也應再次查詢資料庫取得最新的資料後回傳。在此為 了簡化程式,直接以上傳的資料回傳。 1. 修改 API addZombie ,讓它從 MySQL 中建立新的殭屍資料。 2. 使⽤與過去相同的回傳的資料結構。 3. 同樣透過請求 request 物件上的內容 body 取得上傳的 JSON ,⽽後透遛 JSON.parse() 法轉成 JavaScript 的物件。 4. 修改⼀下對上傳 id 屬性值的檢查,只檢查 是否為數值,不檢查是否存在於資料庫中。 5. 呼叫 getConnection() 函式取得連結 物件,並呼叫 connect() ⽅法進⾏連線。 6. 接著呼叫連結物件上的 query() ⽅法將 SQL 指令發出。 7. 1 個參數為要發出的 sql ,在 此使⽤ DELETE 刪除殭屍資料。 8. 同樣使⽤佔位符 (?) ,將 id 帶入 ? 中,以 透過 WHERE 刪除特定 id 的殭屍資料。 9. 3 個參數是執⾏ sql 後執⾏的函 式,它有 2 個參數, err 為錯誤時的物 件參數, rs 為查詢的結果物件。 10. 當有錯誤時則將錯誤的訊息 message 設定在回傳資料結構的 error 屬性中。 11. 若無錯誤,執⾏ else 12. 同樣的, affectedRows 性表⽰是指令影響的筆數,若影 響的筆數為 0 表⽰找不到這筆資料 更新,因此就回傳錯誤資料。 13. affectedRows 屬性不為 0 ,表⽰成功,為了範例簡化,這 邊改為回傳⼀個 ok 狀態的物件 data 中以表⽰刪除成功,不再回 傳刪除的殭屍物件。 14. 與過去相同,轉為 JSON 字串 後呼叫 send() ⽅法回傳。 17. 最後中斷與 MySQL 的連結。

留言