こんにちは、だあしょ(@daasho_blog)です。
Webエンジニアに転職して約1年。
日々新しい知識のキャッチアップに忙しい毎日です。
今回は、Java(Springを使います) + Vue + MySqlを使ったアプリケーションの開発環境を作ってみようと思います。
おおまかにまとめると、必要なことは以下の3点です。
- データベースの用意
- アプリケーションの作成
- フロント、バックエンド両方でCORS接続できるようにする ←これが大事!
結論、上記の3番ができれば、実装自体は難しいものではありませんでした!!
このような方には、この記事は参考になると思います。
私のキャッチアップ中のメモのようなものですが、どなたかの役に立てれば幸いです。
以下のサイトを参考にしました。
開発環境
今回の開発環境は以下の通りです。
IDE | Spring Tool Suite 4(通称:STS) |
OS | Windows 10 |
フロントエンド | Vue 2 |
バックエンド | Java 11 |
フレームワーク | Spring Boot(Spring Data JPA) |
データベース | MySQL |
ビルドツール | Maven |
IDEについてはインストールされていることが前提です。
OSはWindowsで話を進めて行きます。
Macの方はごめんなさい。気が向いたら追記します。
Javaは他の開発言語と比較すると構文がしっかりしているので、初学者の私にとって基礎を固めるのにもってこいだね。
また、APIやライブラリの多さやセキュリティの高さもあるので、将来このプログラムを拡大させていくのに役立つと思ったので選択しました!
Vueを選んだ理由はモダンな技術で手軽に始められること。
大規模な開発には不安があるけど、SPA開発で力を発揮してくれるものです!
あえて最新のVue 3ではなくVue2にしたのは、Vuetifyへの対応を見据えたためです。
新規プロジェクトを作成
まずは新規プロジェクトを作成します。
STSを開き、画面上部のタブから以下を開きます。
[ファイル] > [新規] > [Spring スタータープロジェクト(Spring initializr)]
プロジェクトの名前を決める
プロジェクトの名前を決めます。
今回は「sample_project」にしたいと思います。
以下の画像の赤枠部分に、プロジェクト名を入力します。
入力が完了したら、【次へ】を押します。
プロジェクト依存関係を選択する
以下の画像のページが出てくるので、ここでプロジェクトの依存関係を決めます。
ここで選択しておくと、後で設定ファイル上に手動で書き込む手間が省けます。
今回は以下の4つを選択します。
- Spring Boot DevTools
- Spring Data JPA
- MySQL Driver
- Spring Web
過去にプロジェクトを作成し、これらのツールを使ったことがある場合は赤枠から選べます。
初めて使う場合は、黄色枠内の検索バーで検索するか、ツリーを開いて対象のものを探します。
選択が終わったら【完了】を押します。
【次へ】も押せるようになっていますが、特に変更することはありません。
【次へ】を押した後の画面で【完了】を押してもやっていることは同じです。
【完了】を押すとプロジェクトが作成されます。
ツリーの構造は以下のようになっていると思います。
プロジェクトが作成されるまで、若干時間がかかる場合があります。
ここまでで、新規プロジェクトの作成は完了です。
作成したプロジェクトをMySqlと接続する
データベースを作成する
まずはデータベースを作成します。
Workbenchから作る場合
MySqlのGUIツールであるWorkbenchを開きます。
接続するインスタンスを選択します。
初めての場合は設定をする必要があるかもしれませんが、今回のメインはこれではないため、ここでは触れません。
インスタンスを開いたら、以下のどちらかの方法でスキーマを作成します。
- 画面上部のデータベースの左下に+マークがついたアイコン(カーソルを乗せると「Create a new schema in the connected server」と出る)を押す
- 【SCHEMAS】のタブの余白で右クリックを押し、「Create Schema…」を選択する
以下の画像の画面が表示されるので、【Name:】にスキーマ名を入力し、【Apply】を押します。
次の画面ではスキーマを作成するSQLが表示されるので、また【Apply】を押します。
スキーマの作成に成功すると、成功したことを知らせる画面が出るので、【Finnish】を押します。
最初の画面に戻ると、スキーマが作成されていることが確認できます。
表示されていない場合は【SCHEMAS】のタブの余白で右クリックを押し、「Refresh All」を選択して情報を更新してみてください。
現時点でテーブルの中身は作成していないため、テーブルの内部を確認することはできません。
コマンドから作る場合
MySqlのコマンドラインを開きます。
ユーザー名やパスワードなど、画面に従って必要な情報を入力し、コマンドラインと個人のデータベースを接続します。
接続したら、以下のコマンドを入力します。
create database <スキーマ名>;
最後の「;(セミコロン)」を忘れがちです。気を付けましょう。
今回はデータベースの名前を「sample_database」にするので、<スキーマ名>の部分を変更します。
コマンドを作成後、Enterキーを押し、以下のようになれば成功です。
mysql> create database sample_database;
Query OK, 1 row affected (0.03 sec)
この時点でWorkbenchに入ると、スキーマが作成されていることが確認できます。
表示されていない場合は【SCHEMAS】のタブの余白で右クリックを押し、「Refresh All」を選択して情報を更新してみてください。
現時点でテーブルの中身は作成していないため、テーブルの内部を確認することはできません。
ここまでで、データベースの最低限の作成は完了です。
application.propertiesを編集する
STSに戻り、先ほど作成した新規プロジェクト内の「application.properties」を開き、以下を入力します。
spring.datasource.url= jdbc:mysql://localhost:3306/<スキーマ名>
spring.datasource.username= root
spring.datasource.password= password
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
<スキーマ名>の部分に、先ほど作成したスキーマ名を入力します。
今回は「sample_database」です。
「spring.datasource.username=」の後の「root」の部分に、MySqlで設定しているユーザー名を入力します。
「spring.datasource.password=」の後の「password」の部分に、MySqlで設定しているパスワードを入力します。
入力が完了したらファイルを保存します。
これでデータベースとの接続が完了しました。
JPAを利用してテーブルを自動生成する
先ほど作ったテーブルにカラムを追加します。
今回はJPAを利用して、Javaプロジェクト上からカラムを自動生成してみます。
エンティティを作る
データベースのカラムを設定するエンティティクラスを作成します。
パッケージ作成
クラスを保存するパッケージを作成します。
[src/main/java] > [com.example]の上で右クリックを押し、[新規] > [パッケージ]の順で進みます。
パッケージを作成する画面が出るので、名前を「com.example.model」にします。
入力したら【完了】を押します。
[src/main/java] > [com.example]の下に「model」パッケージが作成されたことが確認できます。
クラス作成
先ほど作成した「model」パッケージの下にエンティティクラスを作成します。
[model]上で右クリックを押し、[新規] > [クラス]の順で進みます。
クラスの名前を決めます。今回は「SampleProject」とします。
他に変更するところは特にありません。
名前を入力したら、【完了】を押します。
【完了】押すと先ほどの「model」パッケージの下に「SampleProject」クラスが作成されていることが確認できます。
SampleProject.javaを編集する
「SampleProject.java」クラスの中でテーブルのカラムを指定していきます。
クラスの中身は以下を参考にして下さい。
@Entity
@Table(name = "sample_project")
public class SampleProject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_name", nullable = false, length = 50)
private String userName;
@Column
private String hobby;
}
各アノテーション(@)にはそれぞれ以下の意味があります。
アノテーション | 意味 |
@Entity | このクラスがエンティティということが認識される。 |
@Table | 引数に任意の名前を渡すことでテーブル名を指定することができる。 省略可。その場合はクラス名がテーブル名となる。 |
@Id | プライマリキーを指定する。 |
@GeneratedValue | プライマリキーカラムにユニークな値を自動で生成、付与する。 引数の「strategy = 」以降は、それぞれ以下の意味を持つ。 ・GenerationType.AUTO :データベースごとに最も適切な手順を選択して、プライマリキー値を生成 ・GenerationType.IDENTITY :データベースのidentity列を利用して、プライマリキー値を生成 ・GenerationType.SEQUENCE :データベースのシーケンスオブジェクトを使用して、プライマリキー値を生成 ・GenerationType.TABLE :プライマリキー値を保持しておくためのテーブルを使用して、プライマリキー値を生成 |
@Column | フィールド上のカラム名を指定する。 引数の指定はそれぞれ以下の通り。 ・name :カラム名を任意に指定 ・nullable :NULLを許可するかどうかを指定 ・length :カラムに入力する文字数/桁数の最大値を指定 |
また、Getter/Setterも後ほど使うので、この時点で作成しておきましょう。
「private String hobby;」の下に配置すると良いと思います。
ファイル内の余白で右クリック > [ソース] > [getter および setter の生成(R)…] > [全て選択] > [生成]
ここまで作成したら、ファイルを保存します。
Springプロジェクトを実行する
この時点でSpringプロジェクトを実行すると、SampleProjectクラスで指定したカラムが自動でテーブルに格納されます。
現在のプロジェクトのツリー最上部である[sample_project]上で右クリックを押し、 [実行] > [Spring Boot アプリケーション]を選択します。
すると、コンソールが動き出します。
コンソールの最後に以下の文字が出ると成功です。
Started SampleProjectApplication in <〇〇〇> seconds
<〇〇〇>の部分は実行までに要した時間が表示されます。
カラムが作成されていることを確認する
Workbenchの方に戻ります。
スキーマを作成した時と同様、【SCHEMAS】のタブの余白で右クリックを押し、「Refresh All」を選択して情報を更新します。
すると、先ほど作成したスキーマの「Tables」部分が展開できるようになっています。
「Tables」を展開すると、先ほどエンティティクラスの中の「@Table(name = “〇〇”)」で指定したテーブルが作成されています。
テーブル名の上にカーソルを乗せると、右側にアイコンが3つ出てきます。
テーブルの中身を確認するには、一番右側の表のようなアイコンを押します。
テーブルの中身を実際に確認してみると、先ほどエンティティクラスで定義したカラムが作成されていることがわかります。
これで、データベースとの接続はひと通り完了です。
あとは機能の追加に応じて設定を増やしていきます。
Repository・Controllerを作る
画面に表示する情報をデータベースから取得するため、RepositoryとControllerを作ります。
Repositoryを作る
インターフェースの作成
先ほど作った「model」パッケージと同じ階層に「repository」パッケージを作ります。
[src/main/java] > [com.example]の上にカーソルを乗せ右クリック > [新規] > [パッケージ]
今回の名前は「com.example.repository」にします。
【完了】を押すと「repository」パッケージが作成されるので、その直下にインターフェースを作成します。
[repository]の上にカーソルを乗せ右クリック > [新規] > [インターフェース]
今回の名前は「SampleProjectRepository」にします。
【完了】を押すとインターフェースが作成されます。
インターフェースを編集する
作成したインターフェースに処理を追加します。
public interface SampleProjectRepository extends JpaRepository<SampleProject, Integer> {
List<SampleProject> findByUserName(String userName);
}
インポートが必要なものは適宜インポートしてください。
上記のように、「JpaRepository」を継承することで、save()やfindById()などのメソッドを実装しなくても使用できるようになります。
各自の方法で検索処理を追加したい場合は、メソッド内に処理を記述します。
今回は「UserName」で検索できるように、findByUserName()メソッドを追加しています。
処理を追加したら、ファイルを保存します。
Controllerを作る
クラスの作成
先ほど作った「repository」パッケージと同じ階層に「controller」パッケージを作ります。
[src/main/java] > [com.example]の上にカーソルを乗せ右クリック > [新規] > [パッケージ]
今回の名前は「com.example.controller」にします。
【完了】を押すと「controller」パッケージが作成されるので、その直下にインターフェースを作成します。
[controller]の上にカーソルを乗せ右クリック > [新規] > [クラス]
今回の名前は「SampleProjectController」にします。
【完了】を押すとクラスが作成されます。
クラスを編集する
作成したクラスに処理を追加します。
今回は簡単な処理として、入力したユーザー名に紐づく趣味の情報を出力するだけのアプリケーションを作成します。
作成するメソッドは以下のとおりです。
インポートが必要なものは適宜インポートしてください。
@CrossOrigin(origins = "http://localhost:8081")
@RestController
@RequestMapping("/")
public class SampleProjectController {
@Autowired
SampleProjectRepository sampleProjectRepository;
@GetMapping("/sample")
public ResponseEntity<List<SampleProject>> getUserInfo(@RequestParam(required = false) String userName) {
List<SampleProject> list = sampleProjectRepository.findByUserName(userName);
return new ResponseEntity<List<SampleProject>>(list, HttpStatus.OK);
}
}
「@CrossOrigin」は、CORSの設定のためのものです。
クライアントサイドとサーバーサイドを別々のマシンで動作させる時、お互いリクエストが受け取れるよう設定しておく必要があります。
今回はSpringはポート「8080」、Vueはポート「8081」で動作します。
そのためSpring側では「8081」のレスポンスが受け取れるように、引数で指定しておきます。
対してVue側では、後で出てきますが、「8080」のレスポンスが受け取れるよう設定します。
@CrossOrigin(origins = "http://localhost:8081")
「@RestController」は、APIサーバー用として使用するときに使うアノテーションです。
そのため、メソッドの戻り値もHTMLのビュー名ではなく、レスポンスボディになります。
@RestController
処理を追加したら、ファイルを保存します。
localhostにアクセスしてみる
ここまでの確認として、「localhost:8080/sample」にアクセスしてみます。
ブラウザを開き、アドレスを入力し、Enterを押します。
「Whitelabel Error Page」などが出なければ成功です。
現時点では、以下の理由から画面には「[]」しか映っていないはずです。
- HTMLのビューを作成していない
- メソッドの戻り値もビューでない
- データベース内に何の情報もない
フロントエンドを作成する
フロントサイドの作成をしていきます。
Vueを立ち上げるにあたり、コマンドから行う必要があります。
私はWindowsユーザーなので、コマンドプロンプトを使用します。
Vueプロジェクトをディレクトリ内に格納する
Vue CLIを使ってプロジェクトを作成していきます。
Vue CLIをインストールする
まずはVue CLIがインストールされているかを確認します。
コマンドプロンプトを開き、以下のコマンドを入力します。
vue –version
以下のようなVueのバージョンが表示されれば、既にインストールされていることになります。
@vue/cli 5.0.8
表示されない場合は、以下のコマンドを入力してインストールします。
npm install -g vue-cli
コマンドを実行後、再度バージョンを確認し、表示されればインストール成功です。
Vueプロジェクトを作成する
コマンドプロンプト上で現在作成しているSpringプロジェクトのディレクトリへ移動します。
移動したら、以下のコマンドを入力します。
vue create <プロジェクト名>
今回のプロジェクト名は「vue-sample」とします。
そのため入力するコマンドは以下になります。
vue create vue-sample
コマンドを実行すると、以下のように選択肢が出てきます。
これは作成するVueのバージョンを「Vue2」と「Vue3」のどちらにするか聞かれています。
「Manually select features」を選択すると、プロジェクトに必要な機能を選択することができます。
今回はVue2かつ機能はデフォルトで作成します。
キーボードの下矢印でカーソルを動かし、「Default ([Vue 2] babel, eslint)」を選択します。
Enterを押すとプロジェクトの作成が始まります。
以下のようになれば成功です。
STSに戻ると、プロジェクトが作成されていることが確認できます。
見当たらない場合はF5キーを押してリフレッシュしてみてください。
作成したプロジェクトを実行してみる
プロジェクトが実行されることを確認します。
コマンドプロンプトでvue-sample直下へ移動します。
以下のコマンドを入力します。
cd vue-sample
移動したら、以下のコマンドを入力します。
npm run serve
Enterを押し、問題なく処理が終了すれば、ブラウザで確認できます。
「localhost:8081」にアクセスしてみます。
以下のページが表示されれば成功です。
この画面は、[vue-sample] > [src] > [App.vue]でVueのロゴマークの表示と全体のスタイルを指定しています。
それ以外の部分は、[vue-sample] > [src] > [components] > [HelloWorld.vue]で定義しています。
定義したファイルを[App.vue]上でHTMLタグを読み込むような形式で呼び出すことで、画面に表示しています。
<script>以下でファイルを呼び出しています。
ビューを作成する
簡単なフォームを作成する
簡単なフォームを用いたビューを作成します。
今回はサンプルのため、細かい見た目には凝りません。
[vue-sample] > [src] > [components]の中に新しくVueファイルを作成します。
[components]の上にカーソルを乗せ右クリック > [新規] > [ファイル]と進みます。
名前に「SearchUser.vue」と入力し、【完了】を押します。
「SearchUser.vue」を開き、とりあえず入力欄とボタンだけ作成します。
<template>
<div>
<input type="text">
<button type="submit">Search</button>
</div>
</template>
ブラウザで確認するには、App.vueを編集します。
先ほども少し触れましたが、これまでは「HelloWorld.vue」というファイルをコンポーネントとして呼び出し、画面に表示していました。
これと同じことを新しく作成したファイルでも実装してみます。
App.vue内の「HelloWorld」の部分を全て、「SearchUser」に変更します。
Vue.jsはファイルを保存するとすぐにブラウザに反映されます。
ブラウザを見ると、Vueのロゴマークの下に簡単なフォームが出現していると思います。
先ほどまでは「HelloWorld.vue」から取得していたビュー情報を「SearchUser.vue」から取得するようにしたためです。
componentを利用すると、このように簡単にビューを変更できるようになります。
Vueのロゴマークを消したい場合は、App.vue内のimgタグを消去してください。
ですが、入力欄だけではなんだか寂しいので、私は残しておきます。。。
入力した文字をフォームの下に出力してみる
コードの全体像は以下の通りです。
inputタグにv-model属性を追加します。
これにより、入力する値が「userName」という変数によって保持されます。
<input type="text" v-model="userName">
buttonタグにクリックアクションを追加します。
@click属性の後にJavascriptで定義したメソッドを指定します。
これにより、ボタンをクリックした時にメソッドを呼び出すことができます。
ここでは、「showCurrentUser()」メソッドを呼び出すことにします。
<button type="submit" @click="showCurrentUser()">Search</button>
v-if属性は一般的なif文と同じような役割をします。
画面に表示する値(=変数:currentUser)がture、つまりcurrentUserに値が入っていれば、その下のdivタグが表示されます。
<div v-if="currentUser">
<div>{{ currentUser }}</div>
</div>
画面にアクセスした時の初期値を定義します。
ここでは全てNULLとしておきます。
data() {
return {
userName: '',
currentUser: '',
};
},
methods:{}内にJavascriptのメソッドを記述していきます。
クリックアクション実行時の処理を追加します。
フォームに入力した値(userName)を、画面に表示する値(currentUser)に代入します。
これによって先ほどのv-if属性がtrueになり、v-if属性以下のdivタグが表示されます。
methods: {
showCurrentUser() {
this.currentUser = this.userName
}
}
ファイルを保存し、ブラウザ上のフォームに文字を入力します。
【Search】ボタンを押すと、フォームの下に入力した文字が表示されます。
データベースの情報を出力してみる
これまでと同じ要領で、今度はデータベースに格納した情報を出力してみます。
axiosのインストール
Spring側でHTTP通信として送信しているJSONをVue側でも受け取れるようにします。
「axios(アクシオス)」というライブラリを利用します。
コマンドプロンプトでインストールする必要があるため、一度プログラムを終了します。
以下のコマンドを入力し、実行します。
npm install axios
インストールが完了したら、STSに戻り、[vue-sample] > [src]直下に新規ファイルを作成します。
名前は「http-common.js」とします。
以下のコードを記述します。
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/",
headers: {
"Content-type": "application/json"
}
});
「baseURL:」の部分で、Spring側のホストを指定しています。
これにより、Springから出力されたJSONをVueでも受け取れることになります。
serviceファイルの作成
axiosによってHTTP通信されているものに対する処理を定義します。
[vue-sample] > [src]直下に新規フォルダを作成し、名前を「services」としておきます。
その直下に新規ファイルを作成し、名前を「SampleService.js」としておきます。
以下の処理を追加します。
import http from "../http-common";
class SampleService {
getAll() {
return http.get("/sample");
}
findByUserName(userName) {
return http.get(`/sample?userName=${userName}`);
}
}
export default new SampleService();
http.get()の引数には、Springでマッピングしたパスを指定します。
これにより、例えばJavascriptでgetAll()メソッドを呼び出すと、Springで「/sample」とマッピングされているメソッドの処理を実行します。
findByUserName()メソッドでは、引数としてuserNameをパラメータにして処理を実行できるようにしました。
SearchUser.vueを編集する
SearchUser.vueに処理を追加していきます。
コードの全体は以下の通りです。
buttonタグのクリックアクションのメソッド名を変更しました。
【Search】ボタンを押すと、searchUserInfo()メソッドの処理を実行します。
<button type="submit" @click="searchUserInfo()">Search</button>
検索された情報を出力します。
v-forは一般的なfor文の意味を持ちます。
変数「userInfo」に格納されている情報を取り出し、一つ一つを「(info, i)」の「info」に入れていきます。
その下の 「{{ 〇〇 }}」に囲まれた部分は、文字列として画面に出力するものを入れます。
「info」の中の「userName」と「hobby」をそれぞれバラバラに出力します。
<div v-for="(info, i) in userInfo" :key="i">
ユーザー名:{{ info.userName }}
<br />
趣味:{{ info.hobby }}
</div>
新たな変数「userInfo」を配列型で定義します。
変数「currentUser」はもう使わないので削除しました。
data() {
return {
userInfo: [],
userName: "",
};
},
入力されたユーザー名をから、その人の趣味を検索します。
入力値をパラメーターとしてSpring側と接続し、データベース検索後、検索結果が戻ります。
受け取ったデータを、変数「userInfo」に代入します。
searchUserInfo() {
SampleService.findByUserName(this.userName).then(response => {
this.userInfo = response.data
}).catch(e => {
console.log(e);
});
}
ここまでで、検索用の処理の追加は終了です。
データベースに情報を登録する
ブラウザ上での動作を確認するため、データベースに1件情報を登録してみます。
さくっとWorkbenchでやってしまいます。
各カラムに情報を入力し、【Apply】を押します。
SQLの確認画面が出るので、もう一度【Apply】を押します。
完了画面が出るので、【Finnish】を押します。
ブラウザで動作を確認する
これまでに作成した全てのファイルが保存されていることを確認します。
STS上で「sample_project」のSpring Boot アプリケーションを実行します。
コマンドプロンプトで「vue-sample」を実行します。
ポート「8081」の方にアクセスします。
「8080」の方については後ほど説明します。
アクセスすると、見た目はデータベース接続前と同じ画面が出てきます。
「ユーザー名:Tom、趣味:baseball」という情報を保存したので、入力欄に「Tom」と入力します。
入力したら【Search】ボタンを押してみます。
入力欄の下にデータベースの情報が表示されました。成功です。
作成したプロジェクトをSpringで確認する
作成したVueプロジェクトをSpring(ポート「8080」)で確認してみます。
確認のためには、プログラムをビルドし、ビルドファイルを[src/main/resources]直下に置く必要があります。
package.jsonを編集する
package.jsonを開きます。
以下の赤枠部分を書き換えます。
書き換えた形が以下のとおりです。
この状態でファイルを保存します。
Vueプログラムをビルドする
ファイルを保存したらビルドしてみます。
コマンドプロンプトに戻ります。
プロジェクトが起動したままの場合は、一度終了してください。
終了したら、以下のコマンドを入力します。
npm run build
Enterを押すと、Vueプロジェクトのビルドが始まります。
ビルドに成功しました。
[src/main/resources]のツリーを展開すると、作成されたビルドファイルが格納されているのが確認できます。
ブラウザで動作を確認する
ビルドが完了したらブラウザで動作を確認します。
ここからは「8081」にアクセスした時と同じです。
同じ結果が確認できたら成功です。
まとめ
プログラムの立ち上げから、動作確認までの一連の流れを紹介しました。
改めて流れをまとめておきます。
- Springプロジェクトの立ち上げ
- MySQLと接続
- Vueでフロント画面作成
- CORS接続
- 動作確認
今後としては、VueのRouterを使った画面遷移の実装をしてみようと思います。
今回はデータベース上で情報の登録を行いましたが、画面上でできた方がラクですもんね。
また、体裁などまったく気にしていないため、見た目も無機質なプログラムになっています。
VueのUIフレームワークであるVuetifyを使ってより洗練されたプログラムに仕上げることも目標です。
さらには、開発環境と実行環境で同じ動作ができるかどうかも開発を進めて行く中で考えなければなりません。
やらなきゃいけないことはまだまだたくさんありますね。。。
コメント