Postgis - 如何通过 JDBC 使用数据类型 'geography'

Postgis - How to work with data type 'geography' via JDBC

正在使用 postgresql 9.3 postgis 2.1.

进行 Web 项目

table中有一个geography类型的列,它只存储了一个point

现在我需要通过 JDBC 和 Java 对象插入/select 类型。

阅读 postgis 手册后,没有找到太多相关信息。

题目是:

  1. 在 java pojo 模型 class 中,列应使用哪种 Java 数据类型?
  2. 如何写插入sql?
  3. 如何编写 select sql 来检索值并放入 Java 对象?
  4. 如果使用mybatis,是否影响上述问题的答案?

POINT 几何不需要特殊类型。只需使用像 double 这样的原始数据类型作为坐标。

例如,要通过 lonlat 参数插入新的 geography 类型,请使用 geometry constructor functions:

INSERT INTO my_table (geog)
VALUES (ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)::geography);

或者将它们作为浮点数返回,使用 geometry accessor functions:

SELECT ST_Y(geog::geometry) AS lat, ST_X(geog::geometry) AS lon FROM my_table;

还有其他 input/output 格式,例如 GeoJSON、WKT 等

如果你使用的是Mybatis,你可以使用TypeHandler透明地进行纬度和经度之间的转换。以下是我在像您的 PostGIS、Mybatis 和 Gegraphy 需要的场景中是如何做到的。使用 TypeHandler 可以处理不同的 classes,您可以将几何类型包装到其中。在我的例子中,坐标有两个 double 属性,latitudelongitude.

坐标class

public class Coordinate {
    private Double latitude;
    private Double latitude;
    ... getters, setters, etc
}

声明 Ibati 的 TypeHandler

@MappedJdbcTypes(JdbcType.JAVA_OBJECT)
@MappedTypes({Coordinate.class})
public class CoordinateTypeHandler extends BaseTypeHandler<Coordinate> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Coordinate parameter, JdbcType jdbcType) throws SQLException {
        // Convert Coordinate to Ibatis representation of Postgis point, e.g., "SRID=4326;POINT(2.294801 48.858007)"
        Point point = new Point(parameter.getLongitude(), parameter.getLatitude());
        point.setSrid(4326);
        ps.setString(i, point.toString());
    }

    // Convert data read from Ibatis to actual Coordinate class
    @Override
    public Coordinate getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return from(rs.getString(columnName));
    }

    @Override
    public Coordinate getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return from(rs.getString(columnIndex));
    }

    @Override
    public Coordinate getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return from(cs.getString(columnIndex));
    }

    protected Coordinate from(String pointAsText) throws SQLException {
        if (pointAsText != null) {
            Point point = new Point(pointAsText);
            return new Coordinate(point.getY(), point.getX());
        }
        return null;
    }
}

然后在 Ibatis 的界面上准备 select。参考这里的用法'as coordinate',是说让ibatis去寻找坐标类型的表示,就是你刚才定义的CoordinateTypeHandler处理的

重要的是要知道下面的 location 在您的 table 定义中被声明为 location geography(POINT, 4326)

@Select("SELECT " +
        "ST_AsText(location) AS coordinate" +
    "FROM " +
        "mytable " +
    "WHERE " +
        "tableattribute = #{myattribute}")
List<Result> myFindMethod(
        @Param("myattribute") Integer myattribute
);

此解决方案将为 class 的 Coordinate-kind 提供干净的抽象,将 latitudelongitude 属性包装到 PostGIS 上的 SRID=4326;POINT(2.294801 48.858007) 表示。考虑到 Mike T. 的解决方案,您需要为要在 API/service.

上创建的每个查询重写相同的 (ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)::geography)

使用 TypeHandler 旨在避免这种情况,一旦您 change/add 表示您 TypeHandler,它会直接反映在您使用的每个查询中 as coordinate.

如果你使用 MyBatis,MyBatis 中有一个 Postgis 类型的小项目。并且已经添加到maven central,可以直接从maven中使用

https://github.com/eyougo/mybatis-typehandlers-postgis