Notes on Java Maps

Original link: https://www.xn2001.com/archives/724.html

[scode type=”yellow”]? I’m a little interested, just take a look, picture Yile. Learn and update by chance. [/scode]

Again, thanks to the dark horse programmer.

Bilibili Dark Horse Programmer: https://www.bilibili.com/video/BV1ue4y1R712?spm_id_from=333.999.0.0

Map overview

map technology

Map technology is a technology that uses map services to complete various services, such as: positioning based on longitude and latitude, querying travel routes, navigation, and searching for nearby shopping malls. With the development of the mobile Internet, mobile terminals can more conveniently obtain the user’s location data, and the application of map technology has also been widely used, such as: online car-hailing, smart wear, smart logistics, smart scenic spots, Internet real estate, online travel , vehicle data services, etc.

Map application scenarios

Online car-hailing service

In the online car-hailing scenario, core requirements such as accurate positioning, navigation, simultaneous display of drivers and passengers, and accurate billing are realized.

smart wear

Realize various needs such as positioning, navigation, trajectory tracking and guidance of smart wearable devices.

Smart Logistics

The intelligent logistics solution is in the middle, and the map technology supports multiple core business scenarios such as logistics order placement, order distribution, trunk transportation planning, and trajectory management.

Smart Scenic Spot

Realize the intelligent and scene-based scenic spots through map services, and create personalized intelligent scenic spots.

Internet of Vehicles

Auto companies use map data and online map services to meet the needs of scenarios such as in-vehicle navigation, autonomous driving, and handcart interconnection.

Domestic common maps

Baidu map

Official website: https://map.baidu.com/

Development platform: https://lbsyun.baidu.com/

Gaode map

Official website: https://www.amap.com/

Development Platform: https://lbs.amap.com/

Tencent map

Official website: https://map.qq.com/

Open platform: https://lbs.qq.com/

Sogou Map

Official website: http://map.sogou.com/

Open Platform: http://map.sogou.com/api/

Maps API and Search

Baidu Maps provides SDKs for various platforms, address: https://lbsyun.baidu.com/

JS API GL

Create a browser-side application

Log in to your account, enter the console, and become a personal developer, https://lbsyun.baidu.com/apiconsole/user/choose

App Management -> My Apps -> Create App

  • Enter the app name and app type.
  • Here first select the browser side to learn.
  • The “*” sign is set in the whitelist, indicating that there is no domain name restriction.

The creation is completed, and the “AK” is obtained

Pull the project and complete some cases.

Create a map

Refer to the official documentation: https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/show

Note that “your key” in the second step “Introducing Baidu Map API File” needs to be changed to the application “AK” created above

 <!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=您的密钥"></script> </head> <body> <div id="container"> </div> <script> 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); //设置地图的倾斜角度</script> </body> </html>

Add controls

Controls are UI elements responsible for interacting with the map. Baidu Maps API supports scale, zoom, positioning, city selection list, copyright, and custom controls. Documentation: https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/widget

 var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件map.addControl(scaleCtrl); var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件map.addControl(zoomCtrl); var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件map.addControl(cityCtrl); var locationCtrl = new BMapGL.LocationControl(); // 添加定位控件map.addControl(locationCtrl);

Add mulch

All overlays or overlays on the map are collectively referred to as map overlays. Overlays have their own geographic coordinates, and when you drag or zoom the map, they move accordingly. The overlays currently supported by the JSAPI GL version are based on basic graphics. Documentation: https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/addOverlay

Overlays can be added to the map using the map.addOverlay method and removed using the map.removeOverlay method.

cover class name illustrate
abstract base class Overlay All overlays inherit the methods of this class
point Marker Represents a point on the map, with customizable label icons
Polyline Polyline Represents a polyline on the map
polygon Polygon Represents polygons on the map
round Circle Represents a circle on a map

Add point labels

 var point = new BMapGL.Point(116.404, 39.915); var marker = new BMapGL.Marker(point); // 创建标注map.addOverlay(marker); // 将标注添加到地图中// 监听标注点marker.addEventListener("click", function () { alert("您点击了该位置"); });

map event

Most of the objects in the Baidu Maps API contain the addEventListener method, through which you can listen to object events. For example, BMapGL.Map contains events like click, dblclick, etc. In a specific environment, these events will be triggered, and the listener function will get the corresponding event parameter e. For example, when the user clicks on the map, the e parameter will contain the geographic location latlng corresponding to the mouse.

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

map style

Baidu Maps supports setting map styles, such as setting the map to Earth mode, documentation: https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/maptype

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

map search

Just look at the Baidu map case for this piece of content: https://lbsyun.baidu.com/jsdemo.htm#localSearchKey

 var local = new BMapGL.LocalSearch(map, { renderOptions:{map: map} }); local.search("景点");

data visualization

MapVGL, a WebGL-based geographic information visualization library, can be used to display a large number of 3D-based geographic information point, line, and surface data.

Documentation: https://lbsyun.baidu.com/solutions/mapvdata

Web service API

Provides the http/https interface for developers, that is, the developer initiates a retrieval request through http/https, and obtains the retrieved data in json or xml format. Based on this, users can develop map applications in languages ​​such as JavaScript, C#, C++, and Java. Document address: https://lbsyun.baidu.com/index.php?title=webapi

Create a server application

Enter the application name and application type, here select the server side for learning.

The number “0.0.0.0/0” is set in the IP whitelist, indicating that there is no restriction on IP addresses.

image-20220713181423728

Coordinate transformation

At present, China mainly has the following three coordinate systems:

WGS84: It is a geodetic coordinate system, and it is also the coordinate system used by the widely used GPS global satellite positioning system.

GCJ02: It is the coordinate system of the geographic information system formulated by the National Bureau of Surveying and Mapping of China. It is the encrypted coordinate system of the WGS84 coordinate system.

BD09: Baidu coordinate system, encrypted again on the basis of GCJ02 coordinate system, where bd09ll represents Baidu latitude and longitude coordinates, and bd09mc represents Baidu Mercator metric coordinates.

The web api provides an interface service for converting non-Baidu coordinates to Baidu coordinate system.

Official website document: https://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition

Through this service, users can realize the conversion from non-Baidu coordinate system (GPS standard coordinates, amap map coordinates, tencent map coordinates, mapbar map coordinates, etc.) to Baidu coordinate system.

It’s relatively simple, just follow the documentation to read it.

 @Test public void test1(){ String url = "https://api.map.baidu.com/geoconv/v1/?coords=114.21892734521,29.575429778924&from=1&to=5&ak={}"; url = StrUtil.format(url, ak); String body = HttpRequest.get(url).execute().body(); System.out.println(body); }

IP status

Ordinary IP positioning is a set of lightweight positioning interfaces provided in the form of HTTP/HTTPS. Users can obtain approximate positions based on IP positioning through this service. It is suitable for applications that request positioning from IPs that do not require high positioning accuracy.

Documentation: https://lbsyun.baidu.com/index.php?title=webapi/ip-api

 @Test public void test2(){ String url = "http://api.map.baidu.com/location/ip?ak={}&ip={}&coor=bd09ll"; url = StrUtil.format(url,ak,"140.206.149.83"); String body = HttpRequest.get(url).execute().body(); JSONObject object = JSONUtil.parseObj(body); System.out.println(object); }

Location input prompt

The user can use this service to match the recommended list of places with the keywords entered by the user. Match user input content and provide input prompt function. Often used in conjunction with location retrieval services. It can also be used alone as a lightweight location retrieval service (complex retrieval scenarios are not supported).

Documentation: https://lbsyun.baidu.com/index.php?title=webapi/place-suggestion-api

 @Test public void test3(){ String url = "https://api.map.baidu.com/place/v2/suggestion?query={}&region=广州&city_limit=true&output=json&ak={}"; url = StrUtil.format(url,"广财",ak); String body = HttpRequest.get(url).execute().body(); JSONObject object = JSONUtil.parseObj(body); System.out.println(object); }

route planning

The Route Planning Service (aka Direction API) is a set of RESTful web service APIs that provide route planning services in HTTP/HTTPS. Currently, the Direction API supports bus, cycling, and driving route planning, and the Direction API supports mainland China.

Documentation: https://lbsyun.baidu.com/index.php?title=webapi/direction-api-v2

Take “Driving Route Planning” as an example:

 @Test public void test4(){ String url = "https://api.map.baidu.com/direction/v2/driving?origin=40.01116,116.339303&destination=39.936404,116.452562&ak={}"; url = StrUtil.format(url,ak); String body = HttpRequest.get(url).execute().body(); JSONObject object = JSONUtil.parseObj(body); System.out.println(object); }

map navigation

BMapGLLib

lBMapGLLib is a JavaScript open source tool library based on Baidu Map JS API GL version. Code address: https://github.com/huiyan-fe/BMapGLLib

static page

The basic idea steps of static page implementation:

1. To load Baidu map, you need to turn on the scroll wheel function and display the scale;

Introduce the necessary resources, be careful not to hang on the “ladder”.

 <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=yQaLjgCSeyRSBLBwjtKK73L4IBlRTVZk"></script> <script type="text/javascript" src="jquery-3.6.0.min.js"></script> <script type="text/javascript" src="https://mapopen.bj.bcebos.com/github/BMapGLLib/RichMarker/src/RichMarker.min.js"></script>

2. Add drag and zoom events to the map to control the display of overlays;

Supported events, official website documentation: https://mapopen-pub-jsapi.bj.bcebos.com/jsapi/reference/jsapi_webgl_1_0.html

We clear the overlay when dragging and zooming starts, and show the overlay after dragging and zooming ends and at the initial state.

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

3. Display custom overlays through the RichMarker (rich annotation) in the BMapGLLib tool library of Baidu Maps;

It is relatively simple, you need to know how to use RichMarker, the official case: https://github.com/huiyan-fe/BMapGLLib/blob/master/RichMarker/examples/RichMarker.html

 function clearMapMarker(map) { let markers = map.getOverlays(); for (let marker of markers) { map.removeOverlay(marker); } } 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); } }

4. Load data asynchronously through Ajax, dynamically generate overlays, and display them on the map.

In this step, you also need to consider the visible range of the map, and only search and display the data display within the visible range.

 function showInfo(map) { // 可视范围矩形坐标, // 其中sw表示矩形区域的西南角,ne表示矩形区域的东北角// 相当于拿到地图在可视区域的范围// 用于获取范围内的有效数据let bound = map.getBounds(); // 缩放级别let zoom = map.getZoom(); console.log(bound); // todo Ajax 请求数据// --- // 测试数据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); }

MongoDB environment

It is relatively simple to directly use Docker to build a MongoDB environment.

 #拉取镜像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: '123456', roles: [ { role: "root", db: "admin" } ] }) #退出后进行认证exit #进行认证mongo -u "root" -p "123456" --authenticationDatabase "admin" #通过admin添加普通用户use admin db.createUser({ user: 'house', pwd: '123456', roles: [ { role: "readWrite", db: "house" } ] }); #退出后进行认证exit #通过house用户登录进行测试mongo -u "house" -p "123456" --authenticationDatabase "admin" #发现可以正常进入控制台进行操作

Configure MongoDB in the backend application.properties configuration file

 #springboot MongoDB配置spring.data.mongodb.username=house spring.data.mongodb.password=123456 spring.data.mongodb.authentication-database=admin spring.data.mongodb.database=house spring.data.mongodb.port=27017 spring.data.mongodb.host=192.168.211.129 spring.data.mongodb.auto-index-creation=true

Use Navicat to connect to the database and import data

MongoDB aggregation

Aggregation operations in MongoDB are done in the form of pipelines, and after one pipeline is processed, the results are passed to the next pipeline for processing.

Common aggregation operations are:

expression effect
$project Modify the structure of the input document. Can be used to rename, add or delete fields, and can also be used to create calculated results and nested documents.
$match Used to filter data and only output documents that meet the conditions. $match uses MongoDB’s standard query operations.
$limit Used to limit the number of documents returned by the MongoDB aggregation pipeline.
$skip Skips the specified number of documents in the aggregation pipeline and returns the remaining documents.
$unwind Splits an array type field in the document into multiple entries, each containing a value in the array.
$group Groups documents in a collection, which can be used for statistical results.
$sort Sort the input documents and output them.
$geoNear Output ordered documents close to a geographic location.

MongoDB aggregate operators

Mainly used to process data (such as statistical average, summation, etc.), and return the calculated data results.

Similar operations like count(*) in SQL statements, commonly used operations are as follows:

expression describe example
$sum Calculate the sum. db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg Calculate the average. db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min Get the minimum value corresponding to all documents in the collection. db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max Get the maximum value corresponding to all documents in the collection. db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push Inserts values ​​into an array in the resulting document. db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet Inserts values ​​into an array in the resulting document, but does not create a copy. db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first Get the first document data according to the sorting of resource documents. db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last Get the last document data according to the sorting of resource documents. db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

structure data

Check the number of listings and average prices in each district by administrative district.

 db.tb_house.aggregate([{ $group: { _id: "$districtCode", price: { $avg: "$price" }, total: { $sum: 1 } } }])

back-end search

 @RestController @RequestMapping("/house/search") public class HouseSearchController { @Autowired private HouseSearchService houseSearchService; /** * 地图找房搜索服务* * @param maxLongitude 最大经度* @param minLongitude 最小经度* @param maxLatitude 最大纬度* @param minLatitude 最小纬度* @param zoom 地图缩放比例值*/ @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 houseSearchService.search(maxLongitude, minLongitude, maxLatitude, minLatitude, zoom); } }

The business is not difficult but cumbersome, and different query operations are performed through different map ranges.

Tucao: The word was misspelled, the query was empty, I couldn’t find it after searching for an hour, and I finally woke up after rewriting it. Impressed.

 package com.xn2001.baidumap.search.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.NumberUtil; import com.xn2001.baidumap.pojo.BusinessCircle; import com.xn2001.baidumap.pojo.Community; import com.xn2001.baidumap.pojo.District; import com.xn2001.baidumap.pojo.House; import com.xn2001.baidumap.search.HouseSearchService; import com.xn2001.baidumap.vo.HouseResultVo; 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; /** * @author 乐心湖* @version 1.0 * @date 2022/7/15 4:10 */ @Service public class HouseSearchServiceImpl implements HouseSearchService { @Autowired private MongoTemplate mongoTemplate; public List<HouseResultVo> search(Double maxLongitude, Double minLongitude, Double maxLatitude, Double minLatitude, Double zoom) { //聚合查询条件List<AggregationOperation> aggregationOperations = new ArrayList<>(); //可视范围内搜索Box box = new Box(new double[]{maxLongitude, maxLatitude}, new double[]{minLongitude, minLatitude}); MatchOperation location = Aggregation.match(Criteria.where("location").within(box)); aggregationOperations.add(location); //分组信息GroupOperation groupOperation; int type; //根据地图缩放比例分组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"); aggregationOperations.add(groupOperation); //生成最终的聚合条件Aggregation aggregation = Aggregation.newAggregation(aggregationOperations); //执行聚合查询AggregationResults<HouseResultVo> aggregate = mongoTemplate.aggregate(aggregation, House.class, HouseResultVo.class); //拿到匹配结果List<HouseResultVo> houseResultVos = aggregate.getMappedResults(); if (CollUtil.isEmpty(houseResultVos)) { return Collections.emptyList(); } switch (type){ case 1: //查询行政区数据for (HouseResultVo houseResultVo : houseResultVos) { 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 : houseResultVos) { 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 : houseResultVos) { Community community = this.queryCommunityById(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 houseResultVos; } /** * 根据code查询行政区数据* @return */ private District queryDistrictByCode(Integer code) { Query query = Query.query(Criteria.where("code").is(code)); return mongoTemplate.findOne(query, District.class); } /** * 根据code查询商圈数据* @return */ private BusinessCircle queryBusinessCircleByCode(Integer code) { Query query = Query.query(Criteria.where("code").is(code)); return mongoTemplate.findOne(query, BusinessCircle.class); } /** * 根据code查询小区数据* @return */ private Community queryCommunityById(Object id) { return mongoTemplate.findById(id, Community.class); } }

Front-end Ajax request

 $.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); } })

healthy exercise track

. . .

This article is reprinted from: https://www.xn2001.com/archives/724.html
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment