简体   繁体   English

在 Spring Boot 上使用 Hibernate 映射 PostGIS 几何点字段

[英]Map a PostGIS geometry point field with Hibernate on Spring Boot

In my PostgreSQL 9.3 + PostGIS 2.1.5 I have a table PLACE with a column coordinates of type Geometry(Point,26910) .在我的 PostgreSQL 9.3 + PostGIS 2.1.5 中,我有一个表PLACE ,其列coordinatesGeometry(Point,26910)

I want to map it to Place entity in my Spring Boot 1.1.9 web application, which uses Hibernate 4.0.0 + .我想将它映射到使用 Hibernate 4.0.0 + 的 Spring Boot 1.1.9 Web 应用程序中的Place实体。 Place is available with a REST repository. Place可用于 REST 存储库。

Unfortunately when I GET http://localhost:8080/mywebapp/places I receive this strange JSON response :不幸的是,当我GET http://localhost:8080/mywebapp/places我收到了这个奇怪的 JSON 响应

{

  "_embedded" : {

    "venues" : [ {

      "id" : 1,

      "coordinates" : {

        "envelope" : {

          "envelope" : {

            "envelope" : {

              "envelope" : {

                "envelope" : {

                  "envelope" : {

                    "envelope" : {

                      "envelope" : {

                        "envelope" : {

                          "envelope" : {

                            "envelope" : {

                              "envelope" : {

                                "envelope" : {

                                  "envelope" : {

                                    "envelope" : {

                                      "envelope" : {

                                        "envelope" : {

                                          "envelope" : {

                                            "envelope" : {

and so on indefinetely...!等等无限……! Spring log doesn't help.. Spring日志没有帮助..

I'm working with this application.properties:我正在使用这个 application.properties:

spring.jpa.database-platform=org.hibernate.spatial.dialect.postgis.PostgisDialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update

spring.datasource.url=jdbc:postgresql://192.168.1.123/mywebapp
spring.datasource.username=postgres
spring.datasource.password=mypwd
spring.datasource.driverClassName=org.postgresql.Driver

First of all, is it ok to use database-platform instead of database ?首先,可以使用database-platform而不是database吗? And maybe do I have to use following settings instead of the above?也许我必须使用以下设置而不是以上设置?

spring.datasource.url=jdbc:postgresql_postGIS://192.168.1.123/mywebapp
spring.datasource.driverClassName=org.postgis.DriverWrapper

Anyway my entity is something like this:无论如何,我的实体是这样的:

@Entity
public class Place {
    @Id
    public int id;
    @Column(columnDefinition="Geometry")
    @Type(type="org.hibernate.spatial.GeometryType")    //"org.hibernatespatial.GeometryUserType" seems to be for older versions of Hibernate Spatial
    public com.vividsolutions.jts.geom.Point coordinates;
}

My pom.xml contains this relevant part:我的 pom.xml 包含这个相关部分:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.3-1102-jdbc41</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-spatial</artifactId>
    <version>4.3</version><!-- compatible with Hibernate 4.3.x -->
    <exclusions>
        <exclusion>
            <artifactId>postgresql</artifactId>
            <groupId>postgresql</groupId>
        </exclusion>
    </exclusions>
</dependency>

A bit strange configuration, I found it on the internet, it is the one that works best for now.有点奇怪的配置,我在网上找到的,它是目前最好的配置。

I hope that someone could help me with this mistery.我希望有人能帮助我解决这个谜团。 :) :)

Finally I discovered that my configuration is ok and might be Jackson that cannot manage Point data type correctly.最后我发现我的配置没问题,可能是Jackson无法正确管理Point数据类型。 So I customized its JSON serialization and deserialization:所以我自定义了它的 JSON 序列化和反序列化:

  • add these annotations to our coordinates field:将这些注释添加到我们的coordinates字段中:

     @JsonSerialize(using = PointToJsonSerializer.class) @JsonDeserialize(using = JsonToPointDeserializer.class)
  • create such serializer:创建这样的序列化程序:

     import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.vividsolutions.jts.geom.Point; public class PointToJsonSerializer extends JsonSerializer<Point> { @Override public void serialize(Point value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { String jsonValue = "null"; try { if(value != null) { double lat = value.getY(); double lon = value.getX(); jsonValue = String.format("POINT (%s %s)", lat, lon); } } catch(Exception e) {} jgen.writeString(jsonValue); } }
  • create such deserializer:创建这样的解串器:

     import java.io.IOException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel; public class JsonToPointDeserializer extends JsonDeserializer<Point> { private final static GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 26910); @Override public Point deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { try { String text = jp.getText(); if(text == null || text.length() <= 0) return null; String[] coordinates = text.replaceFirst("POINT ?\\\\(", "").replaceFirst("\\\\)", "").split(" "); double lat = Double.parseDouble(coordinates[0]); double lon = Double.parseDouble(coordinates[1]); Point point = geometryFactory.createPoint(new Coordinate(lat, lon)); return point; } catch(Exception e){ return null; } } }

Maybe you can also use this serializer and this deserializer , available here .也许你也可以使用这个序列化器这个反序列化这里可用。

The solutions above helped me to fix the problem.上面的解决方案帮助我解决了这个问题。 I simplify it so other people can understand.我把它简化了,以便其他人可以理解。

I included this library in my pom.xml:我在我的 pom.xml 中包含了这个库:

<dependency>
  <groupId>com.bedatadriven</groupId>
  <artifactId>jackson-datatype-jts</artifactId>
  <version>2.2</version>
</dependency>

This is the POJO object I used.这是我使用的 POJO 对象。 Then I was able to get the REST call to work without the envelope error and proper coordinates.然后我能够在没有包络错误和正确坐标的情况下使 REST 调用正常工作。

import com.bedatadriven.jackson.datatype.jts.serialization.GeometryDeserializer;
import com.bedatadriven.jackson.datatype.jts.serialization.GeometrySerializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.vividsolutions.jts.geom.Geometry;

@Entity
@Table(name = "boundary")
public class Boundary {

    private int id;
    private Geometry geometry;

    @Id
    public int getId() {
        return ogc_fid;
    }

    public void setId(int id) {
        this.id = id;
    }
    
    @JsonSerialize(using = GeometrySerializer.class)
    @JsonDeserialize(using = GeometryDeserializer.class)
    @Column(name = "geometry", columnDefinition = "Geometry")
    public Geometry getGeometry() {
        return geometry;
    }

    public void setGeometry(Geometry geometry) {
        this.geometry = geometry;
    }
}

My table had these 2 columns:我的表有以下两列:

id       | integer            
geometry | geometry(Geometry,4326) | 

This serialization/deserialization also worked fine for me.这种序列化/反序列化对我来说也很好用。

https://github.com/bedatadriven/jackson-datatype-jts https://github.com/bedatadriven/jackson-datatype-jts

With Hibernate 5.4 and Posgis 13+ its became very easy.使用 Hibernate 5.4 和 Posgis 13+,它变得非常容易。 We can just add latest hibernate-spatial dependency我们可以添加最新的休眠空间依赖

    <!-- Hibernate Spatial for storing and retrieving geometries -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-spatial</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

Use latest Posgis dialect .使用最新的 Posgis 方言 Add in application.properties :添加 application.properties

spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect

Then we can simply use JST geometry because its supported by Hibernate (see here ).然后我们可以简单地使用 JST 几何体,因为它受 Hibernate 支持(请参阅此处)。

import org.locationtech.jts.geom.Point;

@Entity(name = "address")
public class Address {
 private Point location;
}

SQL to create entity table : SQL 创建实体表:

CREATE TABLE if not EXISTS address (location geometry);

Further JTS GeoJSON Reader and Writer can be used to translate geometries into JSON (see here )进一步的 JTS GeoJSON Reader 和 Writer 可用于将几何图形转换为 JSON(请参阅此处

The problem doesn't appear to be related to PostgreSQL.该问题似乎与 PostgreSQL 无关。 It appears that your POJO has a backreference, which means that your mapper doesn't know how to handle it.您的 POJO 似乎有反向引用,这意味着您的映射器不知道如何处理它。 You need to explicitly define the recursive relationships so that the mapper knows when to stop.您需要明确定义递归关系,以便映射器知道何时停止。 (My Goto link --> http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html ) (我的转到链接 --> http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html

If you don't want to add the annotation on all your fields that are using a Point, you can also use the @JsonComponent to register your JsonSerializer and JsonDeserializer .如果您不想在所有使用 Point 的字段上添加注释,您还可以使用@JsonComponent来注册您的JsonSerializerJsonDeserializer

@JsonComponent
public class PointSerializer extends JsonSerializer<com.vividsolutions.jts.geom.Point>{

    @Override
 public void serialize(com.vividsolutions.jts.geom.Point value, JsonGenerator gen, SerializerProvider provider) throws IOException {
     gen.writeStartObject();
     gen.writeNumberField("lat", value.getY());
     gen.writeNumberField("lon", value.getX());
     gen.writeEndObject();
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM