Spring Boot + MyBatis plus + MySQL 实现位置直线距离实时计算

一、背景

在一些服务类系统开发时,难免遇到一些服务者和客户之间的一些距离计算,更方便的让服务者了解客户的地址,更好的方式就是调用地图sdk或者api实现,但有些需要通过接口查看多个地点的直线距离时,接口请求会比较多,比如我当前接入的地图接口,每秒请求不能超过三次,因此不符合我们一次查多个地点的位置;所以需要借助其他方式实现;

二、解决方案

  1. 在表结构中添加字段

在添加的字段中存客户的经纬度坐标,前提是客户的位置是固定的,字段类型为point类型

添加字段脚本为

sql 复制代码
ALTER TABLE merchant_shop ADD COLUMN geo_point POINT  null comment '地理坐标';
ALTER TABLE merchant_shop ADD SPATIAL INDEX idx_geo_point(geo_point);

2.在表结构对应实体添加位置字段

java 复制代码
  /**
     * MybatisX 会自动识别 POINT 类型,并使用对应的 TypeHandler
     * 它通常会引入 org.locationtech.jts.geom.Point
     */
    @TableField(value = "geo_point",typeHandler = GeoPointTypeHandler.class // 引用你自己的TypeHandler
    )
    private Point geoPoint;

3.引入集合空间计算和分析依赖

JTS(Java Topology Suite)库是一个强大的几何处理工具,提供了丰富的几何对象创建、操作和分析功能。通过JTS,你可以进行各种几何计算和空间分析,并将几何对象转换为标准的WKT格式以便于存储和传输。在实际应用中,JTS广泛用于地理信息系统(GIS)、地图服务和空间数据处理等领域。

java 复制代码
  <dependency>
            <groupId>org.locationtech.jts</groupId>
            <artifactId>jts-core</artifactId>
            <version>1.18.2</version> <!-- 建议使用较新版本 -->
        </dependency>

4.自定实现TypeHandler,处理经纬度坐标

java 复制代码
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKTReader;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class GeoPointTypeHandler  extends BaseTypeHandler<Point> {

    // SRID 4326 对应 WGS84 坐标系 (GPS 使用的坐标系)
    public static final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
    private static final WKBReader wkbReader = new WKBReader(geometryFactory);
    private static final WKTReader wktReader = new WKTReader(geometryFactory);

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Point parameter, JdbcType jdbcType) throws SQLException {
        // 将 Java 的 Point 对象写入数据库
        ps.setObject(i, parameter);
    }

    @Override
    public Point getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return getPointFromResultSet(rs.getObject(columnName));
    }

    @Override
    public Point getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return getPointFromResultSet(rs.getObject(columnIndex));
    }

    @Override
    public Point getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return getPointFromResultSet(cs.getObject(columnIndex));
    }

    /**
     * 从数据库返回的对象中解析出 Point 对象
     * 数据库驱动可能返回 byte[] (WKB) 或 String (WKT)
     */
    private Point getPointFromResultSet(Object obj) throws SQLException {
        if (obj == null) {
            return null;
        }
        if (obj instanceof Point) {
            return (Point) obj;
        }
        try {
            if (obj instanceof byte[]) {
                // 处理 WKB (Well-Known Binary) 格式
                return (Point) wkbReader.read((byte[]) obj);
            } else if (obj instanceof String) {
                // 处理 WKT (Well-Known Text) 格式, e.g., "POINT(103.87 36.05)"
                return (Point) wktReader.read((String) obj);
            }
        } catch (ParseException e) {
            throw new SQLException("Error parsing geometry from database: " + e.getMessage(), e);
        }
        throw new SQLException("Unsupported geometry type returned from database: " + obj.getClass().getName());
    }
}

5.通过SQL脚本查询实现,查询过程使用MySQL现有函数ST_Distance_Sphere

ST_Distance_Sphere 是MySQL中的一个空间函数,它用于计算球面上两点之间的最小距离。这个函数非常有用,特别是在处理地理位置数据时,比如计算两个地点之间的直线距离

sql 复制代码
 SELECT  
    ms.*, 
    ST_Distance_Sphere(geo_point,
        POINT(#{latValue}, #{lngValue})
        ) AS linearDistance
 FROM merchant_shop ms

注:latValue 为当前位置的精度, lngValue为当前位置的维度;

通过以上方案可以实现距离计算,就可以不用频繁调用三方地图接口;

相关推荐
小明bishe188 小时前
计算机毕业设计之基于JAVA的植物科普网站
java·spring boot·spring·架构·课程设计
万亿少女的梦16810 小时前
基于Python的高考志愿填报辅助系统设计与实现
java·spring boot·python·mysql·vue
万亿少女的梦16811 小时前
基于SpringBoot与Vue的历史博物馆展品展示与游客管理系统设计
spring boot·mysql·vue·系统设计·博物馆管理系统
灯澜忆梦13 小时前
MySQL 完整学习路线
学习·mysql
ClouGence13 小时前
保障公共安全,一线治安机构实时数据应用与实践
数据库·mysql·postgresql
Minxinbb14 小时前
TDSQL for MySQL 服务器重启操作
数据库·mysql·dba
cfm_291414 小时前
SpringBoot MockMvc
spring boot·后端·log4j
渣渣灰飞15 小时前
MySQL 系统学习 第二阶段 第三章 DQL(Data Query Language)第三节:ORDER BY + LIMIT(排序 + 分页)
数据库·学习·mysql
北极星日淘16 小时前
实时汇率结算系统开发|SpringBoot+Redis实现无差价跨境计费解决方案
spring boot·后端·bootstrap
fengbingchun17 小时前
客户端获取服务器端MySQL数据库表中数据C++实现
mysql