2014-12-23 17 views
15

W moim PostgreSQL 9.3 + PostGIS 2.1.5 Mam tabelę PLACE z kolumną coordinates typu Geometry(Point,26910).Mapowanie pola punktu geometrii PostGIS z Hibernate na Spring Boot

Chcę zmapować go do jednostki Place w mojej aplikacji internetowej Spring Boot 1.1.9, która używa Hibernacji 4.0.0 +. Place jest dostępny z repozytorium REST.

Niestety kiedy GET http://localhost:8080/mywebapp/places otrzymam tej dziwnej odpowiedzi 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" : { 

i tak dalej indefinetely ...! Wiosna dziennika nie pomaga ..

pracuję z tym 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 

Przede wszystkim, to jest ok używać database-platform zamiast database? A może muszę użyć poniższych ustawień zamiast powyższych?

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

Zresztą moja jednostka jest mniej więcej tak:

@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; 
} 

Moje pom.xml to odpowiednia część zawiera:

<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> 

Trochę dziwne konfiguracja, znalazłem go w Internecie, to jest to, które na razie działa najlepiej.

Mam nadzieję, że ktoś może mi pomóc w tej tajemnicy. :)

Odpowiedz

15

Wreszcie odkryłem, że moja konfiguracja jest w porządku i może być Jackson, że nie można zarządzać Point typ danych poprawnie. Więc dostosować swoje serializacji JSON i deserializacji:

  • dodać te adnotacje do naszego coordinates polu:

    @JsonSerialize(using = PointToJsonSerializer.class) 
    @JsonDeserialize(using = JsonToPointDeserializer.class) 
    
  • stworzenie takiej serializatora:

    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); 
        } 
    
    } 
    
  • stworzenie takiej Deserializator:

    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; 
         } 
        } 
    
    } 
    

Być może można również użyć this serializer i this deserializer, dostępnego pod numerem here.

+0

Zauważam, że szerokość i długość wyjściowa wyjściowa z Serializera są zamieniane. czy to jest oczekiwane? Ten kod wyjaśnia "double lat = value.getY();" i "double lon = value.getX();" dzięki – randytan

+0

@randytan Użyłem tego kodu dawno temu, ale pamiętam tę szerokość i długość geograficzną gdzie w odpowiedniej kolejności. Gdzie ich zamieniasz? – bluish

+0

Jeśli wyślesz 'POINT (AB)' i zrobisz 'sys.out' do swojej zmiennej' jsonValue = String.format ("POINT (% s% s)", lat, lon); 'możesz zobaczyć, że jest on faktycznie zapisany do "PUNKT (BA)". Po prostu zamieniam kod 'value.getY()' oraz 'value.getX()', aby poprawić pozycję. Dzięki – randytan

0

Problem nie wydaje się być związany z PostgreSQL. Wygląda na to, że twoje POJO ma referencje zwrotne, co oznacza, że ​​twój program odwzorowujący nie wie, jak sobie z tym poradzić. Musisz jawnie zdefiniować relacje rekursywne, aby mapper wiedział, kiedy przestać. (Mój związek Goto ->http://vard-lokkur.blogspot.com/2010/10/json-jackson-to-rescue.html)

+0

nie mające odniesienia do jakiegokolwiek innego podmiotu, to nie jest problem. Mimo wszystko dziekuję! – bluish

1

Rozwiązania powyższe pomógł mi rozwiązać problem. Upraszczam to, aby inni ludzie mogli to zrozumieć.

włączyłem tej biblioteki w moim pom.xml:

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

Jest to obiekt POJO użyłem. Wtedy udało mi się uzyskać wywołanie REST do pracy bez błędu obwiedni i właściwych steków.

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 geomertry; 

    @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 getGeomertry() { 
     return geomertry; 
    } 

    public void setGeomertry(Geometry geomertry) { 
     this.geomertry = geomertry; 
    } 
} 

Moja tabela miał te 2 kolumny:

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