java地图完整项目-地图找房(基于百度地图-MongoDB)

 1、BMapGLLib库

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

该库相关辅助功能可通过点击上述网址进行查看!

2、项目静态页面: 

要有一个search.html界面和jQuery-3.6.0.min.js的包的资源:

其中search.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>地图找房</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=你的游览器端的密钥"></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);
        //已经构建好数据库的情况下使用
        // $.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>

3、搭建MongoDB环境:

(1)通过官方直接下载!!!

(相关操作在个人主页的MongoDB笔记中)

网址:MongoDB的安装、部署和启动连接(包含可视化Compass)_Ape 佬的博客-CSDN博客

(2)安装完后进行数据库的部署操作:


#进入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"

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

(3)在application.yml中引入spring-data-mongodb的配置:

spring:
  data:
    mongodb:
      username: house    #账号
      password: ******   #密码
      authentication-database: admin  #数据库
      database: house    
      port: 27017        #端口号
      host: ***.*.*.*    #个人主机
      auto-index-creation: true

4、构造数据:

(1)区数据:

 创建数据库,在集合中去运行脚本:(前提要准备数据***.js)

 (2)商圈数据:

 (3)小区数据:

 (4)房源数据:

 5、MongoDB的聚合操作:

聚合操作符:

 

6、 实现搜索-分析:

(1)要导入相应的Pojo类,分别对应上文构建数据库数据的四个区,


/**
 * 房源
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tb_house")
public class House {

    @Id
    private ObjectId id; //主键id
    private String title; //房源标题
    private Double price; //总价
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location; //x:经度 y:纬度

    @Indexed
    private Integer districtCode; //所属行政区
    @Indexed
    private ObjectId communityId; //所属小区
    @Indexed
    private Integer businessCircleCode; //商圈

    private Long created; //创建时间

}



/**
 * 行政区
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tb_district")
public class District {

    @Id
    private ObjectId id; //主键id
    private String name; //名称
    @Indexed
    private Integer code; //编号
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location; //x:经度 y:纬度

}


/**
 * 小区
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tb_community")
public class Community {

    @Id
    private ObjectId id; //主键id

    private String name; //名称

    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location; //x:经度 y:纬度

    @Indexed
    private Integer districtCode; //所属区
    @Indexed
    private Integer businessCircleCode; //商圈

    private String lianJiaUrl; //链家网url

}



/**
 * 商圈
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tb_business_circle")
public class BusinessCircle {

    @Id
    private ObjectId id; //主键id

    private String name; //名称

    @Indexed
    private Integer code; //编号

    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location; //x:经度 y:纬度

    @Indexed
    private Integer districtCode; //所属区

    private String lianJiaUrl; //链家网url

}


(2) 创建一个vo包里的HouseResultVo类,专门用来作为统一的返回对象,供前端页面显示数据!

@Data
public class HouseResultVo {
//返回到前端时不使用
    @JsonIgnore
    @Field("_id")
    private String code; //用于MongoDB聚合查询结果的映射

    private String name; //显示的名称,可能是区、商业圈、小区
    private String price; //均价
    private String total; //房源数量
    private Double longitude; //位置经度
    private Double latitude; //位置维度

}

(3)控制层类:controller,前端页面进行调用访问路径获得数据!!!

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

    @Autowired
    private HouseSearchService houseSearchService;

    /*
    * 地图找房搜索服务
    * 最大小经度
    * 最大小纬度
    * 地图缩放比例
    * */
    @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);

    }

}

其中会调用到业务层方法,其业务层主要是执行Mongodb数据库的操作!从而获取数据并返回相应的值!

(4)业务层内容:

@Service
public class HouseSearchService {
    @Autowired
    private MongoTemplate mongoTemplate;

    /*
     * 地图找房搜索服务
     * 最大小经度
     * 最大小纬度
     * 地图缩放比例
     * */
    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= 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());
                    //价格保留两位小数
                    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());
                    //价格保留两位小数
                    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());
                    //价格保留两位小数
                    houseResultVo.setPrice(NumberUtil.roundStr(houseResultVo.getPrice(),2));
                }
                break;
            }
            default:{
                return Collections.emptyList();
            }

        }

        return houseResultVoList;
    }


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

    //    根据Code查询商圈区
    public BusinessCircle queryBusinessCircleByCode(Integer code){
        Query query = Query.query(Criteria.where("code").is(code));
        return  this.mongoTemplate.findOne(query,BusinessCircle.class);
    }

    //    根据id查询小区
    public Community queryCommunityById(ObjectId id){
        return  this.mongoTemplate.findById(id,Community.class);
    }



}

(5)项目工程目录:

 (6)运行测试:

http://127.*.*.*:8080/search.html(本机ip地址+访问页面的端口号+前端页面路径)

(7)结果:


此外,在项目中还会出现一些bug,其中就有依赖冲突的问题,因此为了方便大家,下面为正确的pom.xml内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lingnan</groupId>
    <artifactId>Map</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Map</name>
    <description>Map</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--springdata对于mongodb支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <!--        代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>

        <!--        实体类简化-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

<!--        地图web服务-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.5</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值