Help us understand the problem. What is going on with this article?

Doma2+Spring5+Camel2 環境構築・サンプルプログラム(メモ)

More than 1 year has passed since last update.

はじめに

Doma2+Spring5+Camel2での環境構築とサンプルプログラムのメモです。
基本は以下のページを参考に構築しています。

はじめよう! (Eclipse)
https://doma.readthedocs.io/en/2.20.0/getting-started-eclipse/

今回の目的はDoma2のお勉強。
Doma2は2way SQLやJRE 以外のライブラリへの依存がないことが特徴のORマッパーです。
他に有名なORマッパー(MyBatis, Hibernate)はあるのですが、重厚長大で学習コストが高いので今回Doma2を試してみます。

環境

使用したライブラリ・フレームワーク・ミドルウェア・IDEは以下のとおり。

  • Doma 2.24.0
  • Oracle JDK8
  • Spring 5
  • Apache Camel 2.23.0
  • PostgreSQL 9.6
  • Pleiades 4.8.0(Photon)

環境構築

JDK8をインストール

JDK8をインストールしましょう(省略)
※Eclipse内蔵のJavaでも良いのですが、一応インストールし後でEclipseに設定しておきます。

Pleiades(日本語化Eclipse)をインストール

少し古いですが、以下のURLから「Photon (4.8.0) Windows 64bit Full Java」をダウンロードし、Cドライブ直下に展開。

http://mergedoc.osdn.jp/

image.png

Eclipse プラグイン Doma Tools のインストール

Domaを使う上で便利なEclipse用プラグイン「Doma Tools」をインストールします。

まずは、Eclipseを起動して「ヘルプ」-「新規ソフトウェアのインストール」を選択します。

image.png

「インストール」ダイアログが表示されるので、「作業対象」に以下のURLを入力して「追加」ボタンを押します。

image.png

「リポジトリーの追加」ダイアログが表示されるので、ここでは「Doma」(任意)と入力して、「追加」ボタンを押します。

image.png

「Doma Tools」にチェックを入れて「次へ」ボタンを押します。

image.png

「次へ」ボタンを押します。

image.png

「使用条件の条項に同意します」を選択し、「完了」ボタンを押します。

image.png

Eclipseプロジェクト作成

EclipseでMavenプロジェクトを作成します。(手順省略)
プロジェクト名はとりあえず、「domasimple」にしました。

pom.xmlにDoma2を追加します。他のライブラリは(それほど意味はありませんが)後で追加します。

    <dependencies>
        <dependency>
            <groupId>org.seasar.doma</groupId>
            <artifactId>doma</artifactId>
            <version>2.24.0</version>
        </dependency>
    </dependencies>

以下のURLを参考にプロジェクトの設定を行います。

Doma ビルド
https://doma.readthedocs.io/en/2.20.0/build/

domasimpleプロジェクトのプロパティーで、「Javaコンパイラー」-「注釈処理」を選択し、以下のように設定します。

  • 「プロジェクト固有の設定を可能にする」にチェックを入れる
  • 「注釈処理を使用可能にする」にチェックを入れる

image.png

「Javaコンパイラー」-「注釈処理」-「ファクトリー・パス」を選択し、以下のように「doma-2.24.0.jar」を追加します。

image.png

サンプルプログラムの作成

Insert/Update/Select/Deleteを実行するだけのサンプルプログラムを作成します。
一通りの動きを確認するためだけなので、CRUD操作するデータは固定にしています。

ファイルの構成は以下のとおり。

>tree /F
│  pom.xml
├─src
│  ├─main
│  │  ├─java
│  │  │  └─example
│  │  │      └─doma
│  │  │          │  AppConfig.java
│  │  │          │  Main.java
│  │  │          │
│  │  │          ├─dao
│  │  │          │      DomaRepository.java
│  │  │          │      EmployeeDao.java
│  │  │          │
│  │  │          ├─entity
│  │  │          │      Employee.java
│  │  │          │
│  │  │          └─processors
│  │  │                  DeleteEmployee.java
│  │  │                  InsertEmployee.java
│  │  │                  SelectEmployee.java
│  │  │                  UpdateEmployee.java
│  │  │
│  │  └─resources
│  │      │  camel-context.xml
│  │      │  log4j2.xml
│  │      │
│  │      └─META-INF
│  │          └─example
│  │              └─doma
│  │                  └─dao
│  │                      └─EmployeeDao
│  │                              selectAll.sql
│  │                              selectById.sql

まず、pom.xmlを以下のように修正する。

    <properties>
        <camel.version>2.23.0</camel.version>
        <log4j2.version>2.8.2</log4j2.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>


        <!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.seasar.doma</groupId>
            <artifactId>doma</artifactId>
            <version>2.24.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.2.5</version>
        </dependency>
    </dependencies>

テーブルを作成する

employeeテーブルをPostgreSQLに作成します。
PostgreSQLの環境構築は省略。

create table employee (
    id serial not null primary key,
    name varchar(255) not null,
    age integer not null, 
    version integer not null);

Entityを作成する

employeeテーブルに対応した、Entityクラスを作成します。
getter/setterは不要です。
@Idで主キーになります。@GeneratedValueで自動生成を指定。

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer id;
    public String name;
    public Integer age;

    @Version
    public Integer version;

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", age=" + age
                + ", version=" + version + "]";
    }
}

DAOインターフェースを作成する

DAOインターフェースを作成します。
実装クラスは自動で生成されるため、作成不要。これは楽だ。
それぞれ、@Select, @Insert, @Update, @Deleteのアノテーションを付与します。
SelectのSQLは自動生成されないため、後でSQLファイルにSQLを書きます。
それ以外のSQLは自動生成なので、ここでインターフェースを定義するだけです。

@Dao
@AnnotateWith(annotations = {
        @Annotation(target = AnnotationTarget.CLASS, type = Repository.class),
        @Annotation(target = AnnotationTarget.CONSTRUCTOR, type = Autowired.class) })
public interface EmployeeDao {

    @Select
    List<Employee> selectAll();

    @Select
    Employee selectById(Integer id);

    @Insert
    int insert(Employee employee);

    @Update
    int update(Employee employee);

    @Delete
    int delete(Employee employee);
}

Domaのコンフィグを作成する

Domaのコンフィグを作成します。

public class AppConfig implements Config {

     private DataSource dataSource;
        private Dialect dialect;
        private SqlFileRepository sqlFileRepository;

        @Override
        public DataSource getDataSource() {
            return new TransactionAwareDataSourceProxy(dataSource);
        }

        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }

        @Override
        public Dialect getDialect() {
            return dialect;
        }

        public void setDialect(Dialect dialect) {
            this.dialect = dialect;
        }

        @Override
        public SqlFileRepository getSqlFileRepository() {
            return sqlFileRepository;
        }

        public void setSqlFileRepository(SqlFileRepository sqlFileRepository) {
            this.sqlFileRepository = sqlFileRepository;
        }
}

Camelのルートを定義する

Camelのルートとデータソース等を定義します。

camel-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://camel.apache.org/schema/spring
          http://camel.apache.org/schema/spring/camel-spring.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/util
          http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="example.doma.*" />

    <bean id="domaConfig"
        class="example.doma.AppConfig">
        <property name="dataSource" ref="dataSource" />
        <property name="dialect" ref="dialect" />
        <property name="sqlFileRepository" ref="sqlFileRepository" />
    </bean>

    <bean id="dialect"
        class="org.seasar.doma.jdbc.dialect.PostgresDialect" />

    <bean id="sqlFileRepository"
        class="org.seasar.doma.jdbc.GreedyCacheSqlFileRepository" />

    <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
        <property name="jdbcUrl" value="jdbc:postgresql://192.168.20.71:5432/testdb" />
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="minimumIdle" value="10" />
        <property name="maximumPoolSize" value="100" />
        <property name="connectionTimeout" value="30000" />
        <property name="idleTimeout" value="600000" />
        <property name="maxLifetime" value="1800000" />
        <property name="username" value="postgres" />
        <property name="password" value="postgres" />
        <property name="connectionInitSql" value="SELECT 1" />
        <property name="autoCommit" value="false" />
        <property name="validationTimeout" value="5000" />
        <property name="registerMbeans" value="true" />
        <property name="poolName" value="testHikariPool" />
    </bean>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
        destroy-method="close">
        <constructor-arg ref="hikariConfig" />
    </bean>

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="insertEmployee" class="example.doma.processors.InsertEmployee" />
    <bean id="updateEmployee" class="example.doma.processors.UpdateEmployee" />
    <bean id="selectEmployee" class="example.doma.processors.SelectEmployee" />
    <bean id="deleteEmployee" class="example.doma.processors.DeleteEmployee" />

    <camelContext
        xmlns="http://camel.apache.org/schema/spring">

        <route>
            <from uri="timer:trigger?repeatCount=1" />
            <transacted />
            <process ref="insertEmployee" />
            <process ref="deleteEmployee" />
            <process ref="updateEmployee" />
            <process ref="selectEmployee" />
        </route>
    </camelContext>
</beans>

ルート中の「」でトランザクションが開始されます。

Camelのプロセッサを作成する

Insert/Update/Select/Deleteを実行するCamelのプロセッサを作成します。
一通りの動きを確認するためだけなので、CRUD操作するデータは固定にしています。

InsertEmployee.java
@Component
public class InsertEmployee implements Processor {

    private Logger logger = LoggerFactory.getLogger(InsertEmployee.class);

    @Autowired
    private EmployeeDao dao;

    @Override
    public void process(Exchange exchange) throws Exception {
        Employee employee = new Employee();
        employee.age = 20;
        employee.name = "hoge";

        dao.insert(employee);
    }
}
DeleteEmployee.java
@Component
public class DeleteEmployee implements Processor {

    private Logger logger = LoggerFactory.getLogger(DeleteEmployee.class);

    @Autowired
    private EmployeeDao dao;

    @Override
    public void process(Exchange exchange) throws Exception {
        List<Employee> list = dao.selectAll();

        Optional<Employee> emp = list.stream().findFirst();

        if (emp.isPresent()) {
            Employee employee = emp.get();
            dao.delete(employee);
        }
    }
}

SelectEmployee.java
@Component
public class SelectEmployee implements Processor {

    private Logger logger = LoggerFactory.getLogger(SelectEmployee.class);

    @Autowired
    private EmployeeDao dao;

    @Override
    public void process(Exchange exchange) throws Exception {
        Employee emp = dao.selectById(11); // がちがち固定!

        logger.info(emp.toString());
    }
}

UpdateEmployee.java
@Component
public class UpdateEmployee implements Processor {

    private Logger logger = LoggerFactory.getLogger(UpdateEmployee.class);

    @Autowired
    private EmployeeDao dao;

    @Override
    public void process(Exchange exchange) throws Exception {
        List<Employee> list = dao.selectAll();

        Optional<Employee> emp = list.stream().findFirst();

        if (emp.isPresent()) {
            Employee employee = emp.get();
            employee.age += 10;
            dao.update(employee);
        }
    }
}

Doma用のSQLファイルを作成する

DAOインターフェースに対応した2つのSELECT文を作成します。
作成先ディレクトリは、DAOインターフェースと対応したディレクトリになります。

 src/main/resources/META-INF/example/doma/dao/EmployeeDao

selectById.sql
select
    /*%expand*/*
from
    employee
where
id = /* id */0
selectAll.sql
select /*%expand*/* from employee order by id

サンプルプログラムを動かす

サンプルプログラムを動かすために以下のメインクラスを作成し実行します。

Main.java
public class Main {

    static Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) throws Exception {
        logger.info("start ");
        try (ClassPathXmlApplicationContext applicationContext =
                  new ClassPathXmlApplicationContext("camel-context.xml")) {
            applicationContext.start();
            Thread.sleep(30000);
        }
    }
}

動かしてみるだけのメモなので雑ですがこれで終わり。今後いろいろ試行して使えるレベルまで学習するつもり。

感想
・Domaの2way SQLは控えめに言って最高。というか、他に楽なORマッパーがない。
・Camelのトランザクション管理は簡単・らくちん。生産性の高さでDomaとも相性良さそう。
・今回は使用しなかったが、Doma-Genも使えばさらに楽に開発できそう。

最後にサンプルプログラムは以下のサンプルプロジェクトを参考にしています。

simple-boilerplate
https://github.com/domaframework/simple-boilerplate/blob/master/src/main/resources/META-INF/boilerplate/dao/AppDao/create.script

mkyz08
SIer&バックエンドエンジニア&日曜プログラマー。 Apache Camel/VoltDB/Oracle/Apache karaf。 基本的に仕事外での自分用のメモ(興味があること)として記事を書いています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away