使用する開発環境・フレームワークについて

今回は、蔵書管理アプリのフロントエンド部分を作っていこう。フロントエンド部分はJavaScriptフレームワークのVue.jsを用いて作成し、前回設定したAzureストレージにデプロイする。

  • 蔵書管理アプリケーションの概要

    蔵書管理アプリケーションの概要

本稿のサンプルプロジェクトは、次のような開発環境およびフレームワークを利用して作成した。

  • 開発環境: IntelliJ IDEA Ultimate Edition, Vue CLI
  • ベースとなるJavaScriptフレームワーク: Vue.js, Bootstrap
  • Ajax通信: axios

Vue.jsはインタラクティブなWebサイトを作成するためのJavaScriptフレームワークの一種で、特に他のJavaScriptライブラリとの併用が容易なため新規案件で気軽に導入できる点に定評がある。今回はシングルページ・アプリケーションとして作るつもりなので、コアライブラリに加えて、ルーティングを実現するためのVue Routerを使用する。

Vue CLIはVue.js用のコマンドラインツールで、プロジェクトの雛形の作成やビルド、実行などを行うことができる。複数のJavaScriptファイルや設定ファイルから、前処理によって実行可能なJavaScriptファイルを生成する「Webpack」にも対応している。IntelliJ IDEAでは、内部でVue CLIを利用してVue.jsのプロジェクト作成やwebpackによる公開用ファイルのビルドなどを行える。

Spring Bootで作成したバックエンドのWebアプリに対しては、Ajax通信でリクエストを送ってデータを取得したい。今回はAjax通信のためのJavaScriptライブラリであるaxiosを利用して行う。

IntelliJ IDEAでVue.jsを使用する具体的な方法は、JetBrain社によるこちらのドキュメントを参照していただきたい。IntelliJ IDEAを使用しない場合でも、単独でVue CLIを利用すれば作成したコンポーネント群のビルドを行える。

フロントエンドのプログラムてはこの連載の本筋ではないので、解説は最小限に止めるが、本稿で作成したプログラム一式はこのGitHubリポジトリで公開する。ビルド済みのHTML/JapaScriptファイルもdistディレクトリ以下に格納してあるので、バックエンドの実験用であれば自前でビルドせずにこのビルド済みファイルを使うこともできる。

ただし、バックエンドへの接続URLはハードコーディングされてしまっているので、js/app.XXXX.js (XXXXはランダムな文字列) から「https」で検索して、ヒットした箇所を自分の環境用のURLに書き換える必要がある。

フロントエンド・アプリ全体のファイル構成

本稿のサンプルでは、フロントエンドのWebアプリのプロジェクト名を「booklist_web」としており、IntelliJ IDEAでのプロジェクト作成時の設定は次のようにした。

  • IntelliJ IDEAによるプロジェクト作成

    IntelliJ IDEAによるプロジェクト作成

最終的なファイル・ディレクトリ構成は下図のようになっている。

  • booklist_webのファイル・ディレクトリ構成

    booklist_webのファイル・ディレクトリ構成

compomentsディレクトリにある3つの.vueファイルはそれぞれコンポーネントの定義で、ベース・コンポーネントのApp.vueに埋め込まれる形になる。3つのコンポーネント間のルーティングはroutes.jsに定義されている。booklistService.jsには、バックエンドのWeb APIを呼び出すためのAjax通信用メソッドが実装されている。

これらのファイルやスクリプトは最終的にwebpack化されて、distディレクトリに公開用のファイルが生成される。Azureストレージで公開する場合は、このdist以下に生成されたファイルを設置すればよい。

ベース・コンポーネントとルーティングの設定

このWebサイトはシングルページアプリケーションの形になっている。ベースになるのはコンポーネントはApp.vueで、ヘッダ部分にナビゲーション用のメニューがあり、メニュー項目はそれぞれのページへのリンクになる。ページ遷移はVue Routerを使って実現している。UIコンポーネントにはBootstrapを利用した。

App.vue

<template>
  <div id="app">
    <nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-secondary">
      <div class="container">
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navBarToggler" aria-controls="navBarToggler" aria-expanded="false" aria-label="Azure Java WebApplication Sample">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navBarToggler">
          <a class="navbar-brand" href="#/Home">蔵書管理アプリケーション</a>
          <ul class="navbar-nav">
            <li><a class="nav-link"><router-link id="HomeNav" class="text-white" to="/Home">ホーム</router-link></a></li>
            <li><a class="nav-link"><router-link id="BooklistNav" class="text-white" to="/Booklist">書籍リスト</router-link></a></li>
          </ul>
        </div>
      </div>
    </nav>

    <div class="container" role="main" style="margin-top: 80px !important;">
      <router-view></router-view>
    </div>
  </div>
</template>

<style>
  .list-group-item { word-wrap: break-word; }
  #booklist button { margin-left: 5px; }
</style>

main.jsではVueオブジェクトを生成し、Vue Routerによるルーティング定義を設定する。

main.js

import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
import Vue from 'vue'
import VueRouter from 'vue-router';
import App from './App.vue'
import routes from './routes';

Vue.config.productionTip = false
Vue.use(VueRouter);

const router = new VueRouter(routes);

new Vue({
  render: h => h(App),
  router
}).$mount('#app')

実際のルーティング情報はroutes.jsで定義する。ここでは「Home」「Booklist」「BookDatail」という3つのコンポーネントに対してそれぞれパスを割り当ててある。HomeとBooklistはナビゲーションメニューのリンクで移動できる。BookDatailは、Booklistから書籍のIDをパスに渡して移動する想定になっている。

routes.js

import Home from './components/Home';
import Booklist from './components/Booklist';
import BookDetail from './components/BookDetail';

export default {
    routes: [
        {
            name:'Home',
            path: '/Home',
            component: Home
        },
        {
            name:'Booklist',
            path: '/Booklist',
            component: Booklist
        },
        {
            name:'BookDatail',
            path: '/BookDetail/:id',
            component: BookDetail
        }
    ]
}

各コンポーネントの完成図は次のような感じになる。上部メニューの「ホーム」をクリックするとHomeに、「書籍リスト」をクリックするとBooklistに遷移すに。

  • Homeページの例

    Homeページの例

  • Booklistページの例

    Booklistページの例

  • BookDatailページの例

    BookDatailページの例

Ajax通信用のユーティリティ

BooklistとBookDatailでは、それぞれバックエンドのWeb APIを呼び出して書籍の情報を取得したい。booklistService.jsはそのためのユーティリティとなる共通モジュールで、Spring Bootで定義した各エンドポイントにアクセスしてレスンポンスを取得するメソッドを定義する。

booklistService.js

// Web APIのベースURL
//const URL_BASE = 'http://localhost:8080/api/'               // ローカルテスト用
const URL_BASE = 'https://YOUR_APPNAME.azurewebsites.net/api/'    // App Service用
import Vue from 'vue'
import axios from 'axios'

// Vue.js のインスタンス
export default new Vue({
    methods: {
        getItems() {
            return axios.get(URL_BASE + 'booklist')
                .then((res) => {
                    return res.data;
                });
        },
        getItem(id) {
            return axios.get(URL_BASE + 'booklist/search/' + id )
                .then((res) => {
                    return res.data;
                });
        },
        getByTitle(title) {
            return axios.get(URL_BASE + 'booklist/titlesearch/' + title )
                .then((res) => {
                    return res.data;
                });
        },
        addItem(item) {
            return axios.post(URL_BASE + 'booklist/add', item)
                .then((res) => {
                    return res.data;
                });
        },
        saveItem(item) {
            return axios.post(URL_BASE + 'booklist/update', item)
                .then((res) => {
                    return res.data;
                });
        },
        deleteItem(id) {
            return axios.get(URL_BASE + 'booklist/delete/' + id)
                .then((res) => {
                    return res.data;
                });
        }
    }
});

内部的には、axiosのget()またはpost()メソッドで非同期通信によってデータを取得する。URL_BASEには、自分のApp ServiceのURLを設定しよう。なお、サンプルでは単純化のために通信関連のエラー処理は省略している。

次回は、Booklist/BookDatailの各コンポーネントの実装と、Azureストレージを用いた公開方法を解説する。