当前位置: 首页 > news >正文

SpringBoot+MyBatis+MySQL的Point实现范围查找

前言

最近做了一个功能,需要通过用户当前位置点获取指定范围内的数据。由于后端存储用的是 MySQL,故选择使用 MySQL 中的 Point 实现范围查找功能。ORM 框架用的是 MyBatis,MyBatis 原生并不支持 Point 字段与 POJO 的映射,需要自定义 MyBatis 的 TypeHandler 实现该功能。

当然,你可以通过定义两个 MySQL 字段(经度和维度)来代替 Point 也可以实现范围查找,但是既然是使用的 MyBatis,那么还是希望能在 MyBatis 中直接操作 Point,提高代码通用性。

关于 MySQL 的 POINT

在MySQL中,POINT 是一种用于存储地理空间数据的数据类型,它表示二维空间中的一个点。MySQL 从 5.7 版本开始,提供了对地理空间数据类型的原生支持,包括 POINT、LINESTRING、POLYGON 等。

POINT 数据类型用于存储一个二维坐标点,其格式为 (X, Y),其中 X 和 Y 分别表示该点在二维平面上的横坐标和纵坐标。

注意,在用 POINT 存储经纬度时,X 为经度,Y 为纬度,不要弄反了。因为将经纬度存储到 POINT 时并没有循序限制,但是使用 POINT 相关函数时就有限制了。比如ST_Distance_Sphere

组件版本

  • SpringBoot 2.4.3
  • MyBatis-Plus 3.4.2
  • MySQL 8.0.26

建表(含 POINT 字段)

create table group_ride_info
(id             bigint unsigned                            not null comment '主键id'primary key,create_time    datetime                                   not null comment '创建时间',update_time    datetime         default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '修改时间',create_by      int unsigned     default '0'               not null comment '创建人',update_by      int unsigned     default '0'               not null comment '修改人',is_delete      tinyint unsigned default '0'               not null comment '是否删除。默认0,1-是,0-否',...create_point   point                                      not null comment '创建时坐标'
)comment '团信息表';create spatial index create_pointon group_ride_info (create_point);

其中,create_point 是通过 POINT 字段记录的经纬度坐标,POINT 字段建议设置为为空。同时需要给 PIOINT 类型字段创建空间索引。

alter table group_ride_info add SPATIAL index(create_point);

定义 GeoPoint 对象

@Builder
@AllArgsConstructor
@Data
public class GeoPoint implements Serializable {/*** 经度*/private Double longitude;/*** 纬度*/private Double latitude;
}

定义表对象

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("group_ride_info")
@ApiModel(value="GroupRideInfo对象", description="团信息表")
public class GroupRideInfo implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "主键id")@TableId(value = "id", type = IdType.NONE)private Long id;@ApiModelProperty(value = "创建时间")private LocalDateTime createTime;@ApiModelProperty(value = "修改时间")private LocalDateTime updateTime;@ApiModelProperty(value = "创建人")private Integer createBy;@ApiModelProperty(value = "修改人")private Integer updateBy;@ApiModelProperty(value = "是否删除。默认0,1-是,0-否")private Integer isDelete;...@ApiModelProperty(value = "创建时坐标")private GeoPoint createPoint;}

定义坐标转换器 GeoPointConverter

public class GeoPointConverter {/*** Little endian or Big endian*/private int byteOrder = ByteOrderValues.LITTLE_ENDIAN;/*** Precision model*/private PrecisionModel precisionModel = new PrecisionModel();/*** Coordinate sequence factory*/private CoordinateSequenceFactory coordinateSequenceFactory = CoordinateArraySequenceFactory.instance();/*** Output dimension*/private int outputDimension = 2;/*** Convert byte array containing SRID + WKB Geometry into Geometry object*/public GeoPoint from(byte[] bytes) {if (bytes == null) {return null;}try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {// Read SRIDbyte[] sridBytes = new byte[4];inputStream.read(sridBytes);int srid = ByteOrderValues.getInt(sridBytes, byteOrder);// Prepare Geometry factoryGeometryFactory geometryFactory = new GeometryFactory(precisionModel, srid, coordinateSequenceFactory);// Read GeometryWKBReader wkbReader = new WKBReader(geometryFactory);Geometry geometry = wkbReader.read(new InputStreamInStream(inputStream));Point point = (Point) geometry;// convert to GeoPointGeoPoint geoPoint = new GeoPoint(point.getX(), point.getY());return geoPoint;} catch (IOException | ParseException e) {throw new IllegalArgumentException(e);}}/*** Convert Geometry object into byte array containing SRID + WKB Geometry*/public byte[] to(GeoPoint geoPoint) {if (geoPoint == null) {return null;}Coordinate coordinate = new Coordinate(geoPoint.getLongitude(), geoPoint.getLatitude());CoordinateArraySequence coordinateArraySequence = new CoordinateArraySequence(new Coordinate[]{coordinate}, 2);Point point = new Point(coordinateArraySequence, new GeometryFactory());try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {// Write SRIDbyte[] sridBytes = new byte[4];ByteOrderValues.putInt(point.getSRID(), sridBytes, byteOrder);outputStream.write(sridBytes);// Write GeometryWKBWriter wkbWriter = new WKBWriter(outputDimension, byteOrder);wkbWriter.write(point, new OutputStreamOutStream(outputStream));return outputStream.toByteArray();} catch (IOException ioe) {throw new IllegalArgumentException(ioe);}}
}

定义 GeoPointTypeHandler

@MappedTypes({GeoPoint.class})
public class GeoPointTypeHandler extends BaseTypeHandler<GeoPoint> {GeoPointConverter converter = new GeoPointConverter();@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, GeoPoint parameter, JdbcType jdbcType) throws SQLException {ps.setBytes(i, converter.to(parameter));}@Overridepublic GeoPoint getNullableResult(ResultSet rs, String columnName) throws SQLException {return converter.from(rs.getBytes(columnName));}@Overridepublic GeoPoint getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return converter.from(rs.getBytes(columnIndex));}@Overridepublic GeoPoint getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return converter.from(cs.getBytes(columnIndex));}
}

配置扫描 TypeHandler

@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = {"${spring.xxx.data.db.basepackage}"}, sqlSessionFactoryRef = "sqlSessionFactoryMasterDb")
@Slf4j
public class DbConfig implements TransactionManagementConfigurer {/*** 注释** @return SqlSessionFactory* @throws Exception 异常*/@Beanpublic SqlSessionFactory sqlSessionFactoryMasterDb() throws Exception {MybatisSqlSessionFactoryBean factoryBean =new MybatisSqlSessionFactoryBean();...// 此处为定义TypeHandler所在的包名factoryBean.setTypeHandlersPackage("com.xxx.module.typehandler");return factoryBean.getObject();}
}

注意,此处代码仅为示例代码,关键代码在factoryBean.setTypeHandlersPackage("com.xxx.module.typehandler");

SpringBoot 项目也可以在配置文件中配置,请自行百度,目的是让自定义 TypeHandler 生效。

MyBatis 使用 POINT

原生 getById()

自定义 SQL(指定范围查找)

  1. Mapper 接口中定义方法
List<GroupRideInfo> getListByPoint2(Integer distance, GeoPoint point, String ticket);
  1. Mapper.xml 中定义查询语句
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.xxx.groupride.domain.po.GroupRideInfo"><id column="id" property="id" /><result column="create_time" property="createTime" /><result column="update_time" property="updateTime" /><result column="create_by" property="createBy" /><result column="update_by" property="updateBy" /><result column="is_delete" property="isDelete" />...<result column="create_point" property="createPoint" />
</resultMap>
<select id="getListByPoint2" resultMap="BaseResultMap">SELECT *,ST_Distance_Sphere(create_point, #{point}) AS distance_metersFROM group_ride_infoHAVING distance_meters &lt; #{distance} and status=1 and ticket=#{ticket}ORDER BY distance_meters asc
</select>
  1. 调用方法

可以看到,可以在 MyBatis 中像普通类型参数一样使用 POINT 了。上面示例仅列举了查询操作,新增/修改也是可以的。

相关文章:

SpringBoot+MyBatis+MySQL的Point实现范围查找

前言 最近做了一个功能&#xff0c;需要通过用户当前位置点获取指定范围内的数据。由于后端存储用的是 MySQL&#xff0c;故选择使用 MySQL 中的 Point 实现范围查找功能。ORM 框架用的是 MyBatis&#xff0c;MyBatis 原生并不支持 Point 字段与 POJO 的映射&#xff0c;需要自…...

【Apache Paimon】-- 1 -- Apache Paimon 是什么?

目录 1、简介 2、概览 3、哪些场景可以使用 Paimon 4、周边生态 5、小结 6、参考 1、简介 我们听说过数据仓库、数据湖、数据湖仓,那你听说过流式数据仓库(Stream warehouse,简称:Streamhouse)吗?那我们今天就来解锁看看他们之中的新秀: Apache paimon 到底是什么…...

解决VsCode无法跳转问题

在settings.json中加入以下代码 { "files.associations": { "*.c":"c", "*.h":"c", "*.s":"masm" }, "includePath":[ "${workspaceFold…...

优化C++设计模式:用模板代替虚函数与多态机制

文章目录 0. 引言1. 模板编程替换虚函数和多态的必要性1.1. MISRA C对类型转换和虚函数的规定1.2. 虚函数与多态问题的影响及如何适应MISRA C要求1.3. 模板编程的优势&#xff1a;替代虚函数和多态机制 2. 设计模式改进2.1. 单例模式的改进与静态局部变量的对比(第二种实现) 2.…...

浪浪云轻量服务器搭建vulfocus网络安全靶场

什么是网络安全靶场 网络安全靶场是一个模拟真实网络环境的训练平台&#xff0c;旨在为网络安全专业人员提供一个安全的环境来测试和提高他们的技能。靶场通常包括各种网络设备、操作系统、应用程序和安全工具&#xff0c;允许用户在其中进行攻击和防御练习。以下是网络安全靶…...

C++builder中的人工智能(23):在现代C++ Windows上轻松录制声音

在这篇文章中&#xff0c;我们将探讨如何在现代C Windows上轻松录制声音。声音以波形和数字形式存在&#xff0c;其音量随时间变化。在C Builder中&#xff0c;使用Windows设备进行录音非常简单。要录制声音&#xff0c;在多设备应用程序中&#xff0c;必须使用FMX.Media.hpp头…...

避免误差!Android 中正确计算时间差的方式

在 Android 开发中&#xff0c;计时和计算时间差异是非常常见的需求&#xff0c;比如记录事件发生的间隔、统计应用启动时间、测量网络请求的响应时间等。在实现这些功能时&#xff0c;我们通常需要一个可靠的时间源来确保计时的准确性。那么为什么 Android 推荐使用 SystemClo…...

unity3d————Resources异步加载

知识点一&#xff1a;Resources异步加载是什么&#xff1f; 在Unity中&#xff0c;资源加载可以分为同步加载和异步加载两种方式。同步加载会在主线程中直接进行&#xff0c;如果加载的资源过大&#xff0c;可能会导致程序卡顿&#xff0c;因为从硬盘读取数据到内存并进行处理…...

YOLOv11改进,YOLOv11添加GnConv递归门控卷积,二次创新C3k2结构

摘要 视觉 Transformer 在多种任务中取得了显著的成功,这得益于基于点积自注意力的新空间建模机制。视觉 Transformer 中的关键因素——即输入自适应、长距离和高阶空间交互——也可以通过卷积框架高效实现。作者提出了递归门控卷积(Recursive Gated Convolution,简称 gnCo…...

如何选择国产化CMS来建设政务网站?

在介绍CMS之前&#xff0c;我们先了解国家为什么要网站为什么要完成国产化改造&#xff1f; 1、信创国产化网站建站响应了国家的信息安全战略&#xff0c;支持自主可控的信息技术产业的发展&#xff0c;减少对进口软硬件的依赖&#xff0c;保障国家信息安全。 2、国产替代&…...

C/C++语言基础--initializer_list表达式、tuple元组、pair对组简介

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 initializer_list表达式、tuple元组、pair对组再C日常还是比较常用的&#xff0c;尤其是对组在刷算法还是挺好用的&#xff0c;这里做一个简介&#xff1b;这三个语法结合C17的结构化绑定会更好用&#xff…...

paddle表格识别数据制作

数据格式 其中主要数据有两个一个表格结构的检测框&#xff0c;一个是tokens&#xff0c;注意的地方是 1、只能使用双引号&#xff0c;单引号不行 2、使用带引号的地方是tokens里面 "<tr>", "<td", " colspan2", ">",&quo…...

python selenium库的使用:通过兴趣点获取坐标

通过兴趣点获取坐标 from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.common.exceptions import TimeoutException# 保存Cookies到文件&#xff08;可选&#xff09; import pi…...

如何优化Kafka消费者的性能

要优化 Kafka 消费者性能&#xff0c;你可以考虑以下策略&#xff1a; 并行消费&#xff1a;通过增加消费者组中的消费者数量来并行处理更多的消息&#xff0c;从而提升消费速度。 批量消费&#xff1a;配置 fetch.min.bytes 和 fetch.max.wait.ms 参数来控制批量消费的大小和…...

机器学习 决策树

决策树-分类 1 概念 1、决策节点通过条件判断而进行分支选择的节点。如&#xff1a;将某个样本中的属性值(特征值)与决策节点上的值进行比较&#xff0c;从而判断它的流向。 2、叶子节点没有子节点的节点&#xff0c;表示最终的决策结果。 3、决策树的深度所有节点的最大层…...

效益登记册效益管理计划

效益登记册 benefit Register效益管理计划效益登记册汇集并列出项目集计划的效益&#xff0c;用于在项目集的整个持续时间内测量和沟通效益的交付。在效益识别阶段&#xff0c;效益登记册根据项目集商业论证、组织战略计划和其他相关项目集自标而编制。随后&#xff0c;登记册由…...

Go语言的零值可用性:优势与限制

Go语言以其简洁和高效的设计理念而著称&#xff0c;其中之一便是“零值可用”的特性。这一特性使得许多类型在未显式初始化时即可直接安全地使用&#xff0c;大大简化了代码的初始化过程。然而&#xff0c;并非所有类型都支持零值可用&#xff0c;且在使用时也存在一定的限制。…...

【自用】0-1背包问题与完全背包问题的Java实现

引言 背包问题是计算机科学领域的一个经典优化问题&#xff0c;分为多种类型&#xff0c;其中最常见的是0-1背包问题和完全背包问题。这两种问题的核心在于如何在有限的空间内最大化收益&#xff0c;但它们之间存在一些关键的区别&#xff1a;0-1背包问题允许每个物品只能选择…...

HTML5实现俄罗斯方块小游戏

文章目录 1.设计来源1.1 主界面1.2 皮肤风格1.2 游戏中界面1.3 游戏结束界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/143788449 HTML5实现俄罗斯方块小游戏&#x…...

Mybatis官方生成器使用示例

在这篇文章中&#xff0c;我们将通过实际代码示例来说明如何使用 MyBatis Generator (MBG) 来自动化生成 MyBatis 项目所需的实体类、Mapper 接口和 Mapper XML 文件。我们将使用一个 Maven 插件来执行代码生成&#xff0c;并提供详细的配置和解释。 1. MyBatis Generator 简介…...

用C++和Eigen库手把手实现UR3机械臂逆解(附完整代码与避坑指南)

从理论到实践&#xff1a;基于Eigen库的UR3机械臂逆运动学完整实现指南 在工业自动化和机器人研究领域&#xff0c;六轴协作机械臂因其灵活性和广泛的应用场景而备受关注。UR3作为Universal Robots旗下的紧凑型协作机械臂&#xff0c;凭借其轻量化设计和用户友好特性&#xff0…...

终极指南:如何使用ViGEmBus虚拟游戏控制器驱动程序提升Windows游戏体验

终极指南&#xff1a;如何使用ViGEmBus虚拟游戏控制器驱动程序提升Windows游戏体验 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 你是否曾经遇到过想在Win…...

知识竞赛选手排位抽签系统使用全解析

&#x1f3b2; 知识竞赛选手排位抽签系统使用全解析公平 透明 高效 让每一场竞赛从起点就值得信赖&#x1f3af; 引言&#xff1a;为何需要专业的抽签系统在知识竞赛活动中&#xff0c;选手的排位与分组抽签是确保竞赛公平、公正的起点。传统的人工抽签方式不仅效率低下&…...

强化学习算法:深度确定性策略梯度(DDPG)

强化学习算法&#xff1a;深度确定性策略梯度(DDPG) 1. 技术分析 1.1 DDPG概述 DDPG是针对连续动作的深度强化学习算法&#xff1a; DDPG特点确定性策略: 输出确定动作而非概率Actor-Critic架构: 结合策略和价值离线策略: 使用经验回放核心创新:确定性策略梯度目标网络探索噪声…...

Cursor Free VIP:三步破解AI编程助手试用限制的专业解决方案

Cursor Free VIP&#xff1a;三步破解AI编程助手试用限制的专业解决方案 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve reached yo…...

命令行视频生成工具tubecli:配置即代码的自动化视频制作实践

1. 项目概述与核心价值如果你经常需要处理视频内容&#xff0c;无论是做自媒体、产品演示还是内部培训&#xff0c;大概率都遇到过这样的场景&#xff1a;手头有一堆素材、脚本或者PPT&#xff0c;但把它们变成一段流畅的视频&#xff0c;总得在剪辑软件里折腾半天。更别提批量…...

智慧巡检-基于Yolo26的目标检测系统 带登录界面的基于Yolo26的目标检测系统完整源码+原始ui文件+环境配置教程 相关技术文档包含:2万字算法文档+详细操作指南+技术设计文档+流程图+yolo

智慧巡检-基于Yolo26的目标检测系统带登录界面的基于Yolo26的目标检测系统完整源码原始ui文件环境配置教程 相关技术文档包含&#xff1a;2万字算法文档详细操作指南技术设计文档流程图yolo26网络结构图各文件作用说明 可视化界面基于pyside6&#xff0c;数据库为sqlite3&#…...

杰理之升压档位选择,需要同步修改过压档位【篇】

#define TCFG_BOOST_VOUT_S BOOST_VOUT_S_4700_MV //VOUT OV UV #define VOUT_OV_VOLT VOUT_OV_VOL_S_5P53V_TO_5P34V...

企业内如何构建基于Taotoken的标准化AI能力中台

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 企业内如何构建基于Taotoken的标准化AI能力中台 随着大模型技术在企业内部的应用日益广泛&#xff0c;如何高效、安全、可控地管理…...

ffmpeg-static 6.1.1版本:跨平台音视频处理的终极解决方案

ffmpeg-static 6.1.1版本&#xff1a;跨平台音视频处理的终极解决方案 【免费下载链接】ffmpeg-static ffmpeg static binaries for Mac OSX and Linux and Windows 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpeg-static 在当今多媒体处理需求日益增长的开发环境…...