Java地图专题课 基本API BMapGLLib 地图找房案例 MongoDB

本课程基于百度地图技术,由基础入门开始到应用实战,适合零基础入门学习。将企业项目中地图相关常见应用场景的落地实战,包括有地图找房、轻骑小程序、金运物流等。同时讲了基于Netty实现高性能的web服务,来处理高并发的问题。还讲解了海量坐标数据处理解决方案。

学完本课程能够收获:百度地图技术的应用、轨迹类场景、路线规划场景,电子围栏场景的开发,增长开发经验。

导学

地图场景与基础API

案例1:地图找房

案例2:轻骑项目

案例3:金运物流

高并发解决方案

海量数据存储解决方案

地图基础API与搜索

地图技术概述

地图应用场景

常用地图服务的比较

百度地图基本API应用

百度地图提供了各种平台的SDK,地址:百度地图开放平台 | 百度地图API SDK | 地图开发 如下:

账号与API准备

设置应用名称与类型

JavaScript百度地图API项目

案例1:创建地图

创建地图的基本步骤如下:

编写HTML页面的基础代码

引入百度地图API文件

初始化地图逻辑以及设置各种参数

参考官方文档:

jspopularGL | 百度地图API SDK

页面效果:

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map </title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=1GH6ZiAb79MTpfRzmYDpTUPpB7SVImfN"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放
    map.setHeading(64.5);   //设置地图旋转角度
    map.setTilt(73);       //设置地图的倾斜角度

    var scaleCtrl = new BMapGL.ScaleControl();  // 添加比例尺控件
    map.addControl(scaleCtrl);
    var zoomCtrl = new BMapGL.ZoomControl();  // 添加缩放控件
    map.addControl(zoomCtrl);
    var cityCtrl = new BMapGL.CityListControl();  // 添加城市列表控件
    map.addControl(cityCtrl);
</script>
</body>
</html>

添加覆盖物

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map - 覆盖物</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放


    // var  point2 = new BMapGL.Point(116.380194,39.922018);
    // var marker = new BMapGL.Marker(point2);        // 创建标注
    // map.addOverlay(marker);                     // 将标注添加到地图中

    // var myIcon = new BMapGL.Icon("logo.png", new BMapGL.Size(180, 53), {
    //     // 指定定位位置。
    //     // 当标注显示在地图上时,其所指向的地理位置距离图标左上
    //     // 角各偏移10像素和25像素。您可以看到在本例中该位置即是
    //     // 图标中央下端的尖角位置。
    //     anchor: new BMapGL.Size(-10, 12),
    //     // 设置图片偏移。
    //     // 当您需要从一幅较大的图片中截取某部分作为标注图标时,您
    //     // 需要指定大图的偏移位置,此做法与css sprites技术类似。
    //     imageOffset: new BMapGL.Size(0, 0)   // 设置图片偏移
    // });
    // // 创建标注对象并添加到地图
    // var marker = new BMapGL.Marker(point, {icon: myIcon});
    // map.addOverlay(marker);
    //
    // marker.addEventListener("click", function(){
    //     alert("您点击了标注");
    // });

    // 折线
    var polyline = new BMapGL.Polyline([
        new BMapGL.Point(116.399, 39.910),
        new BMapGL.Point(116.405, 39.920),
        new BMapGL.Point(116.425, 39.900)
    ], {strokeColor:"blue", strokeWeight:2, strokeOpacity:0.8});
    map.addOverlay(polyline);

    //多边形
    var polygon = new BMapGL.Polygon([
        new BMapGL.Point(116.387112,39.920977),
        new BMapGL.Point(116.385243,39.913063),
        new BMapGL.Point(116.394226,39.917988),
        new BMapGL.Point(116.401772,39.921364),
        new BMapGL.Point(116.41248,39.927893)
    ], {strokeColor:"blue", strokeWeight:2, strokeOpacity:0.5});
    map.addOverlay(polygon);

    //圆形
    var circle = new BMapGL.Circle(point , 1000, {
        strokeColor:"red",
        strokeOpacity:0.8,
        strokeWeight:3
    });
    map.addOverlay(circle);

</script>
</body>
</html>

地图事件

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map - 事件</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放

    // map.addEventListener('click', function(e) {
    //     alert('click!')
    // });

    map.addEventListener('click', function(e) {
        alert('点击的经纬度:' + e.latlng.lng + ', ' + e.latlng.lat);
        var mercator = map.lnglatToMercator(e.latlng.lng, e.latlng.lat);
        alert('点的墨卡托坐标:' + mercator[0] + ', ' + mercator[1]);
    });

</script>
</body>
</html>

地图样式

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map - 变更地图样式</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放

    map.setMapType(BMAP_EARTH_MAP);      // 设置地图类型为地球模式

</script>
</body>
</html>

地图检索

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map - 搜索兴趣点</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放

    var local = new BMapGL.LocalSearch(map, {
        renderOptions:{map: map},
        pageCapacity:100
    });
    local.search("银行");
</script>
</body>
</html>
复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Baidu Map - 圆形范围搜索兴趣点</title>
    <style type="text/css">
        html{height:100%}
        body{height:100%;margin:0px;padding:0px}
        #container{height:100%}
    </style>
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
    var map = new BMapGL.Map("container");          // 创建地图实例
    var point = new BMapGL.Point(116.404, 39.915);  // 创建点坐标
    map.centerAndZoom(point, 15);                 // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放

    var circle = new BMapGL.Circle(point,2000,{fillColor:"blue", strokeWeight: 1 ,fillOpacity: 0.3, strokeOpacity: 0.3});
    map.addOverlay(circle);
    var local =  new BMapGL.LocalSearch(map, {renderOptions: {map: map, autoViewport: false}});
    local.searchNearby('景点',point,2000);

</script>
</body>
</html>

数据可视化

MapV开发文档

百度地图web API应用

地址: web服务API | 百度地图API SDK

案例一:坐标转换

复制代码
package cn.itcast.baidumap;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import org.junit.Test;

public class TestBaiduWebApi {

    private String ak = "64Ut0Peo2Dsb1l43FRl1nReM0tBdpE3L";

    /**
     * 测试坐标转换服务
     */
    @Test
    public void testGeoconv() {
        String url = "https://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak={}";
        url = StrUtil.format(url, ak);

        //发起get请求
        String body = HttpRequest.get(url).execute().body();
        System.out.println(body);
    }

    /**
     * 测试IP定位服务
     */
    @Test
    public void testLocation(){
        String url = "https://api.map.baidu.com/location/ip?ak={}&ip=140.206.149.83&coor=bd09ll";
        url = StrUtil.format(url, ak);

        //发起get请求
        String body = HttpRequest.get(url).execute().body();
        System.out.println(body);
    }

    /**
     * 测试地点输入提示服务
     */
    @Test
    public void testSuggestion(){
        String url = "https://api.map.baidu.com/place/v2/suggestion?query=清华大&region=北京&city_limit=true&output=json&ak={}";
        url = StrUtil.format(url, ak);

        //发起get请求
        String body = HttpRequest.get(url).execute().body();
        System.out.println(body);
    }

    /**
     * 测试路线规划
     */
    @Test
    public void testDriving(){
        String url = "https://api.map.baidu.com/direction/v2/driving?alternatives=1&origin=40.009645,116.333374&destination=39.937016,116.453576&ak={}";
        url = StrUtil.format(url, ak);

        //发起get请求
        String body = HttpRequest.get(url).execute().body();
        System.out.println(body);
    }
}

案例二:IP定位服务

案例三:地点输入提示服务

案例四:路线规划

综合案例:地图找房

BMapGLLib

GitHub - huiyan-fe/BMapGLLib: 百度地图JSAPI GL版JavaScript开源工具库

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>地图找房 - 地图搜索 </title>
    <style type="text/css">
        html {
            height: 100%
        }

        body {
            height: 100%;
            margin: 0px;
            padding: 0px
        }

        #container {
            height: 100%
        }

        .district {
            width: 84px;
            height: 84px;
            line-height: 16px;
            font-size: 12px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            border: 1px solid transparent;
            border-radius: 50%;
            overflow: hidden;
            text-align: center;
            font-family: PingFangSC-Semibold;
            color: #fff;
            background: #00ae66 !important;
            box-sizing: border-box;
        }

        .district i {
            font-size: 12px;
            color: hsla(0, 0%, 100%, .7);
            line-height: 12px;
            margin-top: 4px;
            font-style: normal;
        }

        #platform > div > div > div {
            background: none !important;
        }
    </style>
    <script type="text/javascript" src="jquery-3.6.0.min.js"></script>
    <script type="text/javascript"
            src="http://api.map.baidu.com/api?v=1.0&type=webgl&ak=LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX"></script>
    <script src="http://mapopen.bj.bcebos.com/github/BMapGLLib/RichMarker/src/RichMarker.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="application/javascript">
    function showInfo(map) {
        let bound = map.getBounds(); //可视范围矩形坐标,其中sw表示矩形区域的西南角,参数ne表示矩形区域的东北角
        let zoom = map.getZoom(); //缩放级别
        console.log(bound);
        console.log(zoom);
        $.ajax({
            url: "/house/search",
            data: {
                maxLongitude: bound.ne.lng,
                minLongitude: bound.sw.lng,
                maxLatitude: bound.ne.lat,
                minLatitude: bound.sw.lat,
                zoom: zoom
            },
            success: function (data) {
                showMapMarker(data, map);
            }
        });

        //测试效果:
        // let data = [{"name":"徐汇","price":"1028.43","total":"6584","longitude":121.43676,"latitude":31.18831},{"name":"黄浦","price":"1016.19","total":"7374","longitude":121.49295,"latitude":31.22337},{"name":"长宁","price":"1008.34","total":"4380","longitude":121.42462,"latitude":31.22036},{"name":"静安","price":"1005.34","total":"8077","longitude":121.4444,"latitude":31.22884},{"name":"普陀","price":"1026.14","total":"5176","longitude":121.39703,"latitude":31.24951},{"name":"金山","price":"1099.67","total":"6","longitude":121.34164,"latitude":30.74163},{"name":"松江","price":"1017.71","total":"14","longitude":121.22879,"latitude":31.03222},{"name":"青浦","price":"1038.11","total":"751","longitude":121.12417,"latitude":31.14974},{"name":"奉贤","price":"1108.63","total":"35","longitude":121.47412,"latitude":30.9179},{"name":"浦东","price":"1030.22","total":"8294","longitude":121.5447,"latitude":31.22249},{"name":"嘉定","price":"1041.45","total":"1620","longitude":121.2655,"latitude":31.37473},{"name":"宝山","price":"1050.65","total":"102","longitude":121.4891,"latitude":31.4045},{"name":"闵行","price":"1027.15","total":"941","longitude":121.38162,"latitude":31.11246},{"name":"杨浦","price":"1007.78","total":"2747","longitude":121.526,"latitude":31.2595},{"name":"虹口","price":"1025.81","total":"4187","longitude":121.48162,"latitude":31.27788}];
        // showMapMarker(data, map);
    }

    //显示覆盖物
    function showMapMarker(data, map) {
        for (let vo of data) {
            let html = "<div class=\"district\">" + vo.name + "<span>" + vo.price + "万</span><i>" + vo.total + "套</i></div>";
            let marker = new BMapGLLib.RichMarker(html, new BMapGL.Point(vo.longitude, vo.latitude));
            map.addOverlay(marker);
        }
    }

    //清除覆盖物
    function clearMapMarker(map) {
        let markers = map.getOverlays(); //获取到地图上所有的覆盖物
        for (let marker of markers) { //循环将其删除
            map.removeOverlay(marker);
        }
    }

    $(function () {
        //地图默认位置,上海市
        let defaultX = 121.48130241985999;
        let defaultY = 31.235156971414239;
        let defaultZoom = 12; //默认缩放比例

        let map = new BMapGL.Map("container");          // 创建地图实例
        let point = new BMapGL.Point(defaultX, defaultY);  // 创建点坐标
        map.centerAndZoom(point, defaultZoom);                 // 初始化地图,设置中心点坐标和地图级别
        map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放
        //显示比例尺
        map.addControl(new BMapGL.ScaleControl({anchor: BMAP_ANCHOR_BOTTOM_RIGHT}));

        map.addEventListener("dragstart", () => {  //拖动开始事件
            clearMapMarker(map)
        });
        map.addEventListener("dragend", () => { //拖动结束事件
            showInfo(map)
        });
        map.addEventListener("zoomstart", () => { //缩放开始事件
            clearMapMarker(map)
        });
        map.addEventListener("zoomend", () => { //缩放结束事件
            showInfo(map)
        });
        //初始显示数据
        showInfo(map);
    });
</script>
</body>
</html>

通过docker安装MongoDB

复制代码
#拉取镜像
docker pull mongo:4.0.3

#创建容器
docker create --name mongodb-server -p 27017:27017 -v mongodb-data:/data/db mongo:4.0.3 --auth

#启动容器
docker start mongodb-server

#进入容器
docker exec -it mongodb-server /bin/bash

#进入admin数据库
mongo
use admin

#添加管理员,其拥有管理用户和角色的权限
db.createUser({ user: 'root', pwd: 'root', roles: [ { role: "root", db: "admin" } ] })
#退出后进行认证

#进行认证
mongo -u "root" -p "root" --authenticationDatabase "admin"

#通过admin添加普通用户
use admin
db.createUser({ user: 'house', pwd: 'oudqBFGmGY8pU6WS', roles: [ { role: "readWrite", db: "house" } ] });

#通过tanhua用户登录进行测试
mongo -u "house" -p "oudqBFGmGY8pU6WS" --authenticationDatabase "admin"

#发现可以正常进入控制台进行操作

构造数据

爬虫代码
复制代码
package cn.itcast.baidumap.wm;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.itcast.baidumap.pojo.BusinessCircle;
import cn.itcast.baidumap.pojo.Community;
import cn.itcast.baidumap.pojo.District;
import cn.itcast.baidumap.util.BaiduApiUtil;
import org.bson.types.ObjectId;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;

public class CommunityPageProcessor implements PageProcessor {

    private District district;

    private BusinessCircle businessCircle;

    private MongoTemplate mongoTemplate;

    public CommunityPageProcessor(District district, BusinessCircle businessCircle, MongoTemplate mongoTemplate) {
        this.district = district;
        this.businessCircle = businessCircle;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public void process(Page page) {
        Document html = Jsoup.parse(page.getRawText()); //解析html
        Elements elements = html.select("div.info div.title a"); //获取数据链接对象
        for (Element element : elements) {
            Community community = new Community();
            community.setId(ObjectId.get());
            community.setName(element.text()); //获取小区名称
            community.setLianJiaUrl(element.attr("href")); //获取链接

            community.setBusinessCircleCode(this.businessCircle.getCode());
            community.setDistrictCode(this.district.getCode());
            String address = StrUtil.format("上海市{}{}{}",
                    this.district.getName(),
                    this.businessCircle.getName(),
                    community.getName());
            //通过百度地图api查询地址对应的经纬度
            double[] coordinate = BaiduApiUtil.queryCoordinateByAddress(address);
            community.setLocation(new GeoJsonPoint(coordinate[0], coordinate[1]));

            this.mongoTemplate.save(community);
        }

        //设置分页
        String pageData = html.select("div[page-data]").attr("page-data");
        JSONObject pageJson = JSONUtil.parseObj(pageData);
        Integer totalPage = pageJson.getInt("totalPage", 1);
        Integer curPage = pageJson.getInt("curPage", 1);
        if (curPage < totalPage) {
            String url = businessCircle.getLianJiaUrl() + "pg" + (curPage + 1);
            page.addTargetRequest(url);
        }
    }

    @Override
    public Site getSite() {
        //失败重试3次,每次抓取休息200毫秒
        return Site.me().setRetryTimes(3).setSleepTime(200);
    }
}

MongoDB的聚合操作

实现搜索---分析

POJO类、Vo类

Controller

复制代码
package cn.itcast.baidumap.controller;

import cn.itcast.baidumap.service.HouseSearchService;
import cn.itcast.baidumap.vo.HouseResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequestMapping("house/search")
@RestController
public class HouseSearchController {

    @Autowired
    private HouseSearchService houseSearchService;

    /**
     * 地图找房搜索服务
     *
     * @param maxLongitude 最大经度
     * @param minLongitude 最小经度
     * @param maxLatitude  最大纬度
     * @param minLatitude  最小纬度
     * @param zoom         地图缩放比例值
     * @return
     */
    @GetMapping
    public List<HouseResultVo> search(@RequestParam("maxLongitude") Double maxLongitude,
                                      @RequestParam("minLongitude") Double minLongitude,
                                      @RequestParam("maxLatitude") Double maxLatitude,
                                      @RequestParam("minLatitude") Double minLatitude,
                                      @RequestParam("zoom") Double zoom) {
        return this.houseSearchService.search(maxLongitude, minLongitude, maxLatitude, minLatitude, zoom);
    }
}

Service

复制代码
package cn.itcast.baidumap.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.itcast.baidumap.pojo.BusinessCircle;
import cn.itcast.baidumap.pojo.Community;
import cn.itcast.baidumap.pojo.District;
import cn.itcast.baidumap.pojo.House;
import cn.itcast.baidumap.vo.HouseResultVo;
import com.mongodb.internal.operation.AggregateOperation;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Box;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Service
public class HouseSearchService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 地图找房搜索服务
     *
     * @param maxLongitude 最大经度
     * @param minLongitude 最小经度
     * @param maxLatitude  最大纬度
     * @param minLatitude  最小纬度
     * @param zoom         地图缩放比例值
     * @return
     */
    public List<HouseResultVo> search(Double maxLongitude,
                                      Double minLongitude,
                                      Double maxLatitude,
                                      Double minLatitude,
                                      Double zoom) {

        //收集聚合查询条件
        List<AggregationOperation> operationList = new ArrayList<>();

        //在可视范围内搜索
        Box box = new Box(new double[]{maxLongitude, maxLatitude}, new double[]{minLongitude, minLatitude});
        MatchOperation matchOperation = Aggregation.match
            (Criteria.where("location").within(box));
        operationList.add(matchOperation);

        int type;
        GroupOperation groupOperation;
        //根据地图的缩放比例进行分组
        if (zoom < 13.5) { //2公里以上
            //按照行政区分组
            groupOperation = Aggregation.group("districtCode");
            type = 1;
        } else if (zoom < 15.5) { //200米以上
            //按照商圈分组
            groupOperation = Aggregation.group("businessCircleCode");
            type = 2;
        } else { //200以下
            //按照小区分组
            groupOperation = Aggregation.group("communityId");
            type = 3;
        }

        groupOperation = groupOperation.count().as("total")
                .avg("price").as("price");
        operationList.add(groupOperation);

        //生成最终的聚合条件
        Aggregation aggregation = Aggregation.newAggregation(operationList);

        //执行查询
        AggregationResults<HouseResultVo> aggregationResults = this.mongoTemplate.aggregate(aggregation, House.class, HouseResultVo.class);

        List<HouseResultVo> houseResultVoList = aggregationResults.getMappedResults();
        if (CollUtil.isEmpty(houseResultVoList)) {
            return Collections.emptyList();
        }

        //填充数据
        switch (type) {
            case 1: {
                //查询行政区数据
                for (HouseResultVo houseResultVo : houseResultVoList) {
                    District district = this.queryDistrictByCode(Convert.toInt(houseResultVo.getCode()));
                    houseResultVo.setName(district.getName());
                    houseResultVo.setLongitude(district.getLocation().getX());
                    houseResultVo.setLatitude(district.getLocation().getY());
                    //价格保留2位小数
                    houseResultVo.setPrice(NumberUtil.roundStr(houseResultVo.getPrice(), 2));
                }
                break;
            }
            case 2: {
                //查询商圈数据
                for (HouseResultVo houseResultVo : houseResultVoList) {
                    BusinessCircle businessCircle = this.queryBusinessCircleByCode(Convert.toInt(houseResultVo.getCode()));
                    houseResultVo.setName(businessCircle.getName());
                    houseResultVo.setLongitude(businessCircle.getLocation().getX());
                    houseResultVo.setLatitude(businessCircle.getLocation().getY());
                    //价格保留2位小数
                    houseResultVo.setPrice(NumberUtil.roundStr(houseResultVo.getPrice(), 2));
                }
                break;
            }
            case 3: {
                //查询小区数据
                for (HouseResultVo houseResultVo : houseResultVoList) {
                    Community community = this.queryCommunityById(new ObjectId(houseResultVo.getCode()));
                    houseResultVo.setName(community.getName());
                    houseResultVo.setLongitude(community.getLocation().getX());
                    houseResultVo.setLatitude(community.getLocation().getY());
                    //价格保留2位小数
                    houseResultVo.setPrice(NumberUtil.roundStr(houseResultVo.getPrice(), 2));
                }
                break;
            }
            default: {
                return Collections.emptyList();
            }
        }

        return houseResultVoList;
    }

    /**
     * 根据code查询行政区数据
     *
     * @param code
     * @return
     */
    private District queryDistrictByCode(Integer code) {
        Query query = Query.query(Criteria.where("code").is(code));
        return this.mongoTemplate.findOne(query, District.class);
    }

    /**
     * 根据code查询商圈数据
     *
     * @param code
     * @return
     */
    private BusinessCircle queryBusinessCircleByCode(Integer code) {
        Query query = Query.query(Criteria.where("code").is(code));
        return this.mongoTemplate.findOne(query, BusinessCircle.class);
    }

    /**
     * 根据code查询小区数据
     *
     * @return
     */
    private Community queryCommunityById(ObjectId id) {
        return this.mongoTemplate.findById(id, Community.class);
    }
}

非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞 👍 关注 💖 收藏 💕 评论 💬 感谢支持!!!

相关推荐
腥臭腐朽的日子熠熠生辉31 分钟前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian33 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之38 分钟前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
俏布斯1 小时前
算法日常记录
java·算法·leetcode
27669582921 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿
爱的叹息1 小时前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
程序猿chen1 小时前
《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
java·jvm·git·后端·java-ee·区块链·量子计算
松韬2 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
绝顶少年2 小时前
Spring Boot 注解:深度解析与应用场景
java·spring boot·后端