スポンサーリンク

【Spring】【PostGIS】【Spring Data JPA】使い方

スポンサーリンク

SpringとPostGISとSpring JPAを連携させる方法です。

初めに各種ライブラリの説明を行い、後にソースコードを配置します。実装にのみ興味がある方は後半に飛んでください。

PostGIS

PostGISは空間データを取り扱うためのPostgreSQLにおけるデータフォーマットです

PostGIS

ライセンス

PostGIS自体はGPLですが、単に使用するだけの場合はGPL汚染されません。PostGIS自体を改変する場合にGPLとする必要があると明記されています

404 Not Found

postgis jdbc driver

2.5.0より前はこれに従うらしい

https://postgis.net/docs/manual-1.5/ch05.html

けど、それ以降は以下の記載があり、以下に移管されている様子。

 As of June 2015, PostGIS JDBC development has been split from PostGIS core and is now on github.

GitHub - postgis/postgis-java: java bindings for postgis
java bindings for postgis. Contribute to postgis/postgis-java development by creating an account on GitHub.

基本的にpostgis jdbc独自のPGeometryは汎用性が低いため、jts準拠のクラス群を用いた方が扱いやすい印象です。

Spring Data JPA

Spring Data JPAはHiberneteをデフォルトでラップしたORM(Object Rerational Mapping)です。

Hibernate Spatial

Hibernate Spatialは PostgreSql/PostGIS, MySQL, Microsoft SQL 等各種DBで定義されている空間データをGenericにORMできるライブラリです。

Hibernate ORM 5.2.18.Final User Guide

普通に調べると以下のhttpなホームページが先に出てきますが、こちらは相当古くHibernate4.0程度までしか記載されていません。上記のホームページをご覧ください。ちなみに、現状の最新spring bootである2.7.3に対応するHibernateは5.6.10です。

tutorial4 | Hibernate Spatial
The documentation for Hibernate Spatial

ライセンス

ただHibernate SpatialはLGPLです。

Just a moment...

コード

POM

Kotlinベースなので、Javaの方には必要ない記載が多いですが、以下となります。Spring系列以外に追加するのはpostgresqlのjdbcとhibernate spatialです。

${hibernate.version}はspring-boot-dependencies-2.7.3.pomで定義してくれているおかげで特に何もせずに関連づいたversionを参照できます。この場合5.6.10Final.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>demo</description>
    <properties>
        <java.version>17</java.version>
        <kotlin.version>1.6.21</kotlin.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-spatial</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <configuration>
                    <args>
                        <arg>-Xjsr305=strict</arg>
                    </args>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                        <plugin>jpa</plugin>
                    </compilerPlugins>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-noarg</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

Geometry等を読み込めるようにpostgisをjpa databaseとして指定します。

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/geo
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.database-platform=org.hibernate.spatial.dialect.postgis.PostgisDialect

Database 定義

postgisに適応したPostgreSQLの使用を始めるのはDockerが用意されているので、それを利用するのが手っ取り早いです。

GitHub - postgis/docker-postgis: Docker image for PostGIS
Docker image for PostGIS. Contribute to postgis/docker-postgis development by creating an account on GitHub.

DB初期化スクリプトとして以下を使用することにします。

CREATE DATABASE geo;

\c geo;

create extension postgis;

create table mygeo(
    id serial primary key ,
    name varchar(32),
    point geometry(POINT, 4326),
    linestring geometry(LINESTRING, 4326),
    polygon geometry(POLYGON, 4326)
);

Entity

通常のSpring Data Jpaと同様です。Hibernate Spatialではorg.locationtech.jts.geomのライブラリを使用してマッピング可能です。

package com.example.demo

import org.locationtech.jts.geom.LineString
import org.locationtech.jts.geom.Point
import org.locationtech.jts.geom.Polygon
import javax.persistence.*

@Entity
@Table(name = "mygeo")
data class GeoEntity(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private var id: Int = 0,

    @Column(name = "name")
    private val name:String?,

    @Column(name = "point")
    private val point: Point?,

    @Column(name = "linestring")
    private val linestring: LineString?,

    @Column(name = "polygon")
    private val polygon: Polygon?
)

Repository

interface PostgisRepository : JpaRepository<GeoEntity, Int>{
}

Controller

package com.example.demo

import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.GeometryFactory
import org.locationtech.jts.geom.LineString
import org.locationtech.jts.geom.LinearRing
import org.locationtech.jts.geom.Point
import org.locationtech.jts.geom.Polygon
import org.locationtech.jts.geom.PrecisionModel
import org.locationtech.jts.geom.impl.CoordinateArraySequence
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class MyController(
@Autowired val repository: PostgisRepository
) {
val factory = GeometryFactory(PrecisionModel(), 4326)

@GetMapping("/")
fun test(): String{
//POINT
val pointSequence = CoordinateArraySequence(arrayOf(Coordinate(1.0, 1.0)))
val point = Point(pointSequence, factory)

//LINESTRING
val lineSequence = CoordinateArraySequence(arrayOf(Coordinate(1.0, 1.0), Coordinate(2.0, 2.0)))
val lineString = LineString(lineSequence, factory)

//POLYGON
val polygonSequence = CoordinateArraySequence(arrayOf(Coordinate(1.0, 1.0), Coordinate(2.0, 2.0), Coordinate(1.0, 2.0), Coordinate(1.0, 1.0)))
val linearRing = LinearRing(polygonSequence, factory)
val polygon = Polygon(linearRing, arrayOf(), factory)

repository.save(GeoEntity(name = "test", point = point, linestring = lineString, polygon = polygon))
val data = repository.findAll()
data.forEach{ println(it) }
return "test"
}
}
タイトルとURLをコピーしました