简体   繁体   中英

How can you insert GeoJSON polygon into PostGIS using Java JDBC PreparedStatement placeholder?

If you are using the javascript library "Leaflet" and its plugin "Draw" then you can retrieve geojson looking something like this:

{
    "type" : "Polygon",
    "coordinates" : [ [ [ 13.95938491821289, 53.41329518072117 ], [ 14.955865859985348, 54.412618223375205 ], [ 13.9606294631958, 54.4120067663998 ], [ 13.95938491821289, 53.41329518072117 ] ] ]
}

If you send json as above to a webserver (with Java code eg Play Framework) I would then like to know the easiest way to insert it or update it in the postgis database without using string concatenation for the creation of the sql string. Indeed it works to create a SQL string with the above structure but you want to avoid string concatenation which is the reason for my question about how to instead use PreparedStatement placeholders. For example, the following SQL code can be executed directly from pgAdmin (and also through JDBC code):

UPDATE polygons
SET 
    geom = ST_SetSRID(ST_GeomFromGeoJSON
    ('{
            "type" : "Polygon",
            "coordinates" : [ [ [ 13.95938491821289, 53.41329518072117 ], [ 14.955865859985348, 54.412618223375205 ], [ 13.9606294631958, 54.4120067663998 ], [ 13.95938491821289, 53.41329518072117 ] ] ]
    }'), 26918)  
WHERE polygonid = 1;

However, as most developers have learned, we should avoid String concatenation and instead use placeholders, for example if using PreparedStatement (or eg JdbcTemplate if using Spring Framework).

Below is some code to illustrate what is working and what is not working.

The PostGIS database table I am using is created with this statement:

CREATE TABLE polygons (
  polygonid serial NOT NULL,
  geom geometry(Polygon,26918),
  CONSTRAINT polygon_pkey PRIMARY KEY (polygonid)
);

In my Maven file pom.xml I am using this dependency:

<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-jdbc</artifactId>
    <version>2.2.0</version>
</dependency>

Java code:

import java.sql.*;
import org.postgis.PGgeometry;
...
// For verbosity reasons, I am below not including 
// any try/catch/throw statements or any closings of connections/statements/recordsets

String url = "jdbc:postgresql://localhost:5432/nameOfYourDatabase";
Connection connection = DriverManager.getConnection(url, "postgres", "[YOUR_PASSWORD]");    

// First below is some SQL query code which works and thus 
// proves that the setup with jar files and database connection indeed works:    
long maxPolygonId  = 100L;
PreparedStatement ps = connection.prepareStatement(
    "SELECT polygonid , geom FROM polygons WHERE polygonid < ?"
);
ps.setLong(1, maxPolygonId);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
    long polygonId = rs.getLong(1);
    // Actually it works to use PGgeometry as below WITHOUT first having to do 
    // "((org.postgresql.PGConnection)conn).addDataType("geometry",Class.forName("org.postgis.PGgeometry"));" 
    // as currently documented at http://postgis.net/docs/ch06.html#idp48666800
    PGgeometry geom = (PGgeometry)rs.getObject(2); 
    System.out.println("polygonId: " + polygonId);
    System.out.println("geom: " + geom); // e.g. "geom: SRID=26918;POLYGON((17.9661226272583 59.41375375704178, ... ,17.9661226272583 59.41375375704178))"
}        

// Below is some code that also indeed works fine but it uses string 
// concatenation for the json string instead of placeholder which I want to use instead   
String geoJson = 
    "   {   " +
    "       \"type\" : \"Polygon\",  " +
    "       \"coordinates\" : [ [ [ 13.95938491821289, 53.41329518072117 ], [ 14.955865859985348, 54.412618223375205 ], [ 13.9606294631958, 54.4120067663998 ], [ 13.95938491821289, 53.41329518072117 ] ] ]  " +
    "   }  ";                   
String sqlUpdatingWithGeoJson = 
        "  UPDATE polygons  " +
        "   SET  " +
        "       geom = ST_SetSRID(ST_GeomFromGeoJSON  " +
        "       ('  " +
                    geoJson + 
        "       '), 26918)  " +
        "   WHERE polygonid = ?  ";
long idForPolygonToUpdate = 1L;
ps = connection.prepareStatement(sqlUpdatingWithGeoJson);
ps.setLong(1, idForPolygonToUpdate);
ps.executeUpdate();

// Below is some code which does NOT work when I am trying 
// to use placeholder instead of string concatenation as above 
String sqlUpdatingWithGeoJsonAsPlaceHolder = 
        "  UPDATE polygons  " +
        "   SET  " +
        "       geom = ST_SetSRID(ST_GeomFromGeoJSON  " +
        "       ('  " +
                    " ? " + // NOTE that this line is the difference with the sql update string above ! 
        "       '), 26918)  " +
        "   WHERE polygonid = ?  ";         

ps = connection.prepareStatement(sqlUpdatingWithGeoJsonAsPlaceHolder);
ps.setString(1, geoJson);
ps.setLong(2, idForPolygonToUpdate);
// The above row results in the exception below
// org.postgresql.util.PSQLException: The column index is out of range: 2, number of columns: 1.            
ps.executeUpdate();               


// Below I instead tried  to replace the whole expression as a string to be set 
// through the placeholder but it does NOT work neither  
String geomValue =
        "       ST_SetSRID(ST_GeomFromGeoJSON  " +
        "       ('  " +
                    geoJson + 
        "       '), 26918)  ";          
String sqlUpdatingWithPostGisStatementForPlaceHolder = 
        "  UPDATE polygons  " +
        "   SET  " +
        "       geom = ?  " +
        "   WHERE polygonid = ?  ";
ps = connection.prepareStatement(sqlUpdatingWithPostGisStatementForPlaceHolder);
ps.setString(1, geomValue); // I have also tried setObject instead of setString here
ps.setLong(2, idForPolygonToUpdate);
// The above row also results in the same exception as previous above i.e. below exception:
// org.postgresql.util.PSQLException: The column index is out of range: 2, number of columns: 1.    
ps.executeUpdate();

Maybe the solution could be to convert the json string to some Java object which can be understood by the PostGIS/PostgreSQL JDBC driver, and then use method "prepareStatement.setObject", but then what type should be used for that Java object and how can you easy convert json string to such an object?

String sqlUpdatingWithGeoJsonAsPlaceHolder = 
        "  UPDATE polygons  " +
        "   SET  " +
        "       geom = ST_SetSRID(ST_GeomFromGeoJSON(?), 26918)  " +
        "   WHERE polygonid = ?  ";         

ps = connection.prepareStatement(sqlUpdatingWithGeoJsonAsPlaceHolder);
ps.setString(1, geoJson);
ps.setLong(2, idForPolygonToUpdate);      
ps.executeUpdate();   

This one should work: you pass the geojson as a string. The function ST_GeomFromGeoJSON is expecting a string as the first parameter, so the statement can be prepared and executed.

You got that error because you quoted the question mark. That way, the question mark is not interpreted as a placeholder!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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