はじめに
最近Node.jsの勉強をしたので、何かしらのアウトプットを行おうとチャットアプリを作成しました。その備忘録です。
機能としては、簡単なログイン・ログアウト機能、チャット機能を実装しました。
成果物
利用したライブラリ
- 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だけ別にしてみました。
初期準備
Node.jsのインストール
公式サイトからダウンロードします。
$ node -v
v12.18.3
$ npm -v
6.14.6
フロントエンド(Vue.js)の初期準備
公式サイトに従ってインストールしていきます。
$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
無事起動できたことが確認できました。
次にVuetifyを利用するためにVuetifyをインストールしましょう。
Vuetifyでもプリセットを聞かれるのでDefaultを選択します。
$ vue add vuetify
バックエンド(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
DBの初期準備
今回はVM(CentOS Linux release 8.1.1911)を立ててそこにMySQLをインストールしてきます。
まずはインストールして利用しているMySQLをアンインストールしていきます。
参考記事:CentOSにインストールした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をインストールしていきます。
参考記事:
・CentOS7にMySQL8をインストールして初期パスワードを変更する
・MySQL 8.0 を CentOS 8.1 にインストールする手順
① 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.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
<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>
<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>
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
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操作
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
<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>
<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}`);
}
}
);
})
});
});
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;
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のコードはこちらに、Node.jsのコードはこちらにアップしております。
よろしればアドバイス頂けますと幸いです。
最後に
次はこのチャットアプリの機能を充実させるか別のアプリをVue.jsとNode.jsを利用して作ってみたいと思っています。
参照
Vue.js公式サイト
CentOSにインストールしたMySQLを削除する
CentOS7にMySQL8をインストールして初期パスワードを変更する
MySQL 8.0 を CentOS 8.1 にインストールする手順
mysqlモジュールでDB操作
ブラウザからWebAPIと非同期通信を行う
Vue.js+Express+Socket.IO 最小構成でリアルタイムチャットを作成する