springboot+mybatis对接使用postgresql中PostGIS地图坐标扩展类型字段
方案一(完全集成和自动解析):
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
使用 org.postgresql.geometric包下的 PGpoint 类来接收数据库中POINT类型,但是由于直接使用无法达到指定sql语句格式,需要重写一下getValue()方法
package com.ruoyi.protect.bean.control.countybound.po;
import org.postgresql.geometric.PGpoint;
public class MyPGPoint extends PGpoint {
public MyPGPoint(double x, double y){
super(x,y);
}
@Override
public String getValue() {
return isNull ? null : "ST_GeomFromText('POINT(" + x + " " + y + ")', 4326)";
}
}
mybatis原生类型中没有这个类型,需要自定义handler进行处理
package com.ruoyi.protect.handler;
import com.ruoyi.protect.bean.control.countybound.po.MyPGPoint;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PGpointTypeHandler extends BaseTypeHandler<MyPGPoint> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, MyPGPoint parameter, JdbcType jdbcType) throws SQLException {
// String param = "ST_GeomFromText('POINT(" + parameter.x + " " + parameter.y + ")', 4326)";
ps.setObject(i, parameter);
}
// 走的这个方法,所以先只重写这个,如果其他方法需要 思路一样
@Override
public MyPGPoint getNullableResult(ResultSet rs, String columnName) throws SQLException {
String pointStr = rs.getString(columnName);
// 解析从数据库中获取的字符串格式的point
if (pointStr!= null) {
pointStr = pointStr.replace("POINT", "");
pointStr = pointStr.substring(1, pointStr.length() - 1);
String[] coords = pointStr.split(" ");
double x = Double.parseDouble(coords[0]);
double y = Double.parseDouble(coords[1]);
return new MyPGPoint(x, y);
}
return null;
}
@Override
public MyPGPoint getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String pointStr = rs.getString(columnIndex);
if (pointStr!= null) {
pointStr = pointStr.substring(1, pointStr.length() - 1);
String[] coords = pointStr.split(",");
double x = Double.parseDouble(coords[0]);
double y = Double.parseDouble(coords[1]);
return new MyPGPoint(x, y);
}
return null;
}
@Override
public MyPGPoint getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String pointStr = cs.getString(columnIndex);
if (pointStr!= null) {
pointStr = pointStr.substring(1, pointStr.length() - 1);
String[] coords = pointStr.split(",");
double x = Double.parseDouble(coords[0]);
double y = Double.parseDouble(coords[1]);
return new MyPGPoint(x, y);
}
return null;
}
}
然后将这个hanler启动时加载,一般配置文件都可以指定加载自定义handler路径,如果是mybatis也有类似的配置项,也可以在配置类或者mybatis-config.xml中配置,反正目的就是把这个handler加载进去:
Mapper.xml中写法也有要求:
插入时要使用${} 否则#{}会带单引号;查询时要使用ST_AsText()包着,否则是一串二进制字符串;
<insert id="addPoint">
insert into gfa_point (
point_name,point_addr,point_coor) values
(#{gp.pointName},#{gp.pointAddr},
${gp.pointCoor} )
</insert>
<select id="selectPage" resultMap="BaseResultMap">
select
point_name,
point_addr,
ST_AsText(point_coor) pointCoor
from
gfa_point;
</select>
此时,启动项目就可以
方案二(更简便方式):
正常使用原生mybatis即可
1、创建实体类
@data
public class{
/**
* 经度
*/
@TableField(exist = false)
private double x;
/**
* 纬度
*/
@TableField(exist = false)
private double y;
}
2、数据库创建坐标类型
3、mapper.xml新增和查询写法
<insert id="addPoint">
insert into gfa_point (point_name,point_addr,point_coor) values
(#{gp.pointName},#{gp.pointAddr},
ST_GeomFromText('POINT(${gp.x} ${gp.y})', 4326))
</insert>
<select id="selectPage" resultMap="BaseResultMap">
select
point_name,
point_addr,
ST_X(point_coor) x,
ST_Y(point_coor) y
from
gfa_point;
</select>
设计表时对于坐标类型使用三个字段,double x ,double y, POINT p;在插入时Point需要特殊处理一下,sql语句使用x y 加上拼接就可以插入进去;查询时不需要查POINT类型,直接查x y就可以返回坐标值,计算时使用POINT类型字段:
INSERT INTO test1 (name, geom) VALUES ('Point A', ST_GeomFromText('POINT(116.40 39.90)', 4326));
INSERT INTO test1 (name, geom) VALUES ('Point bA',ST_SetSRID(ST_MakePoint(-122.3493, 47.6205), 4326));