1 Star 0 Fork 0

周茂和/mapEsDemo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

功能-地理位置搜索(ES实现)

  • 在SpringBoot环境中使用ES实现地理位置查询。
  • 高德地图功能接口

**目标:**将商户信息(包含地理坐标)存入ES中,然后获取当前用户的地理位置,计算出当前用户距离商户的远近,以及用户可根据距离的远近来筛选出符合距离的商户。

测试-技术栈

**前端:**Vue3.x ,Pinia,ElementPlus

**后端:**Spring Boot3.x , ElasticSearch7.x

**地图相关服务提供:**高德地图JS API 2.0

功能实现

  • 商户入驻选址:商户根据地图组件选择地址,获取商户选择的地址信息和地理位置传入后端,后端将信息存储到ES中。
  • 获取用户当前坐标:浏览器地理定位API:navigator.geolocation,前提是用户需要赋予位置权限。
  • 显示商户距离:使用ES中的地理查询(圆形过滤)geo_distance类型进行查询附近商户,并且在sort中配置商户远近排序。
  • 距离筛选:在ES原形过滤时修改distance参数值重新查询商户。

具体实现

Vue整合高德地图JS API-2.0

  1. 安装依赖包:npm i @amap/amap-jsapi-loader ,用于创建地图相关对象。
  2. 配置key和密钥 (安全问题:将key和密钥放到环境变量中)。
  3. 初始化地图对象,显示地图。

**遇到bug:**v-show 控制组件的隐藏显示,导致组件中的地图组件不能正常显示,报错:Invalid Object: LngLat(NaN, NaN)改用v-if即可。

加入商户

用户点击右上角“加入商户”,显示表单填写商户信息,以及显示高德地图组件,根据用户填写的省市区位置设置地图组件中心点,当用户点击地图中指定位置时,获取点击位置的坐标,然后调用【逆地理编码】接口将地理坐标转换为详细地址显示。用户可适当修改详细地址后,提交-新增完毕。

1.创建ES的索引结构,编写后端新增接口。


PUT /hotels
{
  "mappings": {
    "properties": {
      "picture": { "type": "keyword" },
      "name": { "type": "text","analyzer": "ik_smart"},
      "score": { "type": "float"},
      "distance": { "type": "float"},
      "desc": { "type": "text" },
      "newPrice": { "type": "float" },
      "oldPrice": { "type": "float" },
      "sale_month": { "type": "integer" },
      "location": { 
        "type": "geo_point" 
      }
    }
  }
}

引入ES依赖:注意引入8以下的,8以上版本Java客户端变化太大,API中文文档不全面。

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.1</version>
</dependency>

- 创建客户端Bean并加入Ioc容器,编写实体类。

- 编写新增接口

2.前端信息收集,地址信息获取。

- 用户输入省市地址,将地图中心点转至对应省市,供用户标记选择详细地址。

- 当用户点击标记地图上地址后,获取标记处的详细地址映射到详细地址输入框中展示。

- 将数据打包发给后端添加到ES中。

查询用户当前地理坐标

使用浏览器内置函数:navigator.geolocation,实现当前用户地理坐标的查询。

用户需要在弹出的授权框授权地理位置允许。

// 当前用户的地理坐标
const position = ref(null);

function getUserLocation(){
    if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        position.value = {
          lat: pos.coords.latitude,
          lng: pos.coords.longitude,
        };
        // 根据用户地理坐标获取周围指定距离的酒店
        getNearHotel(position.value);
        // console.log("当前用户地理位置:",position.value);
      },
      (err) => {
        error.value = err.message;
      }
    );
  } else {
    error.value = 'Geolocation is not supported by this browser.';
  }
}

获取附近(指定距离)的酒店

1.编写后端接口,根据用户当前位置和想要查询的半径获取包含在圆形区域的内酒店信息。

@PostMapping("/searchByLocation")
public List<Map<String, Object>> searchHotelsByLocation(
        @RequestBody SearchVo searchVo
        ) throws IOException {

    // 构建查询请求
    SearchRequest searchRequest = new SearchRequest("hotels");

    // 构建查询DSL
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    boolQuery.filter(QueryBuilders.geoDistanceQuery("location")
            .point(searchVo.getLat(), searchVo.getLon())
            .distance(searchVo.getRadiusKm(), DistanceUnit.KILOMETERS));

    sourceBuilder.query(boolQuery);
    sourceBuilder.sort(SortBuilders.geoDistanceSort("location", searchVo.getLat(), searchVo.getLon())
            .order(SortOrder.ASC) // 实现升序排序,距离越近越靠前
            .unit(DistanceUnit.KILOMETERS));

    searchRequest.source(sourceBuilder);

    // 执行查询
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits hits = searchResponse.getHits();
    List<Map<String, Object>> hotels = new ArrayList<>();

    for (SearchHit hit : hits) {
        Map<String, Object> hotel = hit.getSourceAsMap();
        // 可以获取距离信息(如果需要显示距离)
        double distance = (double) hit.getSortValues()[0];
        hotel.put("distance_km", distance);
        hotels.add(hotel);
    }

    return hotels;
}
  1. 前端传参,获取商家数据展示。
// 使用圆形过滤,过滤出当前用户指定距离的附近酒店
async function getNearHotel(userLocation){
    // 定义搜索半径
    let radiusKm = 3.0;
    
    // 构造查询参数
    let searchArgs = {
        lat:userLocation.lat,
        lon:userLocation.lng,
        radiusKm:radiusKm
    }

    const res = await axios.post("http://localhost:9009/es/searchByLocation",searchArgs);
    console.log("查询到"+ radiusKm + "公里内,存在"+res.data.length+"家酒店/旅社");
    // 处理距离小数点,保留逗号后两位
    for(let item of res.data){
        item.distance_km = item.distance_km.toFixed(2);
    }
    cardsD.value = res.data
}

至此,使用高德地图API配合ES完成地理位置查询功能点,测试完毕。

空文件

简介

ES配合高德地图JS-API实现地理位置查询Demo 展开 收起
Vue 等 5 种语言
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/maohe101/map-es-demo.git
git@gitee.com:maohe101/map-es-demo.git
maohe101
map-es-demo
mapEsDemo
master

搜索帮助