小背景 在postgis中存在一些空间先关的函数,比如ST_AsEWKT,ST_AsGeoJSON 函数可以把空间数据转为我们常用的wkt,geojson格式等,但是这种方式都需要修改xml
比如这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <update id ="updateProjectGeom" prameterType ="com.xs.model.Project" > UPDATE project SET geom = ST_GeomFromEWKT(#{geom}), name = #{name} WHERE id = #{id} </update > <select id ="selectProjectById" parameterType ="int" resultType ="com.xs.model.Project" > SELECT id, name, ST_AsEWKT(geom) AS geom FROM project WHERE id = #{id} </select >
这样就回到传统的ssm结构,比如查询的时候就需要去写一个查询,通用一点的在更新或查询的时候使用动态的表名,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <update id ="updateProjectGeom" prameterType ="com.xs.model.Project" > UPDATE ${tableName} SET geom = ST_GeomFromEWKT(#{geom}) WHERE id = #{id} </update > <select id ="selectProjectById" parameterType ="int" resultType ="java.lang.String" > SELECT ST_AsEWKT(geom) AS geom FROM ${tableName} WHERE id = #{id} </select >
上边的方法也不是很优雅,pg数据支持使用PGGeometry的Handler,可以解决查询的问题,但是有一定的问题,java后端需要使用geotools,需要转为jts的对象才方面我们的操作,所以我们可以通过handle准转为我们需要的jts的Geometry类 下边展示
准备转换工具类,由于pg支持PgGeometry,可以直接转wkt格式,那么我可以基于这个转geojson,保存的时候数据库存储的是十六进制的字节数组,也需要wkb的转换,准备工具类1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 import org.geotools.geojson.geom.GeometryJSON;import org.locationtech.jts.geom.Geometry;import org.locationtech.jts.io.*;import java.io.IOException;import java.io.Reader;import java.io.StringReader;import java.io.UnsupportedEncodingException;import java.nio.charset.StandardCharsets;public class GeometryDataCoverUtils { public static Geometry geoJsonToGeometry (String data) throws IOException { Reader reader = new StringReader (data); GeometryJSON gjson = new GeometryJSON (); return gjson.read(reader); } public static String geometryToGeoJson (Geometry geometry) { GeometryJSON g = new GeometryJSON (15 ); return g.toString(geometry); } public static Geometry wktToGeometry (String data) throws ParseException { WKTReader reader = new WKTReader (); return reader.read(data); } public static String geometryToWkt (Geometry geometry) { WKTWriter writer = new WKTWriter (); return writer.write(geometry); } public static String wktToGeoJson (String data) throws ParseException { return geometryToGeoJson(wktToGeometry(data)); } public static String geoJsonToWkt (String data) throws IOException { return geometryToWkt(geoJsonToGeometry(data)); } public static Geometry wkbToGeometry (String data) throws ParseException { byte [] bytes = WKBReader.hexToBytes(data); org.locationtech.jts.io.WKBReader reader = new org .locationtech.jts.io.WKBReader(); return reader.read(bytes); } public static String geometryToWkb (Geometry geometry) throws UnsupportedEncodingException { WKBWriter writer = new WKBWriter (); byte [] write = writer.write(geometry); return WKBWriter.toHex(write); } public static byte [] geometryToWkbArr(Geometry geometry) { WKBWriter writer = new WKBWriter (); return writer.write(geometry); } }
先实现WKt格式的转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @MappedJdbcTypes(JdbcType.OTHER) @MappedTypes({String.class}) public class WktTypeHandler extends BaseTypeHandler <String> { @Override public void setNonNullParameter (PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { WKTReader wktReader = new WKTReader (); PGgeometry pGgeometry = null ; try { pGgeometry = new PGgeometry (wktReader.read(parameter).toText()); } catch (ParseException e) { throw new RuntimeException (e); } pGgeometry.getGeometry().setSrid(4326 ); ps.setObject(i, pGgeometry); } @Override public String getNullableResult (ResultSet rs, String columnName) throws SQLException { String string = rs.getString(columnName); return getResult(string); } @Override public String getNullableResult (ResultSet rs, int columnIndex) throws SQLException { String string = rs.getString(columnIndex); return getResult(string); } @Override public String getNullableResult (CallableStatement cs, int columnIndex) throws SQLException { String string = cs.getString(columnIndex); return getResult(string); } private String getResult (String string) throws SQLException { return getWkt(string); } private String getWkt (String string) throws SQLException { if (StrUtil.isBlank(string)) { return null ; } PGgeometry pGgeometry= new PGgeometry (string); String s = pGgeometry.toString(); return s.replace("SRID=4326;" , "" ); } }
还有geojson格式的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 @MappedTypes({String.class}) @MappedJdbcTypes({JdbcType.OTHER}) @Slf4j public class GeoJsonHandler extends BaseTypeHandler <String> { @Override public void setNonNullParameter (PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { try { String wkt = GeometryDataCoverUtils.geoJsonToWkt(parameter); WKTReader wktReader = new WKTReader (); PGgeometry pGgeometry = new PGgeometry (wktReader.read(wkt).toText()); pGgeometry.getGeometry().setSrid(4326 ); ps.setObject(i, pGgeometry); } catch (IOException | ParseException e) { throw new RuntimeException (e); } } @Override public String getNullableResult (ResultSet rs, String columnName) throws SQLException { String string = rs.getString(columnName); return getResult(string); } @Override public String getNullableResult (ResultSet rs, int columnIndex) throws SQLException { String string = rs.getString(columnIndex); return getResult(string); } @Override public String getNullableResult (CallableStatement cs, int columnIndex) throws SQLException { String string = cs.getString(columnIndex); return getResult(string); } private String getResult (String string) throws SQLException { return getWkt(string); } private String getWkt (String string) throws SQLException { if (StrUtil.isBlank(string)) { return null ; } PGgeometry pGgeometry= new PGgeometry (string); String s = pGgeometry.toString(); String replace = s.replace("SRID=4326;" , "" ); try { return GeometryDataCoverUtils.wktToGeoJson(replace); } catch (ParseException e) { throw new RuntimeException (e); } } }
如果我们需要转为Jts的Geometry
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @MappedJdbcTypes(JdbcType.OTHER) @MappedTypes({Geometry.class}) public class WktGeometryTypeHandler extends BaseTypeHandler <Geometry> { @Override public void setNonNullParameter (PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException { byte [] bytes = GeometryDataCoverUtils.geometryToWkbArr(parameter); ps.setBytes(i, bytes); } @Override public Geometry getNullableResult (ResultSet rs, String columnName) throws SQLException { String string = rs.getString(columnName); return getGgeometry(string); } @Override public Geometry getNullableResult (ResultSet rs, int columnIndex) throws SQLException { String string = rs.getString(columnIndex); return getGgeometry(string); } @Override public Geometry getNullableResult (CallableStatement cs, int columnIndex) throws SQLException { String string = cs.getString(columnIndex); return getGgeometry(string); } private Geometry getGgeometry (String string) { if (StrUtil.isBlank(string)) { return null ; } try { return GeometryDataCoverUtils.wkbToGeometry(string); } catch (ParseException e) { throw new RuntimeException (e); } } }
在实体上做修改,
1 2 3 4 5 6 7 8 9 10 11 @Data public class Project { private Integer id; private String name; @TableField(typeHandler = WktTypeHandler.class, value = "geom") private String geom; }
修改mybatis的配置
1 mybatis-plus.type-handlers-package=com.xs.handler
就可以实现查询,保存的时候自动转换,不用在写xml了
总结
mybatis配置需要注入handler