What's?
Spring Boot+MyBatisな構成を始めてみようかなと思ったので、そのとっかかりとしてMyBatis Generatorを使うように構成してみます。
お題
Spring BootアプリケーションにMyBatisを組み込むわけですが、以下の構成をお題とします。
- ModelおよびMapperはMyBatis Generatorを使って自動生成する
- MyBatis Generatorは、Mavenプラグインとして組み込む
- 生成するMyBatisのMapperは、XML Mapperとする
- Mapperには
@Mapper
アノテーションを付与して、MyBatis Spring Boot Starterに自動検出させる - 使用するデータベースはPostgreSQLとする
テーブルは、以下の定義とします。
create table pokemon (
id serial,
name text,
primary key(id)
);
create table person (
id integer,
last_name text,
first_name text,
primary key(id)
);
環境
今回の環境は、こちら。
$ java --version
openjdk 11.0.14.1 2022-02-08
OpenJDK Runtime Environment (build 11.0.14.1+1-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.14.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)
$ mvn --version
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.14.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-107-generic", arch: "amd64", family: "unix"
PostgreSQLは、14.2を使います。
$ docker container run \
-it \
--rm \
--name postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD=password \
postgres:14.2-bullseye
Spring Bootプロジェクトを作成する
$ curl -s https://start.spring.io/starter.tgz \
-d bootVersion=2.6.6 \
-d javaVersion=11 \
-d name=spring-boot-mybatis-generator-demo \
-d groupId=com.example \
-d artifactId=com.example \
-d version=0.0.1-SNAPSHOT \
-d packageName=com.example.spring.mybatis \
-d dependencies=mybatis,postgresql \
-d baseDir=spring-boot-mybatis-generator-demo | tar zxvf -
プロジェクト内に移動。
$ cd spring-boot-mybatis-generator-demo
自動生成された依存関係やプラグインの設定は、こちら。
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
データベース接続設定のみ加えておきます。
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=password
プロジェクトにMyBatis Generatorを追加する
pom.xml
に、MyBatis Generatorを組み込みます。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<configurationFile>${project.basedir}/src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<includeAllDependencies>true</includeAllDependencies>
</configuration>
</plugin>
</plugins>
</build>
ドキュメントは、こちらですね。
configurationFile
はデフォルト値と同じですが、MyBatis Generatorの設定ファイルを明示する意味で書いています。
overwrite
をtrue
として自動生成結果の上書きを可能にし、includeAllDependencies
をtrue
にすることでruntime
スコープのPostgreSQL JDBCドライバーの依存関係を参照できるようにしています。
includeAllDependencies
を使うのが嫌な場合は、プラグインのdependency
にPostgreSQLのJDBCドライバーを追加すればよいでしょう。
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<configurationFile>${project.basedir}/src/main/resources/generatorConfig.xml </configurationFile>
<overwrite>true</overwrite>
<!-- <includeAllDependencies>true</includeAllDependencies> -->
</configuration>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
</dependencies>
</plugin>
MyBatis Generatorの設定は、こちら。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="tables" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>
<plugin type="org.mybatis.generator.plugins.MapperAnnotationPlugin"/>
<jdbcConnection
driverClass="org.postgresql.Driver"
connectionURL="jdbc:postgresql://localhost:5432/postgres"
userId="postgres"
password="password"/>
<javaModelGenerator
targetPackage="com.example.spring.mybatis.model"
targetProject="src/main/java"/>
<sqlMapGenerator
targetPackage="com.example.spring.mybatis.mapper"
targetProject="src/main/resources"/>
<javaClientGenerator
type="XMLMAPPER"
targetPackage="com.example.spring.mybatis.mapper"
targetProject="src/main/java"/>
<table tableName="pokemon">
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="person"/>
</context>
</generatorConfiguration>
XML Mapperとするための前提として、targetRuntime
をMyBatis3
とします。
<context id="tables" targetRuntime="MyBatis3">
生成されたMapperに@Mapper
アノテーションを付与するため、org.mybatis.generator.plugins.MapperAnnotationPlugin
プラグインを適用します。
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>
<plugin type="org.mybatis.generator.plugins.MapperAnnotationPlugin"/>
org.mybatis.generator.plugins.EqualsHashCodePlugin
プラグインは、モデルのequals
およびhashCode
を自動生成するようにオマケで追加しています。
Model、Mapper XMLファイル、Mapperの生成。
<javaModelGenerator
targetPackage="com.example.spring.mybatis.model"
targetProject="src/main/java"/>
<sqlMapGenerator
targetPackage="com.example.spring.mybatis.mapper"
targetProject="src/main/resources"/>
<javaClientGenerator
type="XMLMAPPER"
targetPackage="com.example.spring.mybatis.mapper"
targetProject="src/main/java"/>
XMLMAPPER
を指定することで、Mapper XMLを使うようにMapperが生成されます。
あとは、自動生成対象のテーブルを指定。
<table tableName="pokemon">
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="person"/>
generatedKey
は、主キーを自動採番するもの向けですね。
では、実行。
$ mvn mybatis-generator:generate
生成結果。
$ tree src/main/java/com/example/spring/mybatis/{mapper,model} src/main/resources/com/exampl
e/spring/mybatis/mapper
src/main/java/com/example/spring/mybatis/mapper
├── PersonMapper.java
└── PokemonMapper.java
src/main/java/com/example/spring/mybatis/model
├── Person.java
├── PersonExample.java
├── Pokemon.java
└── PokemonExample.java
src/main/resources/com/example/spring/mybatis/mapper
├── PersonMapper.xml
└── PokemonMapper.xml
0 directories, 8 files
Mapperインターフェースには、@Mapper
アノテーションが付与されています。
@Mapper
public interface PokemonMapper {
これで、MyBatis Spring Boot StarterのAutoConfigureでMapperを認識するようになります。
動かしてみる
MyBatis Generatorによる自動生成はできたので、軽く使って動作確認してみましょう。
こんなクラスを作成。
package com.example.spring.mybatis;
import com.example.spring.mybatis.mapper.PersonMapper;
import com.example.spring.mybatis.mapper.PokemonMapper;
import com.example.spring.mybatis.model.Person;
import com.example.spring.mybatis.model.Pokemon;
import com.example.spring.mybatis.model.PokemonExample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class DemoRunner implements ApplicationRunner {
Logger logger = LoggerFactory.getLogger(DemoRunner.class);
PokemonMapper pokemonMapper;
PersonMapper personMapper;
public DemoRunner(PokemonMapper pokemonMapper, PersonMapper personMapper) {
this.pokemonMapper = pokemonMapper;
this.personMapper = personMapper;
}
@Transactional
@Override
public void run(ApplicationArguments args) throws Exception {
Pokemon pikachu = new Pokemon();
pikachu.setName("ピカチュウ");
pokemonMapper.insert(pikachu);
logger.info("pikachu id = {}", pikachu.getId());
Pokemon fushigidane = new Pokemon();
fushigidane.setName("フシギダネ");
pokemonMapper.insert(fushigidane);
pokemonMapper
.selectByExample(new PokemonExample())
.forEach(pokemon -> logger.info("pokemon[{}]: {}", pokemon.getId(), pokemon.getName()));
Person tanjiro = new Person();
tanjiro.setId(1);
tanjiro.setLastName("竈門");
tanjiro.setFirstName("炭治郎");
personMapper.insert(tanjiro);
Person result = personMapper.selectByPrimaryKey(1);
logger.info("person[{}]: {} {}", result.getId(), result.getLastName(), result.getFirstName());
}
}
動かしてみます。
$ mvn spring-boot:run
結果。
2022-04-08 20:56:32.355 INFO 141382 --- [ main] com.example.spring.mybatis.DemoRunner : pikachu id = 1
2022-04-08 20:56:32.382 INFO 141382 --- [ main] com.example.spring.mybatis.DemoRunner : pokemon[1]: ピカチュウ
2022-04-08 20:56:32.383 INFO 141382 --- [ main] com.example.spring.mybatis.DemoRunner : pokemon[2]: フシギダネ
2022-04-08 20:56:32.388 INFO 141382 --- [ main] com.example.spring.mybatis.DemoRunner : person[1]: 竈門 炭治郎
日時等を削除して、少し見やすく。
pokemon[1]: ピカチュウ
pokemon[2]: フシギダネ
person[1]: 竈門 炭治郎
OKですね。
簡単ですが、こんな感じで。