简体   繁体   English

如何使用Java JDBC PreparedStatement占位符将GeoJSON多边形插入PostGIS?

[英]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: 如果您使用的是JavaScript库“ Leaflet”及其插件“ Draw”,则可以检索geojson,如下所示:

{
    "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. 如果您如上所述将json发送到网络服务器(带有Java代码,例如Play Framework),那么我想知道在不使用字符串串联创建sql字符串的情况下,将其插入或更新到postgis数据库中的最简单方法。 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. 实际上,它可以使用上述结构创建SQL字符串,但是您要避免字符串串联,这是我关于如何改为使用PreparedStatement占位符的问题的原因。 For example, the following SQL code can be executed directly from pgAdmin (and also through JDBC code): 例如,可以从pgAdmin直接执行以下SQL代码(也可以通过JDBC代码):

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). 但是,正如大多数开发人员所了解的那样,我们应该避免String串联,而应使用占位符,例如,如果使用PreparedStatement(或者如果使用Spring Framework,则为JdbcTemplate)。

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: 我正在使用的PostGIS数据库表是通过以下语句创建的:

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: 在我的Maven文件pom.xml中,我正在使用此依赖项:

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

Java code: Java代码:

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? 也许解决方案可能是将json字符串转换为PostGIS / PostgreSQL JDBC驱动程序可以理解的Java对象,然后使用方法“ prepareStatement.setObject”,但是该Java对象应使用什么类型以及如何使用您轻松将json字符串转换为此类对象?

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. 这应该可行:您将geojson作为字符串传递。 The function ST_GeomFromGeoJSON is expecting a string as the first parameter, so the statement can be prepared and executed. 函数ST_GeomFromGeoJSON将字符串作为第一个参数,因此可以准备和执行该语句。

You got that error because you quoted the question mark. 您收到该错误是因为您引用了问号。 That way, the question mark is not interpreted as a placeholder! 这样,问号不会被解释为占位符!

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

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