# [2] 快速學會 node.js 基礎入門

### 0. 說明

本篇將完整說明如何使用 node.js 建立一個簡單的 web，也介紹如何對 mysql 的資料庫操作。

本篇文章是一個步驟指導，建議可以搭配影片一起學習：

%[https://youtu.be/Rlj0xVAEoxk]

### 1. 安裝 node.js

安裝最新版：
```
$ sudo apt-get install curl
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
```

開始安裝：
```
$ sudo apt-get install nodejs
```

檢查版本：
```
$ node -v
v14.15.4
```

### 2. 建立專案

建立資料夾：
```
% mkdir test_node
% cd test_node
```

進入資料夾後，進行初始化的動作：

```
% npm init
```

接下來會進行一連串的詢問：
```
Press ^C at any time to quit.
package name: (test_node) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/jake/Desktop/test_node/package.json:
{
  "name": "test_node",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this OK? (yes) 
```
按下 OK，專案就建立好了。

### 3. 第一次執行 node

用 Visual Studio Code 開啟專案資料夾

建立 index.js 檔案：
```
console.log('Hello');
```

開啟 terminal 視窗，用 node 執行 index.js：
```
% node index.js
```

會印出：
```
Hello
```

### 3-1. 安裝 nodemon

安裝 nodemon：
```
% npm install -g nodemon
```

修改 package.json，新增：
```
"scripts": {
    "dev": "nodemon index.js"
},
```

執行：
```
% npm run dev
```

如此一來，只要修改程式碼儲存後，就會自動重新啟動 Node

### 4. Web 框架

node.js 的 web 框架有很多種，這邊介紹最受歡迎的 express 框架來製作 web

安裝 express：
```
% npm install express --save
```

修改 index.js：
```
const express = require("express");
const app = express();
const port = 3000;

app.get('/', (req, res) => {
    res.send(' Hello World!');
});

app.listen(port, () => {
    console.log(`Listening at http://localhost:${port}`);
});
```

在瀏覽起開啟：http://localhost:3000/ ，會顯示 Hello World! 字串

程式碼解說：
```
const express = require("express"); //載入 express 模組
const app = express(); //初始化 express
const port = 3000; //web port 設定 3000

/*
網址為 / 時，方法設定為 GET
*/
app.get('/', (req, res) => {
    res.send('Hello World!'); //印出 Hello World!
});

/*
開啟 web
*/
app.listen(port, () => {
    console.log(`Listening at http://localhost:${port}`);
});
```

### 5. EJS 框架

程式與資料如何跟 HTML 標籤做互動，這邊會使用 EJS 框架

安裝 EJS 框架：
```
$ npm install ejs --self
```

使用 EJS
在專案內新增一個資料夾 views
在 views 資料夾內新增一個檔案 index.ejs：
```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>Hello EJS</h1>
</body>

</html>
```

修改 index.js：
```
const express = require("express");
const app = express();
const port = 3000;

app.set('view engine', 'ejs'); // 設定 view 的框架為 EJS

app.get('/', (req, res) => {
    res.render("index"); // 將結果傳入給 index.ejs
});

app.listen(port, () => {
    console.log(`Listening at http://localhost:${port}`);
});
```

接下來要從 index.js 傳出資料給 index.ejs

修改 index.ejs，設定變數名稱：
```html
<h1>Hello <%=name%></h1>
```

EJS 用 <%%> 語法來表示，name 則表示設定了一個名為 name 的變數，而等號表示直接呈現出來。

修改 index.js：
```
app.get('/', (req, res) => {
    res.render("index", {
        name: "Jake" //表示出數一個變數叫 name，然後給予內容為 "Jake"
    });
});
```

EJS 的變數呈現也可以這樣寫：
```
<%-name%>
```

傳出陣列給 EJS
如果要傳出多個資料給 EJS，可以使用陣列的方式傳出，修改 index.js：
```
app.get('/', (req, res) => {
  res.render("index", {
      name: "Jake",
      names: ["Jake", "John", "David"]
  });
})
```

然後接著在 index.ejs 新增：
```html
<% for(var i = 0; i < names.length; i++) { %>
    <h1>
        Hello <%- names[i] %>
    </h1>
<% } %>
```

任何 EJS 語法都寫在 <% ... %> 範圍之內，所以在這邊使用一個 for 迴圈去走訪 names 這個陣列。

### 6. 模組化架構

學習如何將程式架構模組化

目前的程式碼會將所有邏輯寫在 index.js：
```
app.get('/', (req, res) => {
    res.render("index", {
        name: "Jake",
        names: ["Jake", "John", "David"]
    });
});
```

但網頁的邏輯不是只有輸出資料給 EJS，還有資料的輸入、資料庫的使用或者其他判斷，所以將所有邏輯寫在這邊是不智之舉，在這邊就要介紹模組化架構，使用 exports 方式來實作。

新增一個 main.js：
```
exports.showMain = function showMain(req, res) {
    res.render("index", {
        name: "Jake",
        names: ["Jake", "John", "David"]
    });
};
```

這邊使用 exports 把 showMain 這個 function 給輸出出去。

然後就可以在 index.js 把 main.js 給 require 進來：
```
const main = require("./main.js");
```

然後就可以去呼叫 main.js 裡面所 exports 出來的函式了：
```
app.get('/', (req, res) => {
    main.showMain(req, res);
});
```

### 7. 使用 body-parser

body-parser 主要可以處理 http request 的資料解析，body-parser 已經被納入 Express 的框架裡，所以只要

定義好要解析哪幾種格式即可，修改 index.js：
```
// 解析 application/x-www-form-urlencoded
app.use(express.urlencoded({
    extended: false,
}));

// 解析 application/json
app.use(express.json());
```

接下來就可以透過 GET 或者 POST 的方法將資料送給 server

如果是 GET 的方法，取值的方式：
```
const name = req.query.name;
```

如果是 POST 的方法，取值的方式：
```
const name = req.body.name;
```

GET 範例
index.js：
```
app.get('/', (req, res) => {
    main.showMain(req, res);
});
```

main.js：
```
exports.showMain = function showMain(req, res) {
    const name = req.query.name;

    res.render("index", {
        name: name
    });
};
```

POST 範例
index.js：
```
app.post('/', (req, res) => {
    main.showMain(req, res);
});
```

main.js：
```
exports.showMain = function showMain(req, res) {
    const name = req.body.name;

    res.render("index", {
        name: name
    });
};
```

### 8. 安裝 Docker

之前篇幅主要是對 node.js 的基礎操作有一個了解，接下來就會針對 mysql 的操作做說明，這邊會使用 Docker 來建立本機端的資料庫

先到官方網站下載：@[https://docs.docker.com/desktop/mac/install/]

### 9 .安裝 Docker: mysql

安裝好 Docker，就可以利用指令來做安裝，首先先安裝 mysql

下載 mysql：
```
% docker pull mysql 
```

開啟 mysql 的指令為：
docker run --name <自定義容器名字> -e MYSQL_ROOT_PASSWORD=<設定資料庫密碼> -d -p <local的port>:<容器的port> mysql:latest
```
% docker run --name mysql1 -e MYSQL_ROOT_PASSWORD=123456 -d -p 3306:3306 mysql:latest
```

登入 mysql 容器：
```
% docker exec -it mysql1 bash
```

登入 mysql：
```
# mysql -u root -p
```

接著輸入剛剛設定的 mysql 密碼，即可以登入 

設定可以讓外部程式登入：

```
ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;
```

### 10. 安裝 Docker: phpmyadmin

phpmyadmin 是一個 web 的 mysql 操作工具

直接執行安裝：
```
% docker run --name myadmin -d --link mysql1:db -p 9100:80 phpmyadmin
```

在瀏覽器打上：http://127.0.0.1:9100/即可開啟

### 11. 開啟資料庫

接下來就可以在 node.js 上來操作 mysql 了

先安裝 mysql 的 node 模組：
```
% npm install mysql --self
```

接下來修改 index.js

將 mysql 匯入進來：
```
const mysql = require("mysql");
```

設定連線到 mysql 的 ip、帳號、密碼、資料庫名稱
```
const pool = mysql.createPool({
    name: "test",
    host: 'x.x.x.x',       // 連線 ip
    user: 'root',          // 連線帳號
    password: 'xxxxxxxx',  // 連線密碼
    database: 'demo'  .    // 資料庫名稱
});
```

開啟資料庫連線：
```
pool.getConnection(function (err, connection) {
    if (err) { // 發生錯誤時的處理
        console.log(err);
        return;
    }
});
```

進行 sql 指令查詢：
```
const sql = "SELECT * FROM device";
connection.query(sql, function (errorQuery, rows) {
    connection.release(); // 查詢完之後，因為不會再連到資料庫，所以進行關閉連線

    if (errorQuery) {
        console.log('Error SELECT to Db: ', errorQuery);
        return;
    }

    console.log(rows); // 將查詢到的資料列印出來
});
```

### 12. 模組化

接下來繼續整理程式碼，將 mysql 相關的程式碼做一個模組化的整理

新增一個 mysql.js：
```
const mysql = require("mysql");

//
const pool = mysql.createPool({
    name: "test",
    host: 'x.x.x.x',       // 連線 ip
    user: 'root',          // 連線帳號
    password: 'xxxxxxxx',  // 連線密碼
    database: 'demo'  .    // 資料庫名稱
});
```

新增一個 function：
```
exports.query = function query(sql, success) {
}
```

這個函式有兩個輸入為 sql 跟 success，並且使用 exports ，讓別的 .js 檔案也可以呼叫。

接下來把開啟與查詢資料庫的程式碼放入：
```
exports.query = function query(sql, success) {
    //
    pool.getConnection(function (err, connection) {
        if (err) {
            console.log(err);
            return;
        }

        connection.query(sql, function (errorQuery, rows) {
            connection.release();

            if (errorQuery) {
                console.log('Error SELECT to Db: ', errorQuery);
                return;
            }

            success(rows); //這邊將結果 rows 輸出出去
        });
    });
}
```

所以 main.js 的要呼叫 mysql.js 時，必須要先匯入：
```
const mysql = require("./mysql.js");
```

然後就可以呼叫 query 這個函式，第一個輸入使用字串，第二個輸入使用函式，並且將回傳的資料列印出來：
```
mysql.query("SELECT * FROM device", function (rows) {
    console.log(rows);
});
```
