Vue.js+Node.jsを利用したチャットアプリの作成

## はじめに
最近Node.jsの勉強をしたので、何かしらのアウトプットを行おうとチャットアプリを作成しました。その備忘録です。
機能としては、簡単なログイン・ログアウト機能、チャット機能を実装しました。

## 成果物
![sample_other.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/b4506835-2333-fce3-dc79-a7e40ce44321.gif)

## 利用したライブラリ
- Vue.js
    - VueCLI…Vue.js向けのアプリケーション開発環境セットアップなどの機能を提供するCLIツール
    - vuetify…Vueのアプリケーションのデザインを容易に整えてくれるライブラリ
    - vuex…vue全体で利用できるデータストアを管理できるライブラリ
    - vuex-persistedstate…vuexの値をローカルストレージに保存するプラグイン
    - socket.io-client…socket.ioでサーバへ接続するためのクライアント用ライブラリ
- Node.js 
    - express…Node.jsで使用するWebアプリのフレームワーク
    - socket.io…Webのリアルタイム通信を可能にするライブラリ
    - mysql…MySQLをNode.jsから扱えるライブラリ

## ディレクトリ構成
chatapp/
├ frontend/ ( VueCLIで作成されたプロジェクト )
｜　　├ src/
｜　　｜　├ components/
｜　　｜　　　├ Chat.vue
｜　　｜　　　└ MenuBar.vue　　
｜　　├ store
｜　　｜　├ index.js
｜　　├ views
｜　　｜　├ Home.vue
｜　　｜　├ Login.vue
｜　　├ App.vue
｜　　└ …etc
└ backend/ (自分で作成)
　　　├ bin/
　　　｜　└ www
　　　├ public
　　　｜　└ javascripts
　　　｜　　　　└ db_config.js
　　　├ routes
　　　｜　├ delete.js
　　　｜　├ getHistories.js
　　　｜　└ login.js
　　　├ app.js
　　　└ …etc

## 環境イメージ図
全部localhostで完結せず、勉強のためにDBだけ別にしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/17fad34e-9c3c-4062-e3ac-e1204b1546e5.png)

## 初期準備
### Node.jsのインストール
[公式サイト](https://nodejs.org/ja/download/)からダウンロードします。

```
$ node -v
v12.18.3

$ npm -v
6.14.6
```

#### フロントエンド(Vue.js)の初期準備
[公式サイト](https://cli.vuejs.org/)に従ってインストールしていきます。

```
$npm install -g @vue/cli

$vue --version
@vue/cli 4.5.4
```

次にプロジェクトを作成します。

```
$vue create frontend
```
コンソールに選択肢が出てくるのですが、Manually select featuresを選択し、Vuexを追加で選択します。

```
Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: 
 (*) Choose Vue version
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support        
 ( ) Router
>(*) Vuex
 ( ) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing
```

次にVue.jsのバージョンを選択します。今回は2.xを選択します。

```
? Choose a version of Vue.js that you want to start the project with (Use arrow keys)     
> 2.x
  3.x (Preview)
```

次にESlintの設定を選択します。今回はエラー防止のみのESLint with error prevention onlyを選択します。

```
? Pick a linter / formatter config: 
> ESLint with error prevention only 
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
```

次にLintをかけるタイミングをどうするか選択します。今回はセーブした場合にかけます。

```
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Lint on save
 ( ) Lint and fix on commit
```

次に各種設定をどこに置くか選択します。設定ファイルは個別に管理するのでIn dedicated config filesを選択します。

```
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
  In package.json
```

最後にこの設定をプリセットとして保存するか選択できます。今回はNを選択します。

```
? Save this as a preset for future projects? (y/N) N
```

プロジェクトを作成できたので、コマンドを入力し、`http://localhost:8080`にアクセスします。

```
$ cd frontend/
$ npm run serve
```

無事起動できたことが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/22bd8f4f-2318-d281-93d6-a522e4741423.png)
次にVuetifyを利用するためにVuetifyをインストールしましょう。
Vuetifyでもプリセットを聞かれるのでDefaultを選択します。

```
$ vue add vuetify
```

Vuetifyが適用されたのが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/eab960aa-40e0-9c16-b6a9-ccd4baff79db.png)

#### バックエンド(Node.js)の初期準備
今回はExpressを利用してバックエンドのアプリケーションを作成するのですが、一から作るのには時間がかかるので、Express Generatorを利用して基本的な部分は作ってもらいます。
※ただExpress Generatorを利用すると今回は利用しないejsファイル( javascript用のテンプレートエンジン)までも作成されたり、不要なルーティングの設定も追加されてしまいます。

```
$ npm install -g express-generator
$ express -e backend
```

まだ必要なパッケージが用意されていないので、インストールしましょう。

```
$ cd backend
$ npm install
```

実際に起動できるか確認します。コマンドを入力し、`http://localhost:3000`にアクセスします。

```
$ npm start
```

無事起動できたことが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555434/ec6ff7f9-e9e5-5db0-ef63-c3a50c3236f8.png)

#### DBの初期準備
今回はVM(CentOS Linux release 8.1.1911)を立ててそこにMySQLをインストールしてきます。
まずはインストールして利用しているMySQLをアンインストールしていきます。
参考記事：[CentOSにインストールしたMySQLを削除する](https://www.suzu6.net/posts/197-delete-mysql/)

###### MySQLのアンインストール
①稼働しているMySQLを停止します。

```
$ mysqld --version
/usr/libexec/mysqld  Ver 8.0.17 for Linux on x86_64 (Source distribution)

$ su

# systemctl stop mysqld.service
# systemctl status mysqld.service
   mysqld.service - MySQL 8.0 database server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Sun 2020-08-23 17:36:29 JST; 42s ago
```

②インストール済みのMySQLの確認をします。

```
# rpm -qa | grep -i mysql
mysql-8.0.17-3.module_el8.0.0+181+899d6349.x86_64
mysql80-community-release-el8-1.noarch
mysql-common-8.0.17-3.module_el8.0.0+181+899d6349.x86_64
mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64
mysql-errmsg-8.0.17-3.module_el8.0.0+181+899d6349.x86_64
```

③MySQL8をアンインストールします。

```
# yum remove mysql*
モジュラーの依存に関する問題:

 問題 1: conflicting requests
  - nothing provides module(perl:5.26) needed by module perl-DBD-SQLite:1.58:8010020191114033549:073fa5fe-0.x86_64
 問題 2: conflicting requests
  - nothing provides module(perl:5.26) needed by module perl-DBI:1.641:8010020191113222731:16b3ab4d-0.x86_64
依存関係が解決しました。
=============================================================================================================================================================================================
 パッケージ                                         アーキテクチャー               バージョン                                                    リポジトリー                          サイズ
=============================================================================================================================================================================================
削除中:
 mysql                                              x86_64                         8.0.17-3.module_el8.0.0+181+899d6349                          @AppStream                             67 M
 mysql-common                                       x86_64                         8.0.17-3.module_el8.0.0+181+899d6349                          @AppStream                            518 k
 mysql-errmsg                                       x86_64                         8.0.17-3.module_el8.0.0+181+899d6349                          @AppStream                            7.8 M
 mysql-server                                       x86_64                         8.0.17-3.module_el8.0.0+181+899d6349                          @AppStream                            138 M
 mysql80-community-release                          noarch                         el8-1                                                         @@commandline                          29 k
未使用の依存関係の削除:
 mariadb-connector-c-config                         noarch                         3.0.7-1.el8                                                   @AppStream                            497
 mecab                                              x86_64                         0.996-1.module_el8.0.0+41+ca30bab6.9                          @AppStream                            2.2 M
 protobuf-lite                                      x86_64                         3.5.0-7.el8                                                   @AppStream                            508 k

トランザクションの概要
=============================================================================================================================================================================================
削除  8 パッケージ

解放された容量: 216 M
これでよろしいですか? [y/N]: y
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                                                                                                                                     1/1
  scriptletの実行中: mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            1/1
  scriptletの実行中: mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            1/8
  削除             : mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            1/8
  scriptletの実行中: mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            1/8
  削除             : mysql-errmsg-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            2/8
  削除             : mysql80-community-release-el8-1.noarch                                                                                                                              3/8
  削除             : mysql-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                                   4/8
  削除             : mysql-common-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            5/8
  削除             : mariadb-connector-c-config-3.0.7-1.el8.noarch                                                                                                                       6/8
  削除             : mecab-0.996-1.module_el8.0.0+41+ca30bab6.9.x86_64                                                                                                                   7/8
  scriptletの実行中: mecab-0.996-1.module_el8.0.0+41+ca30bab6.9.x86_64                                                                                                                   7/8
  削除             : protobuf-lite-3.5.0-7.el8.x86_64                                                                                                                                    8/8
  scriptletの実行中: protobuf-lite-3.5.0-7.el8.x86_64                                                                                                                                    8/8
  検証             : mariadb-connector-c-config-3.0.7-1.el8.noarch                                                                                                                       1/8
  検証             : mecab-0.996-1.module_el8.0.0+41+ca30bab6.9.x86_64                                                                                                                   2/8
  検証             : mysql-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                                   3/8
  検証             : mysql-common-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            4/8
  検証             : mysql-errmsg-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            5/8
  検証             : mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64                                                                                                            6/8
  検証             : mysql80-community-release-el8-1.noarch                                                                                                                              7/8
  検証             : protobuf-lite-3.5.0-7.el8.x86_64                                                                                                                                    8/8

削除しました:
  mysql-8.0.17-3.module_el8.0.0+181+899d6349.x86_64             mysql-common-8.0.17-3.module_el8.0.0+181+899d6349.x86_64      mysql-errmsg-8.0.17-3.module_el8.0.0+181+899d6349.x86_64
  mysql-server-8.0.17-3.module_el8.0.0+181+899d6349.x86_64      mysql80-community-release-el8-1.noarch                        mariadb-connector-c-config-3.0.7-1.el8.noarch
  mecab-0.996-1.module_el8.0.0+41+ca30bab6.9.x86_64             protobuf-lite-3.5.0-7.el8.x86_64

完了しました!
```

④データベースを削除します。

```
rm -rf /var/lib/mysql
```

###### 次にMySQL8をインストールしていきます。
参考記事：<br>・[CentOS7にMySQL8をインストールして初期パスワードを変更する](https://qiita.com/yasushi-jp/items/1579c301075d693a2a36)
・[MySQL 8.0 を CentOS 8.1 にインストールする手順](https://qiita.com/yasushi-jp/items/1579c301075d693a2a36)

① dnfコマンド利用してrpmパッケージをインストールします。

```
# dnf localinstall https://dev.mysql.com/get/mysql80-community-release-el8-1.noarch.rpm
mysql80-community-release-el8-1.noarch.rpm                                                                                                                    21 kB/s |  30 kB     00:01
依存関係が解決しました。
=============================================================================================================================================================================================
 パッケージ                                                アーキテクチャー                       バージョン                              リポジトリー                                 サイズ
=============================================================================================================================================================================================
インストール:
 mysql80-community-release                                 noarch                                 el8-1                                   @commandline                                  30 k

トランザクションの概要
=============================================================================================================================================================================================
インストール  1 パッケージ

合計サイズ: 30 k
インストール済みのサイズ: 29 k
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                                                                                                                                     1/1
  インストール中   : mysql80-community-release-el8-1.noarch                                                                                                                              1/1
  検証             : mysql80-community-release-el8-1.noarch                                                                                                                              1/1

インストール済み:
  mysql80-community-release-el8-1.noarch

完了しました!
```

②MySQLのリポジトリが有効になっていることを確認します。

```
dnf repolist enabled | grep "mysql.*-community.*"
mysql-connectors-community           MySQL Connectors Community               74
mysql-tools-community                MySQL Tools Community                    33
mysql80-community                    MySQL 8.0 Community Server               51

デフォルトデフォルトのMySQLモジュールを無効化します。
# dnf module disable mysql
依存関係が解決しました。
=============================================================================================================================================================================================
 パッケージ                                   アーキテクチャー                            バージョン                                      リポジトリー                                 サイズ
=============================================================================================================================================================================================
モジュールプロファイルの無効化:
 mysql/server
モジュールの無効化:
 mysql

トランザクションの概要
=============================================================================================================================================================================================

これでよろしいですか? [y/N]: y
完了しました!
```

③リポジトリからインストールするパッケージを確認します。

```
dnf info mysql-community-server
利用可能なパッケージ
名前         : mysql-community-server
バージョン   : 8.0.21
リリース     : 1.el8
Arch         : x86_64
サイズ       : 53 M
ソース       : mysql-community-8.0.21-1.el8.src.rpm
リポジトリー : mysql80-community
概要         : A very fast and reliable SQL database server
URL          : http://www.mysql.com/
ライセンス   : Copyright (c) 2000, 2020, Oracle and/or its affiliates. Under GPLv2 license as shown in the Description field.
説明         : The MySQL(TM) software delivers a very fast, multi-threaded, multi-user,
             : and robust SQL (Structured Query Language) database server. MySQL Server
             : is intended for mission-critical, heavy-load production systems as well
             : as for embedding into mass-deployed software. MySQL is a trademark of
             : Oracle and/or its affiliates
             :
             : The MySQL software has Dual Licensing, which means you can use the MySQL
             : software free of charge under the GNU General Public License
             : (http://www.gnu.org/licenses/). You can also purchase commercial MySQL
             : licenses from Oracle and/or its affiliates if you do not wish to be bound by the terms of
             : the GPL. See the chapter "Licensing and Support" in the manual for
             : further info.
             :
             : The MySQL web site (http://www.mysql.com/) provides the latest news and
             : information about the MySQL software.  Also please see the documentation
             : and the manual for more information.
             :
             : This package includes the MySQL server binary as well as related utilities
             : to run and administer a MySQL server.
```

④確認できたので、インストールします。

```
# dnf install mysql-community-server

依存関係が解決しました。
=============================================================================================================================================================================================
 パッケージ                                           アーキテクチャー                     バージョン                                  リポジトリー                                    サイズ
=============================================================================================================================================================================================
インストール:
 mysql-community-server                               x86_64                               8.0.21-1.el8                                mysql80-community                                53 M
依存関係のインストール:
 mysql-community-client                               x86_64                               8.0.21-1.el8                                mysql80-community                                12 M
 mysql-community-common                               x86_64                               8.0.21-1.el8                                mysql80-community                               621 k
 mysql-community-libs                                 x86_64                               8.0.21-1.el8                                mysql80-community                               1.4 M

トランザクションの概要
=============================================================================================================================================================================================
インストール  4 パッケージ

ダウンロードサイズの合計: 67 M
インストール済みのサイズ: 317 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード:
(1/4): mysql-community-common-8.0.21-1.el8.x86_64.rpm                                                                                                        906 kB/s | 621 kB     00:00
(2/4): mysql-community-libs-8.0.21-1.el8.x86_64.rpm                                                                                                          2.1 MB/s | 1.4 MB     00:00
(3/4): mysql-community-client-8.0.21-1.el8.x86_64.rpm                                                                                                        4.6 MB/s |  12 MB     00:02
(4/4): mysql-community-server-8.0.21-1.el8.x86_64.rpm                                                                                                        4.3 MB/s |  53 MB     00:12
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
合計                                                                                                                                                         5.2 MB/s |  67 MB     00:12
警告: /var/cache/dnf/mysql80-community-b1f1ed5ba88ce0f8/packages/mysql-community-client-8.0.21-1.el8.x86_64.rpm: ヘッダー V3 DSA/SHA1 Signature、鍵 ID 5072e1f5: NOKEY
MySQL 8.0 Community Server                                                                                                                                    27 MB/s |  27 kB     00:00
GPG 鍵 0x5072E1F5 をインポート中:
 Userid     : "MySQL Release Engineering <mysql-build@oss.oracle.com>"
 Fingerprint: A4A9 4068 76FC BD3C 4567 70C8 8C71 8D3B 5072 E1F5
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
これでよろしいですか? [y/N]: y
鍵のインポートに成功しました
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                                                                                                                                     1/1
  インストール中   : mysql-community-common-8.0.21-1.el8.x86_64                                                                                                                          1/4
  インストール中   : mysql-community-libs-8.0.21-1.el8.x86_64                                                                                                                            2/4
  scriptletの実行中: mysql-community-libs-8.0.21-1.el8.x86_64                                                                                                                            2/4
  インストール中   : mysql-community-client-8.0.21-1.el8.x86_64                                                                                                                          3/4
  scriptletの実行中: mysql-community-server-8.0.21-1.el8.x86_64                                                                                                                          4/4
  インストール中   : mysql-community-server-8.0.21-1.el8.x86_64                                                                                                                          4/4
  scriptletの実行中: mysql-community-server-8.0.21-1.el8.x86_64                                                                                                                          4/4
  検証             : mysql-community-client-8.0.21-1.el8.x86_64                                                                                                                          1/4
  検証             : mysql-community-common-8.0.21-1.el8.x86_64                                                                                                                          2/4
  検証             : mysql-community-libs-8.0.21-1.el8.x86_64                                                                                                                            3/4
  検証             : mysql-community-server-8.0.21-1.el8.x86_64                                                                                                                          4/4

インストール済み:
  mysql-community-server-8.0.21-1.el8.x86_64     mysql-community-client-8.0.21-1.el8.x86_64     mysql-community-common-8.0.21-1.el8.x86_64     mysql-community-libs-8.0.21-1.el8.x86_64

完了しました!
```

⑤MySQLがインストールされていることを確認します。

```
# mysqld --version
/usr/sbin/mysqld  Ver 8.0.21 for Linux on x86_64 (MySQL Community Server - GPL)
```

###### 次にMySQLの初期設定をしてきます
①パスワードのポリシーの設定を変更します。デフォルトではパスワードポリシーの制約が強く、なかなかパスワードを登録できませんでした。

```
# vi /etc/my.cnf
[変更：コメントアウトを外す]
default_authentication_plugin=mysql_native_password

[追加]
# パスワードポリシー
validate_password.length=4
validate_password.mixed_case_count=0
validate_password.number_count=0
validate_password.special_char_count=0
validate_password.policy=LOW
```

②MySQLを起動し、自動起動の設定を追加します。

```
# systemctl start mysqld.service
# systemctl enable mysqld.service
```

③mysqld.logから初期パスワードを検索します。

```

# grep 'temporary password' /var/log/mysqld.log
2020-08-23T08:55:06.087398Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: 43+;S.lyoamX
```

④パスワードの更新と初期設定

```

# mysql_secure_installation
# mysql -u root -p
Enter password:[更新したパスワードの入力]
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.21

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

⑤localhost以外からも接続できるdevユーザを作成します。
MySQLはデフォルトでlocalhostからしか接続できない設定なので、localhost以外から接続できるユーザを作成しないと疎通できません。

```
mysql> create user 'dev'@'%' identified by '[パスワード]';
mysql> grant all on *.* to 'dev'@'%';
```

⑥データベースの作成

```
mysql> create database chat_app_db;
mysql> use chat_app_db
Database changed

mysql> INSERT INTO user_informations (user_id, password)
VALUES ('test', '1234');
```

あとはNode.jsからSQL文を実行してDB操作をするため、Node.jsのポート3000番を開けます。これをしないとファイヤーウォールでNode.jsからのアクセスが弾かれてDB操作ができません。

```
# firewall-cmd --zone=public --add-port=3000/tcp --permanent
```

### ログイン・ログアウト機能
ログイン機能ではフロント(Vue.js)からaxiosを利用してバックエンド(Node.js)にHTTPリクエストを送ります。
なのでまずaxiosをインストールします。

```
$ npm install --save axios
```

ただこのままだとフロントとバックが異なるオリジンとして捉えられてしまい、CORSを有効化していないため、HTTP通信ができません。フロントはnpm run serveでオリジンが`http://localhost:8080`、バックはnpm startでオリジンが`http://localhost:3000`となり、ポート番号が異なるため、異なるオリジンとして捉えられます。

CORSの有効化を行うためには、Node.jsのapp.jsに以下を追加しましょう。
app.use()がまとまっている部分がありますが、その一番最初に記載しましょう。順番を間違えるとCORSの有効化ができません。

```app.js
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  next();
 });
```

また、バックエンド側ではMySQLへのアクセスを行うために、MYSQLモジュールをインポートします。

```
$ npm install --save mysql
```

実際にログインの処理を記載してみたらうまくいきました。
○Vue.js

```App.vue
<template>
  <v-app>
    <login v-if="!isLogin"></login>
    <home v-else />
  </v-app>
</template>

<script>
import Login from "@/views/Login.vue";
import Home from "@/views/Home.vue";
import { mapState } from "vuex";

export default {
  name: "App",
  components: {
    Login,
    Home,
  },
  computed: {
    ...mapState(["isLogin"]),
  },
};
</script>


```

```Login.vue
<template>
  <div class="login">
    <v-container class="fill-height" fluid>
      <v-row
        align="center"
        justify="center"
        class="headline font-italic font-weight-medium text--secondary"
      >
        <v-col cols="12" sm="8" md="6" lg="4">
          <v-icon large>mdi-chat-processing-outline</v-icon>ChatApp
        </v-col>
      </v-row>
      <v-row align="center" justify="center">
        <v-col cols="12" sm="8" md="6" lg="4">
          <v-card class="elevation-12">
            <v-toolbar color="primary" dark flat>
              <v-toolbar-title>Login form</v-toolbar-title>
              <v-spacer></v-spacer>
            </v-toolbar>
            <v-card-text>
              <v-form>
                <v-text-field
                  label="UserId"
                  name="login"
                  prepend-icon="mdi-account"
                  type="text"
                  v-model="userId"
                ></v-text-field>

                <v-text-field
                  id="password"
                  label="Password"
                  name="password"
                  prepend-icon="mdi-lock"
                  :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
                  :type="showPassword ? 'text' : 'password'"
                  @click:append="showPassword = !showPassword"
                  @keyup.enter="login"
                  v-model="password"
                ></v-text-field>
              </v-form>
            </v-card-text>
            <v-card-actions>
              <v-row align="center" justify="space-around">
                <v-btn color="#B2EBF2" @click="login">Login</v-btn>
              </v-row>
            </v-card-actions>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
export default {
  name: "Login",
  components: {},
  data: () => ({
    showPassword: false,
    userId: "",
    password: "",
  }),
  methods: {
    login() {
      // 入力されたログイン情報が正しいか確認
      this.$store.dispatch("login", {
        userId: this.userId,
        password: this.password,
      });
    },
  },
};
</script>
```

```store>index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import createPersistedState from 'vuex-persistedstate';

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    isLogin: false,
    userId: '',
    password: ''
  },
  mutations: {
    login(state, param) {
      state.isLogin = true;
      state.userId = param.userId;
      state.password = param.password;
    },
    logout(state) {
      state.isLogin = false;
      state.userId = '';
      state.password = '';
    }
  },
  actions: {
    async login({ commit }, { userId, password }) {
      const param = {
        userId: userId,
        password: password
      }

      try {
        const loginResult = await axios.post('http://localhost:3000/login', param);
        if (loginResult.data === 'OK') {
          // 認証に成功した場合
          commit('login', param);
        } else {
          // 認証に失敗した場合
          console.log('認証に失敗しました。');
        }
      } catch{
        alert('処理に失敗しました。')
      }

    },
    logout({ commit }) {
      commit('logout');
    }
  },
  plugins:[createPersistedState()]
})

```

○Node.js

```login.js
var express = require('express');
var router = express.Router();

var mysql = require('mysql');
const config  = require('../public/javascripts/db_config.js');

/* GET home page. */
router.post('/', function (req, res, next) {

    // フロントからのパラメータ取得
    const userId = req.body.userId;
    const password = req.body.password;

    // コネクションの用意
    const connection = mysql.createConnection(config.mysql_setting);

    connection.query(config.loginSQL, [userId, password],
        function (error, results, fields) {
            console.log(results);
            if (results.length >= 1) {
                res.send('OK');
            } else {
                res.send('NG');
            }
        }
    );
});

module.exports = router;
```


最初は下記`mysql_setting`に`timezone`を入れずに確認をしていたのですが、datetime型の値をNode.jsで操作した場合、JSTではなくUTC表記で出力されたため、`timezone:jst`を入れています。
参考記事：[mysqlモジュールでDB操作](https://www.wakuwakubank.com/posts/665-node-mysql/)

```db_config.js
exports.mysql_setting = {
    host: '*',
    user: 'dev',
    password: '*',
    database: 'chat_app_db',
    timezone: 'jst'
};
exports.loginSQL = 'SELECT * from user_informations where user_id=? AND password=?'
exports.insertRecordSQL = 'INSERT INTO chat_histories(history_index,user_id,message,date_time) VALUES(?, ?, ?, ?)';
exports.getHistoriesSQL = 'SELECT * FROM chat_histories';
exports.deleteHistorySQL = 'TRUNCATE TABLE chat_histories';
```

## チャット機能
○Vue.js

```MenuBar.vue
<template>
  <v-app-bar app color="primary" dark>
    <v-spacer></v-spacer>
    <v-btn @click="logout">
      <span class="mr-2">Logout</span>
      <v-icon>mdi-home-export-outline</v-icon>
    </v-btn>
  </v-app-bar>
</template>

<script>
export default {
  name: "MenuBar",
  components: {},
  methods: {
    logout() {
      // ログアウト処理実施
      this.$store.dispatch("logout");
    },
  },
};
</script>
```

```Chat.vue
<template>
  <v-container>
    <v-row class="text-center">
      <v-col cols="12" style="height:80vh">
        <v-toolbar color="#BBDEFB" light>
          <v-toolbar-title>Welcome ChatApp</v-toolbar-title>
          <v-spacer></v-spacer>
          <v-btn @click="deleteRecord">Delete Old Chat</v-btn>
        </v-toolbar>
        <!-- v-card内チャットをスクロールさせるためにclass="overflow-y-auto"を指定 -->
        <v-card height="90%" width="100%" class="overflow-y-auto">
          <!-- チャットの表示 -->
          <v-list two-line subheader>
            <v-list-item v-for="(message,index) in messages" :key="index">
              <v-list-item-avatar>
                <v-icon>mdi-account-circle</v-icon>
              </v-list-item-avatar>
              <v-list-item-content>
                <v-list-item-title v-text="message.user_id"></v-list-item-title>
                <v-list-item-subtitle v-text="message.message"></v-list-item-subtitle>
                <v-list-item-subtitle v-text="message.date_time"></v-list-item-subtitle>
              </v-list-item-content>
            </v-list-item>
            <v-divider inset v-if="messages.length > 0"></v-divider>
          </v-list>
        </v-card>
        <v-card height="10%" width="100%" color="#B2DFDB" class="pa-sm-3 pa-lg-3 pa-md-4">
          <v-text-field
            v-model="message"
            solo
            clearable
            append-outer-icon="mdi-send"
            @click:append-outer="sendMessage"
            @keyup.enter="sendMessage"
          ></v-text-field>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import io from "socket.io-client";
import axios from "axios";

export default {
  name: "Chat",
  data: () => ({
    message: "",
    messages: [],
    userId: "",
    socket: "",
  }),
  methods: {
    //チャットを投稿する処理
    sendMessage() {
      this.userId = this.$store.state.userId;
      const date = new Date();
      const date_time = `${date.getFullYear().toString()}-${(
        "00" + (date.getMonth() + 1).toString()
      ).slice(-2)}-${("00" + date.getDate().toString()).slice(-2)} ${(
        "00" + date.getHours().toString()
      ).slice(-2)}:${("00" + date.getMinutes().toString()).slice(-2)}:${(
        "00" + date.getSeconds().toString()
      ).slice(-2)}`;

      // Socketを利用してサーバと通信を行う。
      this.socket.emit("SEND_MESSAGE", {
        user_id: this.userId,
        message: this.message,
        date_time: date_time,
      });
      this.message = "";
    },
    // 投稿したチャットの削除
    async deleteRecord() {
      try {
        const result = await axios.post("http://localhost:3000/delete");
        if (result.data === "OK") {
          // 削除に成功した場合履歴の初期化
          this.messages = [];
        } else {
          // 削除に失敗した場合
          console.log("削除に失敗しました。");
        }
      } catch {
        alert("処理に失敗しました。");
      }
    },
  },

  async mounted() {
    this.socket = io("localhost:3000");

    // 初期表示時にDBのレコードを取得する
    try {
      const result = await axios.post("http://localhost:3000/getHistories");
      if (result.data !== "NG") {
        // 履歴の取得に成功した場合
        this.messages = result.data;
      } else {
        // 履歴の取得に失敗した場合
        console.log("履歴の表示に失敗しました。");
      }
    } catch {
      alert("処理に失敗しました。");
    }

    // 投稿されたデータの取得
    this.socket.on("MESSAGE", (data) => {
      this.messages = data;
    });
  },
};
</script>

<style scoped>
.v-list-item__content {
  text-align: left;
}
</style>

```

○Node.js

wwwファイルに以下の記述を追加することで、Socket.ioの機能を利用することができます。

```
/**
 * ADDED!! Socket.IO Connection.
 */
var mysql = require('mysql');
const config  = require('../public/javascripts/db_config.js');

io.on('connection', function (socket) {
  // フロント側からチャットが投下された時に発火するイベント
  socket.on('SEND_MESSAGE', function (data) {

    // コネクションの用意
    const connection = mysql.createConnection(config.mysql_setting);

    // レコード件数の取得
    connection.query(config.getHistoriesSQL, function (error, results, fields) {
      const countUpNum = results.length + 1;
      data.index = countUpNum
      results.push(data);
      // 後続の作業を待つ必要がないため、フロントに値を返す。
      io.emit('MESSAGE', results)

      // レコード挿入
      connection.query(config.insertRecordSQL, [countUpNum, data.user_id, data.message, data.date_time],
        function (error, results, fields) {
          // ログ出力
          if (!error) {
            console.log(`INSERT成功：${results}`);
          } else {
            console.log(`INSERT失敗：${error}`);
          }
        }
      );
    })
  });
});

```

```delete.js
var express = require('express');
var router = express.Router();

var mysql = require('mysql'); //★追加
const config  = require('../public/javascripts/db_config.js');

// 削除フォームの送信処理
router.post('/', (req, res, next) => {

  // データベースの設定情報
  var connection = mysql.createConnection(config.mysql_setting);

  // データを取り出す
  connection.query(config.deleteHistorySQL, function (error, results, fields) {
    if (!error) {
      res.send('OK');
    } else {
      res.send('NG');
    }
  }
  );
});

module.exports = router;
```


```getHistories.js
var express = require('express');
var router = express.Router();

var mysql = require('mysql');
const config  = require('../public/javascripts/db_config.js');

// 画面が表示された際に実行される処理
router.post('/', (req, res, next) => {

  // データベースの設定情報
  var connection = mysql.createConnection(config.mysql_setting);

  // データを取り出す
  connection.query(config.getHistoriesSQL, function (error, results, fields) {
    if (!error) {
      res.send(results);
    } else {
      res.send('NG');
    }
  }
  );
});

module.exports = router;
```

Vuejsのコードは[こちら](https://github.com/TakayaTanuki/chatapp-frontend)に、Node.jsのコードは[こちら](https://github.com/TakayaTanuki/chatapp-backend)にアップしております。
よろしればアドバイス頂けますと幸いです。

## 最後に
次はこのチャットアプリの機能を充実させるか別のアプリをVue.jsとNode.jsを利用して作ってみたいと思っています。

## 参照
[Vue.js公式サイト](https://cli.vuejs.org/)
[CentOSにインストールしたMySQLを削除する](https://www.suzu6.net/posts/197-delete-mysql/)
[CentOS7にMySQL8をインストールして初期パスワードを変更する](https://qiita.com/yasushi-jp/items/1579c301075d693a2a36)
[MySQL 8.0 を CentOS 8.1 にインストールする手順](https://qiita.com/yasushi-jp/items/1579c301075d693a2a36)
[mysqlモジュールでDB操作](https://www.wakuwakubank.com/posts/665-node-mysql/)
[ブラウザからWebAPIと非同期通信を行う](https://microcms.io/blog/async-request/)
[Vue.js+Express+Socket.IO 最小構成でリアルタイムチャットを作成する](http://rabadons.com/2018/09/25/vuejs_realtimechat/)