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

news2024/11/24 1:51:02

本课程基于百度地图技术,由基础入门开始到应用实战,适合零基础入门学习。将企业项目中地图相关常见应用场景的落地实战,包括有地图找房、轻骑小程序、金运物流等。同时讲了基于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);
    }
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/872046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue前端 更具router.js 中的meta的roles实现路由卫士,实现权限判断。

参考了之篇文章 1、我在登陆时获取到登录用户的角色名roles&#xff0c;并存入sessionStorage中&#xff0c;具体是在login页面实现&#xff0c;还是在menu页面实现都可以。在menu页面实现&#xff0c;可以显得登陆快一些。 2、编写router.js&#xff0c;注意&#xff0c;一个…

链表(基础详解、实现、OJ笔试题)

文章目录 &#x1f9da;什么是链表&#xff08;链表概念及分类&#xff09;链表分类单链表和双链表的区别 &#x1f6b4;‍♂️单链表、双向链表的实现单链表的实现双向链表的实现 &#x1f349;链表经典OJ笔试题反转单链表移除链表元素合并两个有序链表链表分割链表的中间结点…

Ajax入门+aixos+HTTP协议

一.Ajax入门 概念:AJAX是浏览器与服务器进行数据通信的技术 axios使用: 引入axios.js使用axios函数:传入配置对象,再用.then回调函数接受结果,并做后续处理 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>01.axios使用…

【软件工程】面向对象方法-RUP

RUP&#xff08;Rational Unified Process&#xff0c;统一软件开发过程&#xff09;。 RUP特点 以用况驱动的&#xff0c;以体系结构为中心的&#xff0c;迭代增量式开发 用况驱动 用况是能够向用户提供有价值结果的系统中的一种功能用况获取的是功能需求 在系统的生存周期中…

机器学习笔记:李宏毅 stable diffusion

1 基本框架 ①&#xff1a;文字变成向量 ②&#xff1a;喂入噪声文字encoder&#xff0c;产生中间产物 ③&#xff1a;decoder 还原图片 2 text encoder 这张图越往右下表示效果越好&#xff0c;可以看到text encoder尺寸越大&#xff0c;对后续生成图片的增益越多 3 评价图…

【linux基础操作】如何一键下载 各个版本的python库文件

把需要下载的库名字&版本号&#xff0c;存在.txt文件中 2. 输入命令执行&#xff0c;下载 pip install -r your_file_name该命令的作用是从指定的文本文件中安装 Python 依赖库。 在这个命令中&#xff0c;-r 参数表示从一个文本文件&#xff08;通常以 .txt 结尾&#xf…

FastAPI入门

目录 FastAPI FastAPI 是什么 为什么要用 FastAPI FastAPI 入门 安装 用 FastAPI 写个接口 调试接口 创建快捷请求 保存为快捷请求 发送请求 总结 FastAPI FastAPI 是什么 什么是 FastAPI 呢&#xff1f; FastAPI 是 Python 的一个框架&#xff0c;如果要类比的话…

Java 的 Stream

一、创建 Stream 1.1、创建 Stream 流 1.1.1、List 集合获取 Stream 流 Collection<String> list new ArrayList<>(); Stream<String> s1 list.stream(); 1.1.2、Map 集合获取 stream 流 Map<String, Integer> map new HashMap<>(); // …

动态链接(8/13)

静态链接的缺点&#xff1a;生成的可执行文件体积较大&#xff0c;当多个程序引用相同的公共代码时&#xff0c;这些公共代码会多次加载到内存&#xff0c;浪费内存资源。 为了解决这个问题&#xff0c;动态链接对静态链接做了一些优化&#xff1a;对一些公用的代码&#xff0…

Titanic--细节记录三

目录 image sklearn模型算法选择路径图 留出法划分数据集 ‘留出’的含义 基本步骤和解释 具体例子 创造一个数据集 留出法划分 预测结果可视化 分层抽样 设置方法 划分数据集的常用方法 train_test_split 什么情况下切割数据集的时候不用进行随机选取 逻辑回归…

Linux系统下安装Git软件

环境说明 Linux系统&#xff1a;CentOS 7.9 安装GCC等 JDK版本&#xff1a;jdk-8u202-linux-x64.tar.gz Maven版本&#xff1a;apache-maven-3.8.8-bin.tar.gz 在以上环境下安装Git&#xff08;git-2.41.0.tar.gz&#xff09;软件。 查看是否安装Git软件 查看Git版本&#…

python代码一行过长怎么办,python中一行代码太长

这篇文章主要介绍了python每行代码长度不能超过100个字符&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 30行python代码实现豆瓣电影排行爬取 实现过程完整代码 今天我们想实…

四、Linux常用命令(一)

1、ls命令 (1)ls: list&#xff0c;列表。 (2)作用&#xff1a;使用列表把当前文件夹下所有文件显示出来。 (3)ls -a: 显示所有文件&#xff0c;包括隐藏文件。 (3)ls -l: 显示文件的详细信息。 (3)显示所有文件且显示详细信息&#xff0c;以下四种方式都可以。 ls -a -l…

腾讯云2核2g轻量应用服务器能容纳多少人?

腾讯云轻量应用服务器2核2g能容纳多少人&#xff1f;轻量应用服务器2核2g配置自带4M公网带宽&#xff0c;以网站应用为例&#xff0c;假设优化后的网页平均大小为60KB&#xff0c;2核2G4M带宽轻量服务器可以支持10个并发数&#xff0c;即同时10个人在1秒内同时打开网站&#xf…

Visual Studio 2019 解决scanf函数报错问题

前言 Visual Studio 2019 解决scanf函数报错问题 博主博客链接&#xff1a;https://blog.csdn.net/m0_74014525 关注博主&#xff0c;后期持续更新系列文章 *****感谢观看&#xff0c;希望对你有所帮助***** 系列文章 第一篇&#xff1a;Visual Studio 2019 详细安装教程&…

软工导论知识框架(八)面向对象设计风格

一.面向对象实现 把面向对象设计结果翻译成面向对象程序测试并调试面向对象的程序 二.程序设计语言 所有语言都可完成面向对象实现&#xff0c;但效果不同。 使用非面向对象语言编写面向对象程序&#xff0c;则必须由程序员自己把面向对象概念映射到目标程序中。 1.将来能够占…

Flutter源码分析笔记:Widget类源码分析

Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…

JZ37序列化二叉树

题目地址&#xff1a;序列化二叉树_牛客题霸_牛客网 题目回顾&#xff1a; 解题思路&#xff1a; 首先&#xff0c;序列化就是将二叉树的节点值放入一个字符串中&#xff0c;这里可以按照前序遍历的思路来进行操作&#xff0c;谦虚遍历是&#xff1a;根左右的情况&#xff0c;…

Java 集合详解

目录 1.集合体系结构 2.Collection集合 2.1 Collection集合 2.1.1 Collection基本方法 2.1.2 Collection遍历方式 2.1.2.1 迭代器遍历 2.1.2.2 增强for循环 2.1.2.3 Lambda表达式 3.List集合 3.1 List集合的基本方法 3.2 List集合的遍历方式 4.数据结构 4.1 数据结…

设计模式之七:适配器模式与外观模式

面向对象适配器将一个接口转换成另一个接口&#xff0c;以符合客户的期望。 // 用火鸡来冒充一下鸭子class Duck { public:virtual void quack() 0;virtual void fly() 0; };class Turkey { public:virtual void gobble() 0;virtual void fly() 0; };class TurkeyAdapter :…