2019.04.02

Spring BootでWebアプリケーション開発 (1) 環境設定とO/Rマッパー


この記事ではSpring Bootを使って、以下のような簡単な辞書アプリを作成します。

完成図

この連載で出来るようになること

  • Spring Bootを使った簡単なWebアプリケーションのAPIを開発
  • Vue.jsを使ったフロントエンドの開発

この記事でやること

サーバー側の処理の実装

  • プロジェクトの生成
  • 設定ファイルの作成
  • マイグレーションの作成
  • マッパーの実装
  • サービスクラスの実装
  • コントローラーの実装

Spring Bootとは

Spring Bootとは、Java言語を用いたWebアプリケーションフレームワークです。Javaを使ってWebアプリを作成する手間を大きく省いてくれます。最初は、Webアプリを作成するための設定ファイルなどの、雛形を用意してくれるツールだと思っていて大丈夫です。

この記事では扱いませんが、ある程度慣れてきたら、設定ファイルの内容やDIについて勉強すると、さらに出来ることが増えるでしょう。

使用するツール等

  • Spring Boot
    上記で説明したとおり、Webアプリケーションを開発するためのフレームワーク
  • MyBatis
    WebのAPIからDBへアクセスするためのツール(O/Rマッパー)
  • Vue.js
    フロントエンドのUIを開発するためのJavaScriptフレームワーク
  • Element UI
    Vue.jsでフロントを開発する際に、簡単にUIパーツが使えるようになるライブラリ

事前準備

今回バックエンドの開発はEclipseを、フロントエンドの開発はVSCodeを使用します。

フロントエンドはどのエディタを使ってもかまいませんが、バックエンドの開発はEclipseを使用した開発の仕方を紹介するため、Eclipseのインストールを行っておいてください。

また、DBはPostgreSQLを使用します。PostgreSQLのインストールと、アプリケーションで使用するためのテーブルを作成しておいてください。

STSの導入と雛形の作成

STSのインストール

まずはSpringのプロジェクトを扱うために、EclipseにSTSというプラグインを導入します。

  1. Eclipseを起動してヘルプ → Eclipsse マーケットプレースの順に進んでください。
  2. ウィンドウの検索部分に「STS」と入力して出てきたSpring Tool Suiteをインストールしてください。

STSインストール画面

  1. インストールが完了したらEclipseを再起動します。
  2. パースペクティブにSpringが追加されているのでSpringに切り替えてください。
    これでSpring関連の機能を使用することが可能になります。

ここまででSTSの導入が完了です。

プロジェクトの雛形作成

次にSpringプロジェクトの雛形の作成を行います。

パースペクティブをSpringに切り替えた状態でファイル → 新規 → Springスターター・プロジェクトを選択し、以下の設定を行います。

プロジェクト設定画面

設定値は以下の通りになります。

  • 名前:dictionary
    プロジェクトの名前です。こちらを入力すると「成果物」の欄も同時に更新されます。
  • 型:Maven
    今回は特に細かな設定などは行わないのでどちらでも構いませんが、ここではMavenを選択します。
  • 説明:dictionary application
    どのようなプロジェクトか分かる内容を書きます。
  • パッケージ:com.example.dictionary
    ロジックを書いたファイルはここで指定した名前のパッケージ配下に配置することになるので、分かりやすい名前をつけます。

上記の設定が完了したら次へをクリックし、以下の通り依存関係の追加を行います。

依存関係追加画面

追加する依存関係は以下の通りです。

  • Web
    Webアプリ開発のための基本機能である、SpringMVCがインストールされます。
  • JDBC
    データベースを操作するためのモジュールです。
  • PostgreSQL
    PostgreSQLデータベースに接続するためのドライバです。
  • MyBatis
    O/Rマッパーライブラリです。O/Rマッパーについては後述します。
  • Flyway
    データベースの定義を自動的に管理するためのライブラリです。

上記の設定ができたら、完了ボタンをクリックしてください。プロジェクトの雛形が生成されているはずなので、パッケージ・エクスプローラーを確認してみましょう。

設定ファイルの作成

次は設定ファイルの作成をします。

まず先ほど作成したプロジェクトの src/main/resources 配下にある application.properties ファイルの拡張子を .yml に変更してYAMLファイルに変えます。

その後ファイルを開き、以下の設定を書き込みます。

application.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/[データベース名]
    username: [ユーザーネーム]
    password: [パスワード]
    driver-class-name: org.postgresql.Driver
 flyway:
    enabled: true

拡張子は .properties でも問題は無いです。上記の内容を仮にproperties形式で書くと、以下のようになります。

application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/[データベース名]
spring.datasource.username=[ユーザーネーム]
spring.datasource.password=[パスワード]
spring.datasource.driverClassName=org.postgresql.Driver

spring.flyway.enabled=false

ただ、個人的には冗長で書きづらい・読みづらいと感じます。そのため、今回はYAMLファイルに変更しました。

datasource 以下はDB接続の設定が書かれていて、flyway 以下の設定は Flyway を有効にするかの設定となります。

マイグレーション

マイグレーションとはDBのテーブル定義を管理するもので、テーブルの作成や編集の管理を行う仕組みのことです。

まずはテーブル作成用のSQLを書きます。src/main/resources/db/migration 配下にSQLファイルを作成します。ファイル名は以下の通りにしてください。

V1__create_table.sql

Vの後ろの数字はマイグレーション実行の順番を表しています。なので最初は1をその後テーブル定義に変更があった場合は新しく V2__[file_name].sql というようなファイルを作成します。また、分かりづらいですがV1の後ろのアンダースコアは2つです。

ファイルの内容は以下をコピーして貼り付けてください。

V1__create_table.sql
CREATE TABLE WORD (
    word_id SERIAL PRIMARY KEY,
    word VARCHAR(100) NOT NULL,
    field_id INTEGER  NOT NULL,
    word_desc VARCHAR(1000) NOT NULL
);

CREATE TABLE FIELD (
    field_id SERIAL PRIMARY KEY,
    field_name VARCHAR(10) NOT NULL,
    field_genre VARCHAR(10) NOT NULL
);

このSQL文は、以下のようなテーブルを作成するためのものです。

  • wordテーブル (単語テーブル)
物理名 論理名 制約
word_id 単語ID SERIAL PRIMARY KEY
word 単語 VARCHAR(100) NOT NULL
field_id 分野ID INTEGER NOT NULL
word_desc 説明 VARCHAR(10) NOT NULL
  • fieldテーブル (分野テーブル)
物理名 論理名 制約
field_id 分野ID SERIAL PRIMARY KEY
field_name 分野名 VARCHAR(10) NOT NULL
field_genre 分野大区分 VARCHAR(10) NOT NULL

ただ、SQL文を書いたところでテーブルが作成されるわけではありません。実際にテーブルが作成されるのは、アプリを実行した時なので、また後で確認しましょう。

O/Rマッパー

O/Rマッパーとは、Object-Relationalマッピングを行うライブラリです。O/Rマッパーを使用することで、リレーショナルデータベースに対する検索や更新などの操作を、Javaと同じオブジェクト指向で記述できます。

今回はO/Rマッパーとして、雛形を生成するときに追加したMyBatisを使います。

ドメインクラス

まずはDBから取得したデータを格納するためのドメインクラスを作成します。

src/main/java 配下に com.example.dictionary.domain パッケージを用意し、その中にWord.javaField.java を作成します。

Word.java
package com.example.dictionary.domain;

/*
 * 単語のドメインクラス
 */
public class Word {

    /** 単語ID */
    private int wordId;

    /** 単語 */
    private String word;

    /** 分野ID */
    private int fieldId;

    /** 説明 */
    private String wordDesc;

    public int getWordId() {
        return wordId;
    }
    public void setWordId(int wordId) {
        this.wordId = wordId;
    }
    public String getWord() {
        return word;
    }
    public void setWord(String word) {
        this.word = word;
    }
    public int getFieldId() {
        return fieldId;
    }
    public void setFieldId(int fieldId) {
        this.fieldId = fieldId;
    }
    public String getWordDesc() {
        return wordDesc;
    }
    public void setWordDesc(String wordDesc) {
        this.wordDesc = wordDesc;
    }
}
Field.java
package com.example.dictionary.domain;

/*
 * 分野のドメインクラス
 */
public class Field {

    /** 分野ID */
    private int fieldId;

    /** 分野名 */
    private String fieldName;

    /** 分野大項目 */
    private String fieldGenre;

    public int getFieldId() {
        return fieldId;
    }
    public void setFieldId(int fieldId) {
        this.fieldId = fieldId;
    }
    public String getFieldName() {
        return fieldName;
    }
    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
    public String getFieldGenre() {
        return fieldGenre;
    }
    public void setFieldGenre(String fieldGenre) {
        this.fieldGenre = fieldGenre;
    }
}

これらのクラスは、テーブルのカラムに対応するフィールドおよび、それらのフィールドについてのゲッター、セッターを持っています。

マッパーインターフェース

次にJava側からDBを操作するためのインターフェースを作成します。

src/main/java 配下に com.example.dictionary.mappers パッケージを用意してWordMapper.javaFieldMapper.java を作成します。

WordMapper.java
package com.example.dictionary.mappers;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.dictionary.domain.Word;

@Mapper
public interface WordMapper {

    /**
     * すべての単語を取得する
     *
     * @return 単語リスト
     */
    public List<Word> findAll();
}
FieldMapper.java
package com.example.dictionary.mappers;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.dictionary.domain.Field;

@Mapper
public interface FieldMapper {

    /**
     * すべての分野を取得する
     *
     * @return 分野リスト
     */
    public List<Field> findAll();
}

これらのクラスには、各テーブル内のレコードをすべて取得するメソッドが定義されています。

戻り値は対象のテーブルドメインクラスのリストとなります。このメソッドを実行した戻り値として、対象テーブルを表すドメインクラスのリストを受け取ることが出来ます。

また、マッパーインターフェースには @Mapper のアノテーションを付与する必要があります。付け忘れないように気をつけましょう。

マッパーインターフェースはインターフェースなので、当然実装クラスが必要になります。ただしMyBatisでは直接実装クラスを作成しません。アプリケーションの起動時に、インターフェースから自動的に実装クラスが作成されます。

XMLマッパー

次に、ドメインクラスとテーブル側の情報の紐づけを定義する XML ファイルを作成します。

src/main/resources 配下に com/example/dictionary/mappers フォルダを作成し、WordMapper.xmlFieldMapper.xml を作成します。

WordMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dictionary.mappers.WordMapper">
    <resultMap type="com.example.dictionary.domain.Word" id="wordResultMap">
        <result property="wordId" column="word_id" />
        <result property="word" column="word" />
        <result property="fieldId" column="field_id" />
        <result property="wordDesc" column="word_desc" />
    </resultMap>
  
    <select id="findAll" resultMap="wordResultMap">
        SELECT * FROM word
    </select>
    
  <select id="findByFieldId" resultMap="wordResultMap">
        SELECT * FROM word WHERE field_id = #{id}
    </select>
</mapper>
FieldMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dictionary.mappers.FieldMapper">
    <resultMap type="com.example.dictionary.domain.Field" id="fieldResultMap">
        <result property="fieldId" column="field_id" />
        <result property="fieldName" column="field_name" />
        <result property="fieldGenre" column="field_genre" />
    </resultMap>
    <select id="findAll" resultMap="fieldResultMap">
        SELECT * FROM field
    </select>
</mapper>

DOCTYPE タグの中身はMyBatisを使用するための記述をします。要するにMyBatisのフレームワークを呼び出す呪文です。各タグの内容は以下のようになります。

mapper要素

属性 意味
namespace 対応するマッパーインターフェースのパッケージ名を記述することで、XMLファイルとJavaのインターフェースを紐付けます。

resultMap要素

DBから取得した内容を、どのドメインクラスのどのフィールドに格納するかを定義します。

属性 意味
type DBから取得したレコードを格納するために、対応するドメインクラスのパスを記述します。
id 一意のIDを割り当てます。ここに割り当てられたIDは後で記述する処理との紐付けに使用します。

result要素

属性 意味
property 対応するドメインのフィールド名を設定します。
column property属性に設定したフィールド名に対応するDB側のカラム名を設定します。

select要素

select要素内にはSQL文を記述します。このSQLは、id属性に指定されたメソッド実行時に発行されます。

属性 意味
id マッパーインターフェースに定義したメソッド名を設定します。
resultMap 取得した内容を格納するドメインクラスに紐付いたresultMapに割り振ったIDを設定します。

これでマッパーを使用する準備が完了しました。

次回予告

ここまでで環境構築とO/RマッパーでDB操作する準備が整ったので、次回からビジネスロジックを書いていきます。

今回やったこと

  • プロジェクトの生成
  • 設定ファイルの作成
  • マイグレーションの作成
  • マッパーの実装

次回やること

  • サービスクラスの実装
  • コントローラーの実装

<!-- Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com --><!-- License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->