71648


Express.js で外部にあるデータベースのテーブル情報をやりとりするための具体的なコードが分かりません。  
例えば、テーブルの一覧を表示するコードはどうなりますか？

**課題となっているところ**

  1. `all.js` において `app.get('/', function (request, response, next) { res.render('all', ...)})` で `all.ejs` を投げることと

  2. 

[code]

    const mysql = require('mysql2');
    
    const connection = mysql.createConnection({
      host: '??',
      user: '?',
      password: '',
      database: 'dbname'
    });
    
[/code]

（ `app.js` と `all.js` どちらに記載すべき？）  
➝

[code]

    connection.connect();
    
    connection.query('SELECT...', function (err, rows, fields) {
      if (err) throw err
     // この辺りの記述も分からない
    }); // query の記述
    
[/code]

と記述するのだが、1. とどう組み合わせるのか。

  3. ejs の変数も投げる必要があります（後述）。

**追記**  
・top page から `./all/` というページにとんだら一覧が表示される、という状況でお願いします。  
・ mysql は外部にあります（`const connection = mysql.createConnection({});` の `{}`内
`host` に書くIPアドレスを localhost にしてしまうと、 mysql の場所の指定はどこでするのでしょうか？？）。MySQL 側でこの
webサーバがある IPアドレスを指定して（ IPアドレスとユーザに権限を与えて）こちらは localhost でよいということでしょうか。(その場合ですと
MySQL の場所の情報ってないですよね？)  
・view engine に ejs を用いているので、その前提でお願いします。

**テーブル(MySQL)**  
[![データ構造](https://i.stack.imgur.com/GITBH.png)](https://i.stack.imgur.com/GITBH.png)  
全部で 200強 rows あります。

**`all.ejs`**

[code]

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title><%=title %></title>
      <link rel="stylesheet" href="/stylesheets/all.css">
      <link rel="icon" href="/images/favicon.ico">
    </head>
    <body>
      <header>
        <div class="container">
          <h1><%=title %></h1>
        </div>
      </header>
    
      <section class="top">
        <div>
          <div><a href=<%= top %>>Topへ戻る</a></div>
        </div>
      </section>
    
      <section class="output">
        <div>
          <p>一覧の表示</p>
          <table>
            <%- content %>
          </table>
        </div>
      </section>
    
      <footer>
        <div>
          <p><%= libraryName %></p>
        </div>
      </footer>
    
    </body>
    </html>
    
    
[/code]

`res.render` で `title, top, libraryName, content` も投げる必要があります。

**ファイル構成**  
`index.ejs` で `top.css` を読み込んでいます.  
一覧を表示する `./routes/all.js` のコーディングに苦戦しています.

[![ファイル構成](https://i.stack.imgur.com/LUZAZ.png)](https://i.stack.imgur.com/LUZAZ.png)


CC BY-SA 4.0
2020-10-26T02:24:51.713
71508
2020-11-13T00:50:51.843
2020-10-28T14:09:19.670
36372
36372
question
mysql node.js express.js
Express.js (ejs 使用) で、外部のデータベース(MySQL)のテーブル一覧を表示する方法


## 直接的な実装

直接クエリを叩く最もシンプルな形だと次のようになります。

[code]

    # expressとmysql2をインストールする
    npm i express mysql2
    
[/code]

**server.js**

[code]

    const express = require("express");
    const mysql = require("mysql2/promise");
    
    async function getTableData() {
      // データベースへの接続を確立させる ここは自分のデータベースに合わせてください。
      const connection = await mysql.createConnection({
        host: "localhost",
        user: "userName",
        database: "databaseName",
        password: "raw password", // 取り扱い注意
      });
      // SQLを実行 ここは自分のデータベースに合わせてください。
      const [rows, fields] = await connection.execute("SELECT * FROM [tableName]");
    
      return {
        rows,
        fields,
      };
    }
    
    // expressサーバーを作成
    const app = express();
    
    app.get("/", async (req, res) => {
      const data = await getTableData();
      const html = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
      res.send(html);
    });
    
    app.listen(3000, () => {
      console.log("http://localhost:3000");
    });
    
[/code]

[code]

    # サーバーを起動
    node server.js
    
[/code]

`http://localhost:3000` に接続すると、DBから取得したデータが一覧で表示されます。

## O/R Mapperが必要な場合

いまだとTypeORMあたりでしょうか。mysql2をラップして作成されたものです。スキーマの定義からする必要があるので、ドキュメントを読んでみると良いでしょう。

  * <https://www.npmjs.com/package/typeorm>

## 参考

  * <https://www.npmjs.com/package/typeorm>
  * <https://www.npmjs.com/package/mysql2#using-promise-wrapper>


CC BY-SA 4.0
2020-10-26T04:12:29.067
71510
2020-10-26T04:12:29.067
7997
71508
answer


  1. ejsにデータを渡す

expressでejsを使う場合は、テンプレート側(.ejsファイル)で使用する変数(all.ejsの場合だとtitleやtopなど)をrenderメソッドの第２引数に指定します。  
形式はテンプレート側で使う変数名をキーにしたオブジェクトで、all.ejsの場合だとこのようになるでしょう。

[code]

    app.get('/', function (request, response, next) {
      res.render('all', {
        title: '一覧ページ',
        top: '/',
        libraryName: '',
        content: '<tr><td>データ</td></tr>'
      })
    })
    
[/code]

  2. MySQLへの接続、クエリ

読み込み順序やサーバーを起動したときにデータベースに接続するために、db.jsなど別ファイルに書くのが良いと思います。

[code]

    const mysql = require('mysql2')
    
    const connection = mysql.createConnection({
      host: '',
      user: '',
      password: '',
      database: ''
    })
    
    module.exports = connection
    
[/code]

hostやuserなどは接続先のデータベースの情報を入れます。  
localhostは自身を指すので、具体的な状況は分からないですが、異なるサーバーで実行されているのならば、そのサーバーのホスト名やIPアドレスを入れることになります。

all.jsからのqueryはこのようになります。

[code]

    const connection = require('../db')
    
    app.get('/', function (request, response, next) {
      connection.query('SELECT * FROM books', function (err, rows, fields) {
        if (err) throw err
    
        let table = ''
        for (let i = 0; i < rows.length; i++) {
          table += '<tr>'
          table += '<td>' + rows[i].id + '</td>'
          table += '<td>' + rows[i].title + '</td>'
          table += '<td>' + rows[i].author + '</td>'
          table += '<td>' + rows[i].genre + '</td>'
          table += '<td>' + rows[i].hight + '</td>'
          table += '<td>' + rows[i].publisher + '</td>'
          table += '</tr>'
        }
    
        res.render('all', {
          title: '一覧ページ',
          top: '/',
          libraryName: '...',
          content: table
        })
      })
    })
    
[/code]

rowsにはその名前の通り、データベースから取得した行の配列が入っているので、これを元に表示するHTMLを生成して渡します。

ここまでall.ejsに`<%- content
%>`とあったのでall.js側でHTMLを生成し埋め込むという想定でここまで書きましたが、ejs側でテーブル構造を表現(HTMLを生成)するのが良いでしょう。  
これはHTMLを生成する部分と、プログラムの処理を分けることで可読性や保守性が上がるほか、HTMLに意図しないデータが含まれてしまうのを防ぐことができます。  
もしユーザーによってデータベースに値を追加される場合、`<script>alert('XSS!')</script>`のような文字列を入れられた場合、そのままHTMLに埋め込まれ表示してしまいます。これはXSS脆弱性です。  
テンプレート側でテーブル構造を表現することでこの問題を回避することができます。

[code]

    <table>
      <% for (let i = 0; i < books.length; i++) { %>
        <tr>
          <td><%= books[i].id %></td>
          <td><%= books[i].title %></td>
          <td><%= books[i].author %></td>
          <td><%= books[i].genre %></td>
          <td><%= books[i].hight %></td>
          <td><%= books[i].publisher %></td>
        </tr>    
      <% } %>
    </table>
    
[/code]

このように書くことで、`<%- foo %>`を使ったHTMLの埋め込みをさけ、`<%= foo %>`を使うことができるため、XSS脆弱性が発生しません。

all.jsからはHTML生成処理がなくなるので、単にrowsを渡すだけになります。

[code]

    const connection = require('../db')
    
    app.get('/', function (request, response, next) {
      connection.query('SELECT * FROM books', function (err, rows, fields) {
        if (err) throw err
    
        res.render('all', {
          title: '一覧ページ',
          top: '/',
          libraryName: '...',
          content: rows
        })
      })
    })
    
[/code]


CC BY-SA 4.0
2020-11-01T21:17:30.700
71648
2020-11-01T21:26:29.743
2020-11-01T21:26:29.743
31898
31898
71508
answer


これは MySQL 側の問題で、データベースの user に [username]@[IP address]
と登録（create）するとき、IPアドレスにサーバの場所ではなく MySQL の場所を登録することが必要で、（最初）違和感でした。


CC BY-SA 4.0
2020-11-13T00:50:51.843
71905
2020-11-13T00:50:51.843
36372
71508
answer