1.前言 PostGIS无疑是GIS领域一个非常重要的项目。
2.Geojson转入postgis中
3.将shp文件导入到postgis中 在 mac 版本中的 shp2pgsql 工具路径在 “/Library/PostgreSQL/15/bin/shp2pgsql” 路径下。
1 shp2pgsql -c 路径/shp数据文件名 新建的数据表名 数据库名|psql -d 数据库名 -U 用户名
5.MybatisPlus 返回 geojson 数据 这里其实有个两种思路,使用sql语句,或者使用 java 进行拼接。
5.1.使用sql语句进行转换 一种就是直接使用 postgis 提供的sql语句,将数据库中的数据转为 geojson 字符串,然后通过 JSONObject 对象转成 json 对象返回给前端。
(1)定义mapper.xml
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 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.openmap.disaster.mapper.RfdwdMapper" > <select id ="queryGeojson" resultType ="java.lang.String" > SELECT row_to_json(fc) as geojson FROM ( SELECT 'FeatureCollection' AS type , array_to_json(array_agg(f)) AS features FROM ( SELECT 'feature' AS type , ST_AsGeoJSON(shape)::json as geometry , ( SELECT row_to_json(t) FROM ( SELECT id ) AS t ) AS properties FROM map_rfdwd mr ) AS f ) AS fc </select > </mapper >
(2) 分别实现 Mapper、IService和 ServiceImpl 接口 这里我就简单的贴上 ServiceImpl 实现的方法,Mapper 和 IService 都只需要定义一个 String queryGeojson(); 方法就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service public class RfdwdServiceImpl extends ServiceImpl <RfdwdMapper, Rfdwd> implements IRfdwdService { @Resource private RfdwdMapper rfdwdMapper; public String queryGeojson () { String result=rfdwdMapper.queryGeojson(); return result; } }
(3) 在 Controller 层实现 IService 接口的调用
1 2 3 4 5 public Result<JSONObject> queryGeojson () { String rfdwd=rfdwdService.queryGeojson(); JSONObject result=JSONObject.parseObject(rfdwd); return Result.OK(result); }
5.2使用转换器进行转换 另外一种就是在使用 mybatis-plus 的使用,自定义一个类型转换器,将geom字段转换为 geojson 格式,然后在进行属性的拼接。
(1) pom.xml 中增加依赖 这里我稍微的做了变动,就是把依赖的版本提升了。
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 <properties > <geotools.version > 29.2</geotools.version > </properties > <dependencies > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-geojson</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-swing</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-jdbc</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools.jdbc</groupId > <artifactId > gt-jdbc-postgis</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-epsg-hsql</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-shapefile</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-main</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-api</artifactId > <version > 20.5</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-opengis</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-data</artifactId > <version > 20.5</version > </dependency > <dependency > <groupId > org.geotools</groupId > <artifactId > gt-referencing</artifactId > <version > ${geotools.version}</version > </dependency > <dependency > <groupId > net.postgis</groupId > <artifactId > postgis-jdbc</artifactId > <version > 2.5.0</version > </dependency > <repositories > <repository > <id > osgeo</id > <name > OSGeo Release Repository</name > <url > https://repo.osgeo.org/repository/release/</url > <snapshots > <enabled > false</enabled > </snapshots > <releases > <enabled > true</enabled > </releases > </repository > <repository > <id > osgeo-snapshot</id > <name > OSGeo Snapshot Repository</name > <url > https://repo.osgeo.org/repository/snapshot/</url > <snapshots > <enabled > true</enabled > </snapshots > <releases > <enabled > false</enabled > </releases > </repository > </repositories >
(2) 编写转换器
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 package com.openmap.disaster.config;import org.apache.ibatis.type.BaseTypeHandler;import org.apache.ibatis.type.JdbcType;import org.apache.ibatis.type.MappedTypes;import org.geotools.geojson.geom.GeometryJSON;import org.geotools.geometry.jts.WKBReader;import org.locationtech.jts.geom.Geometry;import org.locationtech.jts.io.ParseException;import org.postgis.PGgeography;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;@MappedTypes({String.class}) public class GeographyTypeHandler extends BaseTypeHandler <String> { @Override public void setNonNullParameter (PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { PGgeography pGgeography = new PGgeography (parameter); ps.setObject(i, pGgeography); } @Override public String getNullableResult (ResultSet rs, String columnName) throws SQLException { PGgeography pGgeography = new PGgeography (rs.getString(columnName)); if (pGgeography == null ) { return null ; } return pGgeography.toString(); } @Override public String getNullableResult (ResultSet rs, int columnIndex) throws SQLException { PGgeography pGgeography = new PGgeography (rs.getString(columnIndex)); if (pGgeography == null ) { return null ; } return pGgeography.toString(); } @Override public String getNullableResult (CallableStatement cs, int columnIndex) throws SQLException { PGgeography pGgeography = new PGgeography (cs.getString(columnIndex)); if (pGgeography == null ) { return null ; } return pGgeography.toString(); } @Override public String getResult (ResultSet rs, String columnName) throws SQLException { String WKB = rs.getString(columnName); if (WKB==null ){ return null ; } WKBReader reader = new WKBReader (); Geometry geometry = null ; try { geometry = reader.read(WKBReader.hexToBytes(WKB)); } catch (ParseException e) { return null ; } GeometryJSON geometryJson = new GeometryJSON (16 ); return geometryJson.toString(geometry); } }
(3) 应用转换器 在实体类上需要指定转换器,并且实体类注解TableName 补充 autoResultMap = true
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 package com.openmap.disaster.entity;import java.io.Serializable;import java.io.UnsupportedEncodingException;import java.util.Date;import java.math.BigDecimal;import com.baomidou.mybatisplus.annotation.*;import com.openmap.disaster.config.GeographyTypeHandler;import lombok.Data;import com.fasterxml.jackson.annotation.JsonFormat;import org.springframework.format.annotation.DateTimeFormat;import org.jeecgframework.poi.excel.annotation.Excel;import org.jeecg.common.aspect.annotation.Dict;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data @TableName(value = "map_rfdwd",autoResultMap = true) public class Rfdwd implements Serializable { private static final long serialVersionUID = 1L ; @TableField(typeHandler = GeographyTypeHandler.class) private String shape; }
(4) 结果 最终的结果,就是将这个 shape 字段转换成了geojson字符串。
1 2 3 { "shape" : '{ "type" : "Point" , "coordinates" : [ 120.02095677700004 , 30.23700725300006 , 0.0 ] } ' }
5.3.Error setting non null for parameter #18 with JdbcType null 在使用转换器进行将geojson转为数据库类型的时候,出现了这个问题: Could not set parameters for mapping: ParameterMapping{property=’et.shape’, mode=IN, javaType=class java.lang.Object, jdbcType=STRUCT, numericScale=null, resultMapId=’null’, jdbcTypeName=’null’, expression=’null’},Unknown type: {“type”:”Point”,”coordinates”:[120.00888900000008,30.283056000000045]}
1 2 3 4 @Excel(name = "shape", width = 15) @ApiModelProperty(value = "shape") @TableField(typeHandler = GeographyTypeHandler.class) private String shape;
转换函数:
1 2 3 4 5 6 7 8 9 10 @MappedTypes({String.class}) public class GeographyTypeHandler extends BaseTypeHandler <String> { private static final Logger logger= LoggerFactory.getLogger(GeographyTypeHandler.class); @Override public void setNonNullParameter (@NotNull PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { PGgeography pGgeography = new PGgeography (s1); ps.setObject(i, pGgeography); } }
【解决方案】 修改了转换方法,就是将geojson格式,读取为wkt格式,然后转换为 geometry 类型,更新到数据库中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Override public void setNonNullParameter (@NotNull PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { try { GeometryJSON geometryJson = new GeometryJSON (16 ); Geometry geometry = geometryJson.read(parameter); WKBWriter wkbWriter = new WKBWriter (); byte [] write = wkbWriter.write(geometry); String s1 = WKBWriter.toHex(write); PGgeometry pGgeometry=new PGgeometry (s1); ps.setObject(i, pGgeometry); }catch (Exception e){ logger.error("GeographyTypeHandler" ,e); } }