当前位置:网站首页>地图找房的实例
地图找房的实例
2022-07-27 16:18:00 【猫的幻想曲】
1.功能说明:
- 在房源信息类网站中,为了方便用户查找房源,推出了地图找房的功能,房源数据展示更加的直观。
- 例如:链家网:上海地图找房_上海小区地图_上海房产地图(上海链家)


BMapGLLib:
- BMapGLLib是基于百度地图JSAPI GL版的JavaScript开源工具库。
- 代码地址: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=XdBGuSs0p90SNRM3dtpGGbvEygzfQyte"></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>搭建MongoDB环境:

application.properties文件中的配置:
spring.application.name = itcast-baidumap
server.port = 8899
#springboot MongoDB配置
spring.data.mongodb.username=house
spring.data.mongodb.password=********
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=house
spring.data.mongodb.port=27017
spring.data.mongodb.host=192.168.31.81
spring.data.mongodb.auto-index-creation=true构造数据:
为了数据真实性,我们从网上抓取一些小区的数据,小区的位置数据可以通过百度地图API数据

案例以上海为例,其有16个行政区
构造完成的数据如下:

商圈数据是行政区的下级分类:

构造完成后有198条数据

小区数据抓取网上的数据。
抓取完成后,共有20510条数据(建议使用提供的数据即可,无需重新抓取)

由于房源数据仅仅是展现数量,所以就不再进行数据抓取,按照小区数据进行构造即可
每个小区随机构造1~20个房源数据
最终构造完成有106094条数据。

MongoDB的聚合操作:
- MongoDB的聚合操作是以管道的形式完成的,在一个管道处理完毕后将结果传递给下一个管道处理
- 常用的聚合操作有:

MongoDB的聚合操作符:

实现搜索:
实现搜索的关键点:
通过矩形的对角的坐标可以确定矩形搜索范围。
需要按照不同的地图比例尺进行分组聚合查询,通过按照行政区、商圈或小区名进行分组,聚合数量、价格等数据。
响应数据:

pom文件:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--通过继承的方式集成SpringBoot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<groupId>cn.itcast</groupId>
<artifactId>itcast-baidumap</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 集中定义依赖版本号 -->
<properties>
<mongo.version>4.0.3</mongo.version>
<lombok.version>1.18.4</lombok.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>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.2</version>
</dependency>
<!--springdata对于mongodb支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-core</artifactId>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.7.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>实现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 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;
/**
* @Description:
* @Author : Jerry
* @create : 2022-07-19 18:50
*/
@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,maxLongitude},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());
//价格保留两位小数
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查询行政区数据
* @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查询小区数据
* @param id
* @return
*/
private Community queryCommunityById(ObjectId id){
return this.mongoTemplate.findById(id,Community.class);
}
}
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.*;
import java.util.List;
/**
* @Description:
* @Author : Jerry
* @create : 2022-07-19 18:40
*/
@RequestMapping("house/search")
@RestController
public class HouseSearchController {
@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);
}
}
实现效果:根据缩放的程度,显示不同的寻房的信息。


边栏推荐
- 2021.8.7 note Servlet
- Must the MySQL query column be consistent with the group by field?
- Alibaba architects spent 280 hours sorting out 1015 pages of distributed full stack pamphlets to easily start the distributed system
- 「MySQL那些事」一文详解索引原理
- Use mobaxtermto establish a two-tier springboard connection
- Complete set of machine learning classification task effect evaluation indicators (including ROC and AUC)
- Solve the problem of JSP cascading
- How to realize the full-text content retrieval of word, PDF and txt files?
- Idea packaging war package and war package location
- Uniapp H5 cross domain problem
猜你喜欢

LED学习护眼台灯触摸芯片-DLT8T10S-杰力科创

搭建一个简单的知识问答系统

你有没有在MySQL的order by上栽过跟头

MySQL 主从复制数据不一致,怎么办?

Uniapp H5 cross domain problem

2021.7.13 note sub query

Use ETL tools for data migration in salesforce project

阿里架构师耗时280个小时整理的1015页分布式全栈小册,轻松入手分布式系统

【npm】 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。

2021.7.31笔记 视图
随机推荐
微信小程序多文件上传
微信小程序 wxacode.getUnlimited生成小程序码
Canvas draws graphics according to coordinate points
2021.7.28 notes
智能失眠治疗仪产品-DLT8P68SA-杰力科创
全身多功能按摩仪芯片-DLTAP602SD
电动加热护颈枕芯片-DLTAP703SC
2021.7.12笔记 内外连接
全自动吸奶器芯片-DLTAP703SD
Wechat applet obtains mobile number
2021.7.18笔记 mysql数据类型
浴室带除雾化妆镜触摸芯片-DLT8T10S
pandas的to_sql函数使用
Commonly used built-in methods of mybtis plus
USB充电式暖手宝芯片-DLTAP602SC-杰力科创
Use ETL tools for data migration in salesforce project
Using Jieba and pyhanlp tools to extract keyword words and sentences
filebeat.yml配置文件关于多个服务的配置问题
微信小程序微信支付概述
"MySQL things" explains the indexing principle in detail