如何使用 Java JDBC PreparedStatement 占位符将 GeoJSON 多边形插入到 PostGIS 中?
How can you insert GeoJSON polygon into PostGIS using Java JDBC PreparedStatement placeholder?
如果您正在使用 javascript 库 "Leaflet" 及其插件 "Draw",那么您可以检索 geojson,如下所示:
{
"type" : "Polygon",
"coordinates" : [ [ [ 13.95938491821289, 53.41329518072117 ], [ 14.955865859985348, 54.412618223375205 ], [ 13.9606294631958, 54.4120067663998 ], [ 13.95938491821289, 53.41329518072117 ] ] ]
}
如果您将 json 如上所述发送到网络服务器(使用 Java 代码,例如 Play Framework)我想知道
在不使用的情况下将其插入或更新到 postgis 数据库中的最简单方法
用于创建 sql 字符串的字符串连接。
事实上,它可以创建具有上述结构的 SQL 字符串,但您想避免字符串连接,这就是我提出有关如何改用 PreparedStatement 占位符的问题的原因。
例如,以下 SQL 代码可以直接从 pgAdmin 执行(也可以通过 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;
但是,正如大多数开发人员所了解的那样,我们应该避免字符串连接,而是
使用占位符,例如如果使用 PreparedStatement(或者例如 JdbcTemplate 如果使用 Spring Framework)。
下面是一些代码来说明什么有效,什么无效。
我正在使用的 PostGIS 数据库 table 是使用以下语句创建的:
CREATE TABLE polygons (
polygonid serial NOT NULL,
geom geometry(Polygon,26918),
CONSTRAINT polygon_pkey PRIMARY KEY (polygonid)
);
在我的 Maven 文件中 pom.xml 我正在使用这个依赖项:
<dependency>
<groupId>net.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>2.2.0</version>
</dependency>
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();
也许解决方案是将 json 字符串转换为一些可以理解的 Java 对象
通过 PostGIS/PostgreSQL JDBC 驱动程序,然后使用方法 "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();
这个应该可以工作:您将 geojson 作为字符串传递。函数 ST_GeomFromGeoJSON 需要一个字符串作为第一个参数,因此可以准备和执行该语句。
你得到这个错误是因为你引用了问号。这样,问号就不会被解释为占位符!
如果您正在使用 javascript 库 "Leaflet" 及其插件 "Draw",那么您可以检索 geojson,如下所示:
{
"type" : "Polygon",
"coordinates" : [ [ [ 13.95938491821289, 53.41329518072117 ], [ 14.955865859985348, 54.412618223375205 ], [ 13.9606294631958, 54.4120067663998 ], [ 13.95938491821289, 53.41329518072117 ] ] ]
}
如果您将 json 如上所述发送到网络服务器(使用 Java 代码,例如 Play Framework)我想知道 在不使用的情况下将其插入或更新到 postgis 数据库中的最简单方法 用于创建 sql 字符串的字符串连接。 事实上,它可以创建具有上述结构的 SQL 字符串,但您想避免字符串连接,这就是我提出有关如何改用 PreparedStatement 占位符的问题的原因。 例如,以下 SQL 代码可以直接从 pgAdmin 执行(也可以通过 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;
但是,正如大多数开发人员所了解的那样,我们应该避免字符串连接,而是 使用占位符,例如如果使用 PreparedStatement(或者例如 JdbcTemplate 如果使用 Spring Framework)。
下面是一些代码来说明什么有效,什么无效。
我正在使用的 PostGIS 数据库 table 是使用以下语句创建的:
CREATE TABLE polygons (
polygonid serial NOT NULL,
geom geometry(Polygon,26918),
CONSTRAINT polygon_pkey PRIMARY KEY (polygonid)
);
在我的 Maven 文件中 pom.xml 我正在使用这个依赖项:
<dependency>
<groupId>net.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>2.2.0</version>
</dependency>
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();
也许解决方案是将 json 字符串转换为一些可以理解的 Java 对象 通过 PostGIS/PostgreSQL JDBC 驱动程序,然后使用方法 "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();
这个应该可以工作:您将 geojson 作为字符串传递。函数 ST_GeomFromGeoJSON 需要一个字符串作为第一个参数,因此可以准备和执行该语句。
你得到这个错误是因为你引用了问号。这样,问号就不会被解释为占位符!