前回
Micronaut + KotlinでHelloWorld
前回のプロジェクトを拡張し、MyBatisを使ってデータベース接続をしてみます。
実際に作成したリポジトリはこちらになります。
データベースを用意
DockerでPostgreSQLのコンテナを用意します。
前回作成したプロジェクトと同階層に以下を作成しました。
- DB環境作成用の
docker-compose.yml
version: '3'
services:
db:
image: postgres
restart: always
container_name: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: books
volumes:
- ./data/postgres/db-data:/var/lib/postgresql/data
- ./database:/docker-entrypoint-initdb.d
ports:
- 5432:5432
- テーブル作成用のSQLを格納する
data
フォルダとSQL
set client_encoding = 'UTF8';
CREATE TABLE book (
id SERIAL,
name VARCHAR(200) NOT NULL,
publisher VARCHAR(200),
publication_date DATE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
CONSTRAINT pk_book PRIMARY KEY (id)
);
-- 確認用の初期データ
INSERT INTO book (id, name, publisher, publication_date, created_at, updated_at) VALUES (1, 'テスト書籍1', 'テスト出版社A', null, current_timestamp, current_timestamp);
INSERT INTO book (id, name, publisher, publication_date, created_at, updated_at) VALUES (2, 'テスト書籍2', 'テスト出版社A', null, current_timestamp, current_timestamp);
- DBデータをGitの管理対象から外すための
.gitignore
data
docker-compose
のあるフォルダに移動し、コンテナを起動します。
$ docker-compose up -d
これでDBの方の準備はOKです。
プロジェクトの改修
ライブラリの追加
build.gradleを編集し、ライブラリを追加します。
dependencies {
// 省略
implementation("org.mybatis:mybatis:3.4.6")
implementation("io.micronaut.sql:micronaut-jdbc-hikari")
runtimeOnly("org.postgresql:postgresql")
// 省略
}
接続設定とか追加
application.yml
を編集します。
- 接続先の追加
- MyBatisの設定を追加
micronaut:
application:
name: helloworld
# 以下を追加
datasources:
default:
url: jdbc:postgresql://localhost:5432/books
username: postgres
password: postgres
driverClassName: org.postgresql.Driver
mybatis:
# mapperのxmlファイルを格納する位置を指定
mapper-locations: classpath:example/mapper/*.xml
configuration:
map-underscore-to-camel-case: true
default-fetch-size: 100
default-statement-timeout: 30
cache-enabled: false
モデルの作成
DBから取得したデータを格納するクラスを作成します。
package example.model
import io.micronaut.core.annotation.Introspected
import java.sql.Date
/**
* 書籍データクラス
*/
@Introspected
data class Book(
var id: Int?,
var name: String,
var publisher: String?,
var publicationDate: Date?,
)
SqlSessionFactoryの作成
SqlSessionを用意するFactoryクラスを作成します。
package example
import io.micronaut.context.annotation.Factory
import org.apache.ibatis.mapping.Environment
import org.apache.ibatis.session.Configuration
import org.apache.ibatis.session.SqlSessionFactory
import org.apache.ibatis.session.SqlSessionFactoryBuilder
import org.apache.ibatis.transaction.TransactionFactory
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
import javax.inject.Singleton
import javax.sql.DataSource
@Factory
class MybatisFactory(private val dataSource: DataSource) {
@Singleton
fun sqlSessionFactory(): SqlSessionFactory {
val transactionFactory: TransactionFactory = JdbcTransactionFactory()
val environment = Environment("dev", transactionFactory, dataSource)
val configuration = Configuration(environment)
// mapperをスキャンするパッケージを指定。
configuration.addMappers("example")
return SqlSessionFactoryBuilder().build(configuration)
}
}
Mapperの作成
SQLとのインタフェースとなるMapperを作成します。
package example.mapper
import example.model.Book
import org.apache.ibatis.annotations.Mapper
@Mapper
interface BookMapper {
fun findById(id: Int): Book
}
実行するSQL本体は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="example.mapper.BookMapper">
<select id="findById" resultType="example.model.Book">
SELECT
id,
name,
publisher,
publication_date
FROM book
<where>
id = #{id}
</where>
</select>
</mapper>
インタフェースの実装としてServiceクラスを作成します。
package example.service
import example.mapper.BookMapper
import example.model.Book
import org.apache.ibatis.session.SqlSessionFactory
import javax.inject.Singleton
@Singleton
class BookService(private val sqlSessionFactory: SqlSessionFactory) : BookMapper {
override fun findById(id: Int): Book {
sqlSessionFactory.openSession().use { session ->
val bookMapper = session.getMapper(BookMapper::class.java)
return bookMapper.findById(id)
}
}
}
Controllerの作成
データベースにアクセスするAPIを作成します。
package example.controller
import example.mapper.BookMapper
import example.model.Book
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
@Controller()
class BookController(private val bookMapper: BookMapper) {
/**
* 書籍情報の取得。
* ID指定
*
* @param id 書籍ID
*
* @return HttpResponse
*/
@Get("/book/{id}")
fun readById(id: Int): HttpResponse<Book> {
return HttpResponse.ok(bookMapper.findById(id))
}
}
ひとまず完成
ここまで/book/{id}
のエンドポイントにアクセスすればデータを取得する動きができました。
試してみます。
サーバを実行します。
$ cd server
$ ./gradlew run
http://localhost:8080/book/1
にアクセスします。
$ curl -X GET http://localhost:8080/book/1
{"id":1,"name":"テスト書籍1","publisher":"テスト出版社A"}
データベースからデータを取得することができました。
次にやりたいこと
登録、更新も作りました。
Micronaut + Kotlin のプロジェクトにてMyBatisを使ってデータベースにデータ登録してみる