如何使用 Spring 数据 JPA 在 postgres(使用 postgis)中插入一个点/多边形?

问题描述 投票:0回答:1

我使用 leaflet 创建了一个地图,我正在尝试使用 spring data JPA 将绘制的点/多面体发送到我的 postgres 数据库。服务器最初接收一个字符串 geoJSON(通过以下反序列化方法转换为 org.locationtech.jts.geom.MultiPolygon 和 org.locationtech.jts.geom.Point)。 Obs:我注意 geojson 字符串始终有效

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.locationtech.jts.geom.MultiPolygon;
import java.io.IOException;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.geojson.GeoJsonReader;

public class MultiPolygonDeserializer extends JsonDeserializer<MultiPolygon> {

    @Override
    public MultiPolygon deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        String geoJson = parser.getValueAsString();
        GeoJsonReader reader = new GeoJsonReader();
        try {
            return (MultiPolygon) reader.read(geoJson);
        } catch (ParseException e) {
            throw new IOException(e);
        }
    }
}
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.locationtech.jts.geom.Point;
import java.io.IOException;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.geojson.GeoJsonReader;

public class PointDeserializer extends JsonDeserializer<Point> {

    @Override
    public Point deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        String geoJson = parser.getValueAsString();
        GeoJsonReader reader = new GeoJsonReader();
        try {
            return (Point) reader.read(geoJson);
        } catch (ParseException e) {
            throw new IOException(e);
        }
    }
}

他们显然工作正常,返回,例如: 多边形 (((-42.538033 -19.461896, -42.542667 -19.489894, -42.487564 -19.478404, -42.538033 -19.461896))) 和 点 (-42.5270802 -19.4777807)

这是我的模特:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.pedro.geoPartners.util.MultiPolygonDeserializer;
import com.pedro.geoPartners.util.PointDeserializer;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.util.UUID;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Point;


/**
 *
 * @author pedro
 */
@Entity
public class Partner {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;

    private String tradingName;
    private String ownerName;
    private String document;

    @Column(columnDefinition = "geometry(Point,4326)")
    @JsonDeserialize(using = PointDeserializer.class)
    private Point address;

    @Column(columnDefinition = "geometry(MultiPolygon,4326)")
    @JsonDeserialize(using = MultiPolygonDeserializer.class)
    private MultiPolygon coverageArea;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    public String getTradingName() {
        return tradingName;
    }

    public void setTradingName(String tradingName) {
        this.tradingName = tradingName;
    }

    public String getOwnerName() {
        return ownerName;
    }

    public void setOwnerName(String ownerName) {
        this.ownerName = ownerName;
    }

    public String getDocument() {
        return document;
    }

    public void setDocument(String document) {
        this.document = document;
    }

    public Point getAddress() {
        return address;
    }

    public void setAddress(Point address) {
        this.address = address;
    }

    public MultiPolygon getCoverageArea() {
        return coverageArea;
    }

    public void setCoverageArea(MultiPolygon coverageArea) {
        this.coverageArea = coverageArea;
    }

但是,当我尝试在数据库中保存合作伙伴时,我收到:

2023-03-04T17:51:39.152-03:00  WARN 116266 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: XX000
2023-03-04T17:51:39.152-03:00 ERROR 116266 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: Invalid endian flag value encountered.
2023-03-04T17:51:39.152-03:00  INFO 116266 --- [nio-8080-exec-1] o.h.e.j.b.internal.AbstractBatchImpl     : HHH000010: On release of batch it still contained JDBC statements
2023-03-04T17:51:39.157-03:00 ERROR 116266 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.jpa.JpaSystemException: could not execute statement] with root cause

org.postgresql.util.PSQLException: ERROR: Invalid endian flag value encountered.
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2676) ~[postgresql-42.5.4.jar:42.5.4]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2366) ~[postgresql-42.5.4.jar:42.5.4]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:356) ~[postgresql-42.5.4.jar:42.5.4]
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:496) ~[postgresql-42.5.4.jar:42.5.4]...
  • 我尝试了很多“JPA 属性转换器”的实现,但总是出现同样的错误。此外,我在某处(不确定)读到 MultiPolygon 和 Point locationtech 可以直接插入 @Column(columnDefinition = "geometry(MultiPolygon,4326)") 和 @Column(columnDefinition = "geometry(Point,4326)").

*另请阅读 hibernate @Type... 但显然在 hibernate spatial 版本 5.4.32 中不起作用(已弃用?)

*只是为了确定,我尝试在尝试保存到数据库之前设置 coverageArea 和地址为空,并且保存正确。

我的应用属性:

spring.jpa.database=POSTGRESQL
spring.datasource.url=jdbc:postgresql://localhost:5432/GeoPartners?useTimeZone=true&serverTimezone=UTC&autoReconnect=true&useSSL=false
spring.datasource.username=postgres
spring.datasource.password=:)
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.sql.init.mode=ALWAYS
spring.jpa.defer-datasource-initialization=true
hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect

我的pom.xml:

<?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>3.0.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.pedro</groupId>
    <artifactId>geoPartners</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>geoPartners</name>
    <description>update of &quot;JavaWebProject&quot;, implementing new features and Front-end</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-spatial</artifactId>
            <version>5.4.32.Final</version>
        </dependency>
        <dependency>
            <groupId>org.locationtech.jts.io</groupId>
            <artifactId>jts-io-common</artifactId>
            <version>1.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.postgis</groupId>
            <artifactId>postgis-jdbc</artifactId>
            <version>1.3.3</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>osgeo-alt</id>
            <url>https://repo.osgeo.org/repository/release/</url>
        </repository>
        <repository>
            <id>geomajas</id>
            <name>Geomajas Maven Repository</name>
            <url>http://maven.geomajas.org/(http://maven.geomajas.org/)</url>
        </repository>
    </repositories>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这是我的第一个问题,对不起,如果我犯了错误或忘记了什么。谢谢

尝试使用 JpaRepository“保存”在 postgres 数据库中保存“合作伙伴”(模型)。期望保存所有属性但总是收到相同的错误(org.postgresql.util.PSQLException:错误:遇到无效的字节序标志值。)当我尝试保存 MultiPolygon 或/和 Point.

java spring spring-data-jpa geometry postgis
1个回答
0
投票
  1. 你可以试试这个AttributeConverter接口实现。 postgis 存储格式中的几何是 WKB。

  2. 在 pojo 字段中添加 @Convert(converter = GeometryAttributeConverter.class)

import org.geotools.geometry.jts.WKBReader;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBWriter;

import javax.persistence.AttributeConverter;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Arjen10
 * @date 2023/3/6 14:42
 */
public class GeometryAttributeConverter implements AttributeConverter<Geometry, byte[]> {

    private static final WKBWriter WKB_WRITER = new WKBWriter();

    private static final WKBReader WKB_READER = new WKBReader();

    private static final ReentrantLock WRITE_LOCK = new ReentrantLock();

    private static final ReentrantLock READ_LOCK = new ReentrantLock();

    @Override
    public byte[] convertToDatabaseColumn(Geometry attribute) {
        WRITE_LOCK.lock();
        try {
            //PostGIS's storage format is WKB
            return WKB_WRITER.write(attribute);
        }finally {
            WRITE_LOCK.unlock();
        }
    }

    @Override
    public Geometry convertToEntityAttribute(byte[] dbData) {
        READ_LOCK.lock();
        try {
            return WKB_READER.read(dbData);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        } finally {
            READ_LOCK.unlock();
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.