①开发背景
在当今的数字化时代,人们对于便捷的生活体验有着越来越高的期望,无论实在旅行中还是在日常生活中,用户经常需要才查找附近商户,比如餐厅,咖啡馆,酒店等;然而,传统的方式往往需要依赖搜索引擎或者地图应用,需要用户手动输入关键词或者地址来获取结果。
为了提供更加便捷的个性化服务,业务中开发了基于地理位置的附近商户查找功能。这个将利用用户设置的定位信息吗,结合商户数据库和地图数据,为用户提供准确、实时的附近商户信息。用户只应用需要打开应用就可以获取周边的商户信息列表,并可以根据自己的需求仅供筛选。
应用场景:地理位置的定位和周围的信息
数据库设计
区域表:用户存储商圈地址信息:(t_area)
字段名 | 字段描述 |
id | 主键 |
name | 商圈名称 |
分类表:用户储存不同的商户分类(t_shop_type)
字段名 | 字段名 |
id | 主键 |
name | 商户分类名称 |
商户信息表:存储商户的基本信息(t_shop)
字段名 | 字段描述 |
id | 主键 |
name | 商户名称 |
pic | 商户图片 |
address | 商户地址 |
phone | 练习方式 |
area_id | 商户所在商圈ID |
type_id | 商户分类id |
x | 经度坐标 |
y | 纬度坐标 |
status | 是否上线状态 |
技术选型:
使用Redis的GEO类型
主要效果:可以将地理位置坐标与其他数据关联,并提供了一些强大的地理位置搜索和计算功能。GEO功能用于地理位置相关的应用场景,如附近的人、附近的商铺、地理围栏等
Redis中GEO的数据结构和命令:
Redis的GEO数据机构为有序集合,每一个元素都是一个地理位置
地理位置由经度和纬度进行表示
相关命令:
将一个或者多个地理位置及其关联数据添加到指定的key 中
GEOADD key longitude latitude member [longitude latitude member]
根据给定的经纬度和半径,在指定的key中搜索地理位置,并按照一定的条件返回结果
GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
计算两个地理位置之间的距离
GEODIST key member1 member2 [unit]
获取一个或者多个地理位置的经纬度坐标
GEOPOS key member [member ...]
项目实战
注册高德地图账号
高德开放平台:高德开放平台 | 高德地图API
高德地图api:地图JS API接口免费配额调整 | 高德地图API
经纬度获取系统:经纬度查询 - 坐标拾取系统
数据初始化功能:
定义一个容器启动完毕的事件监听器
/** 开启事件监听注解 */
@EventListener
public void initShop(ContextRefreshedEvent event){
/**
* 在程序启动开始前 将Mysql中的数据进行预热到Redis中
*
*/
geoService.initDate();
System.out.println("redis数据预热成功");
}
查询已经上线的商户集合,通过Redis的GEO功能,将商户信息的经纬度进行储存
支持的搜索模式:
①按照附近距离查询
②按照商圈查询
③按照商户分类查询
Redis的key设计模式
存储广州市美食的商户集合: SHOP_GEO_CITY_TYPE:1
存储广州市酒店的商户集合: SHOP_GEO_CITY_TYPE:2
存储天河区美食的商户集合: SHOP_GEO_AREA:1_TYPE:1
存储天河区酒店的商户集合: SHOP_GEO_AREA:1_TYPE:2
存储番禺区美食的商户集合: SHOP_GEO_AREA:2_TYPE:1
存储番禺区酒店的商户集合: SHOP_GEO_AREA:2_TYPE:2
业务逻辑:
1.查询上线的商户集合
2.将List<Shop> list转成Map<String, String>结构,然后通过multiSet批量缓存
3.处理城市商户数据,将List<Shop> list转成Map<Long, List<Shop>>,遍历cityMap.entrySet()集合,将数据封装成List<RedisGeoCommands.GeoLocation<String>>
4.使用redisTemplate.opsForGeo().add(key,locations)将商户数据存储到Redis中
5.将List<Shop> list转成Map<Long, Map<Long, List<Shop>>>,经过两层遍历将数据封装成List<RedisGeoCommands.GeoLocation<String>>
6.使用redisTemplate.opsForGeo().add(key,locations)将商户数据存储到Redis中