はじめに
MariaDBのデータベースに(データベースの)メンテナンスのためにアクセスして”mysql”コマンドを実行してSQL文を実行するのは、うっかり手が滑ってdelete文とかupdate文とかを実行することにより予期せぬ結果をもたらす恐れがあったりして少々怖い(それも重要なデータほど資産性を帯びてきたりするので、飽きてき始めた時が一番怖いです。)ので、wrapper的なWebアプリをNode.jsとVue.jsを使って手間をかけずに作ることにしました。
Node.jsでサーバサイドを書く
Emacsのjs2-modeのインストール
作業の開始前にEmacsにjs2-modeをインストールし、emacs-lspを使ってJavaScriptのコードの補完や定義の参照ができるようにします(M-x package-installでインストールしますが、事前にemacs-lspが使用可能な状態になっていることが必要です)。
その後、.emacs.d/init.elのemacs-lsp関連の設定の直前のところに、以下の設定を追加します。
また、lsp-modeの設定を以下のように変更します。
Node.jsのインストール
今回のWebアプリの開発はWindows 10で行うことにしました。そこで、開発に使うPCにNode.jsをインストールします。
Node.jsは最新版(この記事を最初に書いた時点(2020年7月)ではv12.18.3のようです。)をNode.jsのWebサイトからダウンロードしてきてインストールします。
すると、MSIインストーラがダウンロードされますので、そいつをダブルクリックしてインストーラを起動してインストールします。
インストールが完了するとnodeコマンド(node.exe)及びnpmコマンド(npm.exe)へのパスが設定されます。
開発環境の構築
コマンドプロンプトを開き、適当なディレクトリで以下のコマンドを実行します。
ここで決めた名前が後で思わぬ影響をもたらすことはなさそうなので、適当な名前にしておきます。
この記事では、上記のコマンドを実行することによって作成されたディレクトリを「プロジェクトディレクトリ」と書くことにします。
Hello World的なコードを用いたNode.jsの動作確認
スポンサーリンク
以下のような感じのHello Worldするだけの簡単なコードを書いて、以下の手順でNode.jsの動作を確認します。
// See https://pandanote.info/?p=6505 for details. | |
const http = require('http'); | |
const server = http.createServer | |
(function (request, response) { | |
response.writeHead(200, {"Content-Type": "text/plain"}); | |
if (!request.url.endsWith('/')) { | |
response.end("Hello World!!, ("+request.url+")\n"); | |
} else { | |
response.end("Hello World!!\n"); | |
} | |
}); | |
server.listen(8590); | |
console.log("Server running at http://127.0.0.1:8590/"); |
- 上記のファイルをHelloWorld.jsというファイル名で保存します。
- 再度コマンドプロンプトを開き、プロジェクトディレクトリの下で以下のコマンドを実行します。
c:\Users\pandanote\nodejs> node HelloWorld.js
- ブラウザ(できるだけ最新版のもの。以下同じ。)で http://localhost:8590/ にアクセスします。
- 以下の文字列が表示されることを確認します。
- ブラウザで http://localhost:8590/ppp にアクセスします。
- 以下の文字列が表示されることを確認します。
サーバサイドのコードの追加
次に、MariaDBとの接続のためのコードやstaticなHTMLファイルを追加します。
MariaDB Connectorのインストール
今回作ろうとしているWebアプリではWebサーバからMariaDBへのアクセスをしますので、アクセスのための準備も行う必要があります。
そこで、プロジェクトディレクトリ上で以下のコマンドを実行し、MariaDB Connectorをインストールします。
すると…
と表示されますが、MariaDB Connectorは追加されたようですので、WARNINGについては気にしないことにして、作業を進めます。
staticなHTMLファイルの作成
クライアント(=ブラウザ)はユーザからの操作を受け付けつつ自律的に動作することが必要になりますが、その元ネタはサーバから送ってやる必要があります。
そこで、その元ネタとしてクライアントに送るべきstaticなHTMLファイルのためのディレクトリを作ります。
上記のディレクトリの下にstaticなHTMLファイルを書いて保存します。
staticなHTMLファイルとして、ファイルを作りました。
staticなHTMLファイルの送信用コードの追加
Webサーバのトップページにアクセスした際にはindex.htmlを、存在しないURLにアクセスしたときには404.htmlをそれぞれ送信したいので、以下のようなコードをHelloWorld.jsに追加します。
const fs = require('fs'); | |
const server = http.createServer | |
(function (request, response) { | |
var urlp = request.url; | |
if (別のURLの場合) { | |
// 中略 | |
} else { | |
if (urlp == "/") { | |
urlp += "index.html"; | |
} | |
urlp = "static"+urlp; | |
try { | |
const f = fs.readFileSync(urlp); | |
response.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); | |
response.write(f); | |
} catch (e) { | |
response.writeHead(404, {'Content-Type':'text/html; charset=utf-8'}); | |
response.write(fs.readFileSync("static/404.html")); | |
} | |
response.end(); | |
} | |
}); | |
// (後略) |
コネクションプールを用いたSQL文発行用コードの追加
今回開発するWebアプリではWebサーバからMariaDBのサーバにSQL文を発行してデータを取得しますので、Webサーバ側で接続のための情報を保持する必要があります。そこで、Webサーバ-MariaDBサーバ間の接続は接続インスタンスの使いまわしを可能とするため、コネクションプールを用いることにします。
また、得られたデータについてはJSONフォーマットに変換して、ブラウザに返すことにします。
そこで、以下のようなコードをHelloWorld.jsに追加します。なお、MariaDBサーバのポートを無制限に公開することを避けるため、MariaDBサーバへの接続はOpenVPN経由で行います。
const mariadb = require('mariadb'); | |
const pool = mariadb.createPool({ | |
host: "(ホスト名またはホストのIPアドレス)", | |
user: "(ユーザ名)", | |
password: "(パスワード)", | |
database: "(データベース名)", | |
connectionLimit: 5 | |
}); | |
const server = http.createServer | |
(function (request, response) { | |
var urlp = request.url; | |
if (urlp.startsWith('/api/get')) { | |
response.writeHead(200, {"Content-Type": "text/plain"}); | |
var conn = pool.getConnection() | |
.then(conn => { | |
conn.query("(SQL文(SELECT文))") | |
.then(rows => { | |
response.end(JSON.stringify(rows)); | |
}) | |
.catch(err => { | |
response.end("Hello MariaDB!!\nBut there is some error(s): "+err); | |
}); | |
conn.release(); | |
}) | |
.catch(err => { | |
response.end("Hello World!!\nBut there is some error(s): "+err); | |
}); | |
} | |
// (中略) | |
}); | |
// (後略) |
上記のような感じのコードを追加して再度コマンドプロンプトを開き、プロジェクトディレクトリの下で以下のコマンドを実行します。
次に、ブラウザを用いて http://localhost:8590/api/get にアクセスすると…
のような感じで、ブラウザにWebサーバを経由して取得したデータがJSONフォーマットで表示されます(ほとんどモザイクになってしまい、すみません)。
Vue.jsでクライアントサイドのコードを書く
最後に、Vue.jsを用いてクライアントサイドのコードを書いていきます。
CDN版及びaxios(CDN版)の読み込み
プロジェクトディレクトリのstaticの下のindex.html(以下、単に「index.html」と書きます。)のheadタグの中に以下の記述を追加します。
WebサーバのAPIの呼び出しは、axiosを使って行うため、axiosもついでにCDNから読み込んでいます。
ルートVueインスタンスの記述
index.htmlのbodyタグの下の適当な場所に以下のような記述を追加します。
<script> | |
new Vue({ | |
el: '#app', | |
data: { | |
msg: null, | |
rawmsg: "", | |
newad: "", | |
status: "" | |
}, | |
methods: { | |
getList() { | |
axios.get("/api/get") | |
.then(response => { | |
this.msg = response.data | |
}) | |
.catch(error => {}) | |
}, | |
reset() { | |
this.msg = [] | |
} | |
}, | |
mounted(){ | |
} | |
}) |
上記のコード例では”/api/get”にアクセスした結果として得られたデータをmsgという変数に代入しています。
動作確認
データが取得・表示できることの確認
index.htmlにボタンやテキストエリア等を追加し、それらに対応するためのコードをHelloWorld.jsに追加する(詳細な説明は省略します。)と、アプリケーションの完成です。
コマンドプロンプトを開き、プロジェクトディレクトリの下で以下のコマンドを実行します。
そして、http://localhost:8590/ にアクセスすると、以下のように表示されます。
さらに、上図画面上の「データを取得してみる!!」ボタンをクリックすると…
データが取得できました!!
おまけ
その1: ボタンがクリックされたときの変数
上図の赤矢印の「使用可/不可の切り替え」ボタンはv-onディレクティブ(の省略形)を使って、
のように記述し、ボタンがクリックされると、ルートVueインスタンスに定義されているtoggleAvailability(id)メソッドを(引数つきで)呼び出しています。
HTML属性の内部ではmustache記法はそのまま使えないので、ボタンがクリックされたときに呼び出されるメソッドに引数を設定する(それもボタンごとに異なる引数を設定する)にはどうしたらよいのかと思っていましたが、属性に変数名をそのまま記述すれば良いようです。
上記の例では、trタグ及びそれに含まれるtdタグがmsgに含まれているオブジェクトの数だけ繰り返し表示されますが、tdタグに含まれるbuttonタグに設定されているメソッドには表示の時点でdataオブジェクトとしてセットされているインスタンスに含まれているidが引数としてセットされるようです。
その2: INSERT文の戻り値
Node.jsのMariaDB Connectorを使ってINSERT文を以下のように呼び出したとします。
INSERT文の処理が成功すると、thenメソッドの引数であるresultに戻り値としてOkPacketオブジェクトが返されますが、これがObjectの配列の一要素として返されます。
これをクライアント側で処理する場合には上記のようにJSON形式の文字列に変換してから送信するとクライアント側での処理が容易になります。
困ったときのクライアント頼みです。
まとめ
Javaベースのフレームワークでデータベースを触ろうとするとお作法がいろいろと重たいので、今回はJavaScriptベースのフレームワークでデータベースを触ってみましたところ、ちょっと爽快な感じがしました(※個人の感想です)。
Node.js及びVue.jsベースのフレームワークとしてはNuxt.jsというのもあるようですが、学習コストがやや高めで個人的な学習の範疇を超えるような気がしたので、Node.js及びVue.jsを素で使いつつ軽くWebアプリを作ってみたところ、正味6時間程度で上記のような感じのものが出来上がりました。
細かいところや見た目や機能については調整・追加の余地がありそうですが、wrapper的なwebアプリを量産することができれば、うっかり手が滑ってdelete文とかupdate文とかをMariaDBのデータベースに対して直接実行してしまうリスクは大幅に軽減できそうです。
この記事は以上です。