Mybatis操作postgresql的postgis的一些总结
1、springboot项目连接postgresql数据库
导入postgresql的依赖
xml
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
导入mybatisplus的依赖
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
数据库连接池依赖
xml
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
配置yml文件中postgresql的连接 ==连接的URL要说明数据库名称和选择的架构==
yml
# 数据源配置
spring:
datasource:
# 数据库连接URL要说明数据库名称和选择的架构
url: jdbc:postgresql://localhost:5432/postgis_35_sample?currentSchema=public
# 数据库用户名
username: postgres
# 数据库密码
password: 123456
# 数据库驱动类名
driver-class-name: org.postgresql.Driver
# 指定数据源类型(这里使用 HikariCP 连接池)
type: com.zaxxer.hikari.HikariDataSource
# HikariCP 连接池配置
hikari:
# 连接池的名称,方便在监控工具中识别
pool-name: PostGISPool
# 最小空闲连接数,建议设置为10-30%的最大连接池大小
minimum-idle: 10
# 最大连接池大小,根据应用并发量和数据库负载调整
maximum-pool-size: 30
# 是否启用自动提交,true为启用(默认值)
auto-commit: true
# 获取连接的超时时间(毫秒),增加到60秒以应对可能的网络延迟
connection-timeout: 60000 # 60 seconds
# 连接验证的超时时间(毫秒)
validation-timeout: 30000 # 30 seconds
# 连接的最大生命周期(毫秒),避免长时间占用连接
max-lifetime: 1800000 # 30 minutes
# 获取连接后执行的 SQL 语句,用于验证连接是否有效
connection-init-sql: SELECT 1
# 连接泄漏检测时间(毫秒),可帮助发现连接未关闭的情况
leak-detection-threshold: 30000 # 30 seconds
# 是否注册JMX MBeans,方便通过JMX监控连接池状态
register-mbeans: true
# MyBatis Plus 配置
mybatis-plus:
# 将执行的 SQL 语句和相关信息打印到标准输出(如控制台)
configuration:
# 启用 MyBatis 的日志输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 指定 MyBatis POJO 类所在的包
type-aliases-package: com.postgis.pojo
# 全局配置
global-config:
# 数据库配置
db-config:
# 设置 ID 生成策略为自增
id-type: AUTO
# 指定 Mapper XML 文件的扫描路径
mapper-locations: classpath*:mapper/**/*.xml
# 日志配置
logging:
# 配置日志级别
level:
# 设置 com.postgis 包下的日志级别为 DEBUG,方便调试
com.postgis: debug
2、关于postgis数据库表映射的实体类的相关配置
- ==一定要有一个geom字段==映射到postgis的geomtry字段,==x、y坐标在数据库表中没有映射的字段,但是可以从geom字段中解析出来==
- ==不要使用Lombok注解==提供的getter和setter方法,会出现bug
java
/**
* 这是一个数据传输对象(Data Transfer Object, DTO),用于映射数据库表 "locations" 中的数据。
* 该类提供了与数据库表 "locations" 中字段相对应的 Java 属性,并通过注解定义了它们之间的映射关系。
*/
@TableName(value = "locations")
public class Location{
@TableId
private Integer id;
private String name;
/**
* 存储几何位置的几何数据。
* 通常用于存储空间坐标信息,如点、线、面等。
* 在 PostGIS 中,可能使用 geometry 类型来存储。
*/
private String geom;
// x、y坐标在数据库表中没有映射的字段,但是可以从geom字段中解析出来
/**
* X 坐标
*/
@TableField(exist = false)
private double xCoord;
/**
* Y 坐标
*/
@TableField(exist = false)
private double yCoord;
// Getters 和 Setters 方法(不要使用lombok,会出问题)
......
}
3、Mapper层sql语句中关于geometry字段映射的注意事项
SQL语句中常用的将WKB类型转为Java可以表示的类型的函数
ST_AsText (geometry):将几何对象转换为WKT格式。(string类型) ST_AsGeoJSON (geometry):将几何对象转换为GeoJSON格式。(string类型) ST_X(point) :返回点的X坐标 (返回double类型)。 ST_Y(point):返回点的Y坐标 (返回double类型)。
一、 映射所有字段不要使用select * from db,要把所要的字段写出来,同时==关于geometry类型的字段要使用AS指定为实体类==中的字段名称。
java
@Select("SELECT id, name, ST_X(geom) AS x_coord, ST_Y(geom) AS y_coord, ST_AsGeoJSON(geom) AS geom FROM locations WHERE id = #{id};")
Location findGeoJsonById(Long id);
查询结果
json
{"id":13,"name":"Location D","geom":"{\"type\":\"Point\",\"coordinates\":[116.3974,39.984]}","xCoord":0.0,"yCoord":0.0}
二、直接使用String类型接收geom字段的WKB值
java
@Select("SELECT id, name, geom FROM locations WHERE id = #{id}")
Location findGeoJsonById(Long id);
返回值
json
{"id":11,"name":"Location B","geom":"0101000020E6100000F1A0D9756F195D4032207BBDFBFD4340","xCoord":0.0,"yCoord":0.0}
根据返回值可见,string类型的geom字段存储了wkb十六进制数据,对此 ==Java的GeoTools可以提供强大的方法解析wkb十六进制数据==。
4、GeoTools解析WKB数据为geojson数据
GeoTools主要功能
1、数据访问:
支持多种地理数据格式,如 Shapefile、GeoJSON、KML、GML、PostGIS 等。 可以从不同来源读取和写入地理数据,包括数据库和文件系统。
2、空间分析:
提供几何操作和空间分析功能,允许用户执行缓冲区、重投影、空间查询等操作。
3、地图渲染:
具有强大的渲染和符号化功能,可以创建地图图层,并根据所需样式动态渲染地理数据。
4、支持标准:
遵循 OGC(开放地理空间联盟)标准,支持各种网络服务功能(如 WMS 和 WFS)。 能够与其他 GIS 组件(如 GeoServer)无缝集成。 aliyunmaven * 阿里云公共仓库 maven.aliyun.com/repository/...
添加将WKB 字符串转换为GeoJSON 格式的工具类
1、配置依赖
需要改自己 maven 的镜像源配置如下:
xml
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>*,!osgeo,!maven2-repository.dev.java.net,!boundless</mirrorOf>
</mirror>
需要添加 repository如下: (与dependencies标签同一级别)
xml
<repositories>
<repository>
<id>osgeo</id>
<name>OSGeo</name>
<url>https://repo.osgeo.org/repository/release/</url>
</repository>
</repositories>
之后就可以成功导入geotools的依赖了,注意消除依赖冲突 消除依赖冲突的方法
xml
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>24.0</version>
<exclusions>
<exclusion>
<groupId>tech.units</groupId>
<artifactId>indriya</artifactId>
</exclusion>
<exclusion>
<groupId>si.uom</groupId>
<artifactId>si-quantity</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>24.0</version>
</dependency>
2、添加工具类
在utils包下新建将WKB 字符串转换为 GeoJSON格式数据(Map<String, Object>)的工具类
java
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
@Slf4j
public class WKBToGeoJSONUtil {
/**
* 将WKB十六进制字符串转换为GeoJSON格式的Map
* @param hexWKB PostGIS返回的WKB十六进制字符串
* @param decimals 保留的小数位数
* @return 对应GeoJSON结构的Map
* @throws Exception 如果解析WKB或生成GeoJSON时发生错误
*/
public static Map<String, Object> convert(String hexWKB, int decimals) throws Exception {
// 解析WKB字符串为JTS Geometry对象
Geometry geometry = parseWKB(hexWKB);
// 将Geometry对象转换为GeoJSON Map
return convertToGeoJSONMap(geometry, decimals);
}
/**
* 解析WKB字符串为JTS Geometry对象
* @param hexWKB WKB十六进制字符串
* @return 解析后的Geometry对象
* @throws Exception 如果解析WKB时发生错误
*/
private static Geometry parseWKB(String hexWKB) throws Exception {
try {
// 创建WKBReader实例
WKBReader wkbReader = new WKBReader();
// 将十六进制字符串转换为字节数组
byte[] wkbBytes = WKBReader.hexToBytes(hexWKB);
// 解析字节数组为Geometry对象
return wkbReader.read(wkbBytes);
} catch (ParseException e) {
// 如果解析失败,记录错误并抛出异常
log.error("Failed to parse WKB string: {}", hexWKB, e);
throw new Exception("Failed to parse WKB string", e);
}
}
/**
* 将Geometry对象转换为GeoJSON Map
* @param geometry JTS Geometry对象
* @param decimals 保留的小数位数
* @return GeoJSON格式的Map
* @throws IOException 如果生成GeoJSON时发生错误
*/
private static Map<String, Object> convertToGeoJSONMap(Geometry geometry, int decimals) throws IOException {
try {
// 创建GeometryJSON实例,指定小数位数
GeometryJSON geometryJSON = new GeometryJSON(decimals);
// 使用StringWriter生成GeoJSON字符串
StringWriter writer = new StringWriter();
geometryJSON.write(geometry, writer);
String geoJsonStr = writer.toString();
// 使用Jackson将GeoJSON字符串转换为Map
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(geoJsonStr, new TypeReference<Map<String, Object>>() {});
} catch (IOException e) {
// 如果生成GeoJSON或解析GeoJSON时失败,记录错误并抛出异常
log.error("Failed to convert Geometry to GeoJSON Map", e);
throw new IOException("Failed to convert Geometry to GeoJSON Map", e);
}
}
/**
* 测试方法
*/
public static void main(String[] args) {
// 示例 WKB 字符串
String wkb = "0101000020E6100000B6F3FDD478195D40E7FBA9F1D2FD4340"; // 示例WKB字符串
// 调用工具类方法
Map<String, Object> geoJsonMap = null;
try {
geoJsonMap = convert(wkb, 6); // 转换为GeoJSON,保留6位小数
} catch (Exception e) {
log.error("Error converting WKB to GeoJSON", e);
throw new RuntimeException(e);
}
// 打印结果
log.info("GeoJSON Map: {}", geoJsonMap);
}
}
通过这种方式,你可以将PostGIS中的WKB数据转换为GeoJSON格式的Map,方便在前端或其他系统中使用。
3、设计返回给前端的VO实体类
==将Map返回给前端,方便调用==
java
@NoArgsConstructor
@AllArgsConstructor
@Data
public class LocationVO {
@TableId
private Integer id;
private String name;
// 将Map返回给前端,方便调用
private Map<String, Object> geoJson;
}
4、service层调用
java
public LocationVO findGeoJsonById(Long id) {
Location geoJsonById = locationsMapper.findGeoJsonById(id);
LocationVO locationVO = new LocationVO();
BeanUtils.copyProperties(geoJsonById, locationVO);
try {
locationVO.setGeoJson(WKBToGeoJSONUtil.convert(geoJsonById.getGeom(), 6));
} catch (Exception e) {
throw new RuntimeException(e);
}
return locationVO;
}
返回结果
json
{
"id": 11,
"name": "Location B",
"geoJson": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
115.737332,
28.640312
],
[
115.73762,
28.640515
],
[
115.73826,
28.639818
],
[
115.737973,
28.639615
],
[
115.737332,
28.640312
]
]
]
]
}
}