かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その16 )( H2 Database に Flyway でテーブルを作成する )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その15 )( Flyway のインストール + Spring Security 使用時に H2 Console に接続する + IntelliJ IDEA の Database Tools で in-memory モードの H2 Database に接続する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Tomcat 起動時に Flyway で in-memory モードの H2 Database にテーブルを作成します。
    • Doma-Gen で in-memory モードの H2 Database に作成したテーブルの entity クラス, dao インターフェースを生成します。

参照したサイト・書籍

  1. Spring Boot Flyway Sample
    https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-flyway

目次

  1. Database Tools でテーブルを作成する
  2. Tomcat 起動時に Flyway が実行するよう SQL ファイルを配置する
  3. 動作確認
  4. Doma-Gen で entity クラス, dao インターフェースを生成する
  5. 次回は。。。

手順

Database Tools でテーブルを作成する

IntelliJ IDEA の Database Tools でテーブルを作成して SQL を生成するのがお手軽なので、最初に Database Tools で今回使うテーブルを作成します。

in-memory モードの H2 Database に接続する必要があるので、Tomcat を起動します。

Database Tools で PUBLIC スキーマを選択してコンテキストメニューを表示した後、「New」-「Table」を選択します。

f:id:ksby:20170822003640p:plain

「Create New Table」ダイアログが表示されるので、カラムを追加します。

f:id:ksby:20170822005521p:plain

ダイアログの下の「SQL Script」に生成された SQL は以下のようになります。

CREATE TABLE INQUIRY_DATA
(
    id INT AUTO_INCREMENT PRIMARY KEY,
    lastname VARCHAR(20) NOT NULL,
    firstname VARCHAR(20) NOT NULL,
    lastkana VARCHAR(20) NOT NULL,
    firstkana VARCHAR(20) NOT NULL,
    sex VARCHAR(1) NOT NULL,
    age INT NOT NULL,
    job VARCHAR(1),
    zipcode1 VARCHAR(3) NOT NULL,
    zipcode2 VARCHAR(4) NOT NULL,
    address VARCHAR(256) NOT NULL,
    tel1 VARCHAR(5),
    tel2 VARCHAR(4),
    tel3 VARCHAR(4),
    email VARCHAR(256),
    type1 VARCHAR(1) NOT NULL,
    type2 VARCHAR(1),
    inquiry TEXT NOT NULL,
    survey VARCHAR(1) NOT NULL,
    update_date DATETIME NOT NULL
);

「Execute」ボタンをクリックするとテーブルが作成されて、Database Tools 上に INQUIRY_DATA テーブルが表示されます。

f:id:ksby:20170822010045p:plain

Tomcat 起動時に Flyway が実行するよう SQL ファイルを配置する

src/main/resources の下に db/migration ディレクトリを作成します。

src/main/resources/db/migration の下に V1__init.sql を新規作成し、上で記述した SQL をそのままコピー&ペーストします。

また IntelliJ IDEA のエディタ上に「Change dialect to…」リンクが表示されますのでクリックして、

f:id:ksby:20170822010851p:plain

SQL Dialects」ダイアログが表示されたら「Project SQL Dialect」で「H2」を選択して「OK」ボタンをクリックします。

f:id:ksby:20170822011101p:plain

Project Tool Window では以下のようなディレクトリ構成になります。

f:id:ksby:20170822015349p:plain

動作確認

Tomcat 起動時に INQUIRY_DATA テーブルが作成されるか確認します。

Tomcat を再起動するとコンソールに CREATE TABLE INQUIRY_DATA 文が出力されて、

f:id:ksby:20170822011940p:plain

Database Tools を更新すると INQUIRY_DATA テーブルが表示されました。問題なく作成されています。

f:id:ksby:20170822012928p:plain

Doma-Gen で entity クラス, dao インターフェースを生成する

build.gradle の domaGen タスクを変更し、Tomcat を起動した状態で entity クラス, dao インターフェースを生成します。

build.gradle を以下のように変更します。

dependencies {
    ..........

    // for Doma
    compile("org.seasar.doma:doma:${domaVersion}")
    domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}")
    domaGenRuntime("com.h2database:h2:1.4.192")

    ..........
}

// for Doma-Gen
task domaGen {
    doLast {
        // まず変更が必要なもの
        def rootPackageName = 'ksbysample.webapp.bootnpmgeb'
        def daoPackagePath = 'src/main/java/ksbysample/webapp/bootnpmgeb/dao'
        def dbUrl = 'jdbc:h2:tcp://localhost:9092/mem:bootnpmgebdb'
        def dbUser = 'sa'
        def dbPassword = ''
        def tableNamePattern = 'INQUIRY_DATA'
        // おそらく変更不要なもの
        def importOfComponentAndAutowiredDomaConfig = "${rootPackageName}.util.doma.ComponentAndAutowiredDomaConfig"
        def workDirPath = 'work'
        def workDaoDirPath = "${workDirPath}/dao"

        ..........
  • dependencies に domaGenRuntime("com.h2database:h2:1.4.192") を追加します。
  • domaGen タスクの以下の点を変更します。
    • dbUrljdbc:h2:mem:bootnpmgebdbjdbc:h2:tcp://localhost:9092/mem:bootnpmgebdb に変更します。
    • tableNamePattern.*INQUIRY_DATA に変更します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

更新が終わったら Gradle Tool Window から domaGen タスクを実行します。"BUILD SUCCESSFUL" が表示されました。

f:id:ksby:20170822014140p:plain

Project Tool Window を見ると InquiryDataDao インターフェース、InquiryData クラスが作成されています。

f:id:ksby:20170822014456p:plain

生成されたソースは以下の通りです。TEXT 型にした inquiry カラムが Clob になっていますね。H2 Database の Data Types を見ると、たしかに TEXT 型は CLOB の1種類でした。

■ksbysample.webapp.bootnpmgeb.dao.InquiryDataDao

package ksbysample.webapp.bootnpmgeb.dao;

import ksbysample.webapp.bootnpmgeb.entity.InquiryData;
import ksbysample.webapp.bootnpmgeb.util.doma.ComponentAndAutowiredDomaConfig;
import org.seasar.doma.Dao;
import org.seasar.doma.Delete;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.Update;

/**
 */
@Dao
@ComponentAndAutowiredDomaConfig
public interface InquiryDataDao {

    /**
     * @param id
     * @return the InquiryData entity
     */
    @Select
    InquiryData selectById(Integer id);

    /**
     * @param entity
     * @return affected rows
     */
    @Insert
    int insert(InquiryData entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Update
    int update(InquiryData entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Delete
    int delete(InquiryData entity);
}

■ksbysample.webapp.bootnpmgeb.entity.InquiryData

package ksbysample.webapp.bootnpmgeb.entity;

import java.sql.Clob;
import java.time.LocalDateTime;
import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

/**
 * 
 */
@Entity
@Table(name = "INQUIRY_DATA")
public class InquiryData {

    /**  */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    Integer id;

    /**  */
    @Column(name = "LASTNAME")
    String lastname;

    /**  */
    @Column(name = "FIRSTNAME")
    String firstname;

    /**  */
    @Column(name = "LASTKANA")
    String lastkana;

    /**  */
    @Column(name = "FIRSTKANA")
    String firstkana;

    /**  */
    @Column(name = "SEX")
    String sex;

    /**  */
    @Column(name = "AGE")
    Integer age;

    /**  */
    @Column(name = "JOB")
    String job;

    /**  */
    @Column(name = "ZIPCODE1")
    String zipcode1;

    /**  */
    @Column(name = "ZIPCODE2")
    String zipcode2;

    /**  */
    @Column(name = "ADDRESS")
    String address;

    /**  */
    @Column(name = "TEL1")
    String tel1;

    /**  */
    @Column(name = "TEL2")
    String tel2;

    /**  */
    @Column(name = "TEL3")
    String tel3;

    /**  */
    @Column(name = "EMAIL")
    String email;

    /**  */
    @Column(name = "TYPE1")
    String type1;

    /**  */
    @Column(name = "TYPE2")
    String type2;

    /**  */
    @Column(name = "INQUIRY")
    Clob inquiry;

    /**  */
    @Column(name = "SURVEY")
    String survey;

    /**  */
    @Column(name = "UPDATE_DATE")
    LocalDateTime updateDate;

    /** 
     * Returns the id.
     * 
     * @return the id
     */
    public Integer getId() {
        return id;
    }

    /** 
     * Sets the id.
     * 
     * @param id the id
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /** 
     * Returns the lastname.
     * 
     * @return the lastname
     */
    public String getLastname() {
        return lastname;
    }

    /** 
     * Sets the lastname.
     * 
     * @param lastname the lastname
     */
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    /** 
     * Returns the firstname.
     * 
     * @return the firstname
     */
    public String getFirstname() {
        return firstname;
    }

    /** 
     * Sets the firstname.
     * 
     * @param firstname the firstname
     */
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    /** 
     * Returns the lastkana.
     * 
     * @return the lastkana
     */
    public String getLastkana() {
        return lastkana;
    }

    /** 
     * Sets the lastkana.
     * 
     * @param lastkana the lastkana
     */
    public void setLastkana(String lastkana) {
        this.lastkana = lastkana;
    }

    /** 
     * Returns the firstkana.
     * 
     * @return the firstkana
     */
    public String getFirstkana() {
        return firstkana;
    }

    /** 
     * Sets the firstkana.
     * 
     * @param firstkana the firstkana
     */
    public void setFirstkana(String firstkana) {
        this.firstkana = firstkana;
    }

    /** 
     * Returns the sex.
     * 
     * @return the sex
     */
    public String getSex() {
        return sex;
    }

    /** 
     * Sets the sex.
     * 
     * @param sex the sex
     */
    public void setSex(String sex) {
        this.sex = sex;
    }

    /** 
     * Returns the age.
     * 
     * @return the age
     */
    public Integer getAge() {
        return age;
    }

    /** 
     * Sets the age.
     * 
     * @param age the age
     */
    public void setAge(Integer age) {
        this.age = age;
    }

    /** 
     * Returns the job.
     * 
     * @return the job
     */
    public String getJob() {
        return job;
    }

    /** 
     * Sets the job.
     * 
     * @param job the job
     */
    public void setJob(String job) {
        this.job = job;
    }

    /** 
     * Returns the zipcode1.
     * 
     * @return the zipcode1
     */
    public String getZipcode1() {
        return zipcode1;
    }

    /** 
     * Sets the zipcode1.
     * 
     * @param zipcode1 the zipcode1
     */
    public void setZipcode1(String zipcode1) {
        this.zipcode1 = zipcode1;
    }

    /** 
     * Returns the zipcode2.
     * 
     * @return the zipcode2
     */
    public String getZipcode2() {
        return zipcode2;
    }

    /** 
     * Sets the zipcode2.
     * 
     * @param zipcode2 the zipcode2
     */
    public void setZipcode2(String zipcode2) {
        this.zipcode2 = zipcode2;
    }

    /** 
     * Returns the address.
     * 
     * @return the address
     */
    public String getAddress() {
        return address;
    }

    /** 
     * Sets the address.
     * 
     * @param address the address
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /** 
     * Returns the tel1.
     * 
     * @return the tel1
     */
    public String getTel1() {
        return tel1;
    }

    /** 
     * Sets the tel1.
     * 
     * @param tel1 the tel1
     */
    public void setTel1(String tel1) {
        this.tel1 = tel1;
    }

    /** 
     * Returns the tel2.
     * 
     * @return the tel2
     */
    public String getTel2() {
        return tel2;
    }

    /** 
     * Sets the tel2.
     * 
     * @param tel2 the tel2
     */
    public void setTel2(String tel2) {
        this.tel2 = tel2;
    }

    /** 
     * Returns the tel3.
     * 
     * @return the tel3
     */
    public String getTel3() {
        return tel3;
    }

    /** 
     * Sets the tel3.
     * 
     * @param tel3 the tel3
     */
    public void setTel3(String tel3) {
        this.tel3 = tel3;
    }

    /** 
     * Returns the email.
     * 
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /** 
     * Sets the email.
     * 
     * @param email the email
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /** 
     * Returns the type1.
     * 
     * @return the type1
     */
    public String getType1() {
        return type1;
    }

    /** 
     * Sets the type1.
     * 
     * @param type1 the type1
     */
    public void setType1(String type1) {
        this.type1 = type1;
    }

    /** 
     * Returns the type2.
     * 
     * @return the type2
     */
    public String getType2() {
        return type2;
    }

    /** 
     * Sets the type2.
     * 
     * @param type2 the type2
     */
    public void setType2(String type2) {
        this.type2 = type2;
    }

    /** 
     * Returns the inquiry.
     * 
     * @return the inquiry
     */
    public Clob getInquiry() {
        return inquiry;
    }

    /** 
     * Sets the inquiry.
     * 
     * @param inquiry the inquiry
     */
    public void setInquiry(Clob inquiry) {
        this.inquiry = inquiry;
    }

    /** 
     * Returns the survey.
     * 
     * @return the survey
     */
    public String getSurvey() {
        return survey;
    }

    /** 
     * Sets the survey.
     * 
     * @param survey the survey
     */
    public void setSurvey(String survey) {
        this.survey = survey;
    }

    /** 
     * Returns the updateDate.
     * 
     * @return the updateDate
     */
    public LocalDateTime getUpdateDate() {
        return updateDate;
    }

    /** 
     * Sets the updateDate.
     * 
     * @param updateDate the updateDate
     */
    public void setUpdateDate(LocalDateTime updateDate) {
        this.updateDate = updateDate;
    }
}

次回は。。。

入力画面1~3を順に作成します。

履歴

2017/08/22
初版発行。