Springboot 微信小程序定位后将坐标转换为百度地图坐标,在百度地图做逆地址解析

news2024/11/17 22:29:04

问题解析以及解决思路

业务:微信小程序定位后,将坐标转换为百度地图坐标,在百度地图做逆地址解析

问题:微信小程序的定位是拿的腾讯地图的经纬度,但是我们app端这边使用的百度地图,如果直接使用腾讯地图的经纬度再使用腾讯地图的逆地址解析需要腾讯和百度商业授权,为了减少授权成本

解决方案:将腾讯地图的经纬度转换为百度地图的经纬度后,再进行逆地址解析

  • 腾讯地图转百度地图此处有两种解决方案
    • 使用数学的方式进行转换可参考我的这篇文章微信小程序定位判断点位是否在某个范围内(腾讯地图转百度地图),但是这种方法有会导致定位有偏差,如果对定位精度要求高的需求不建议使用
    • 使用百度地图的官方接口进行转换(我相信官方的转换精度肯定会高一些,本文使用)

本文使用到的两个百度地图的接口文档如下

坐标转换

全球逆地理编码

解决方案实现

开通百度地图相关接口权限

Springboot对接接口

  1. 新增接口相关的配置
baidu:
  service: # 服务端应用
    appId: 1160xxxxx
    apiKey: C8NCMTxxxxxxxxxxxxxxxxxxx
  1. 百度接口统一返回对象封装
import lombok.Data;

@Data
public class BaiduApiResponse<T> {
    private int status;
    private T result;
}

  1. 坐标转换返回对象封装
import lombok.Data;

import java.util.List;

@Data
public class GeoConvResponseDto {
    private double x;
    private double y;

}

  1. 全球逆地理编码返回对象封装
import lombok.Data;

import java.util.List;

@Data
public class ReverseGeocodingResponseDto {
    private Location location;
    private String formatted_address;
    private Edz edz;
    private String business;
    private AddressComponent addressComponent;
    private List<Object> pois;
    private List<Object> roads;
    private List<Object> poiRegions;
    private String sematic_description;
    private String formatted_address_poi;
    private int cityCode;

    @Data
    public static class Location {
        private double lng;
        private double lat;
    }

    @Data
    public static class Edz {
        private String name;
    }

    @Data
    public static class AddressComponent {
        private String country;
        private int country_code;
        private String country_code_iso;
        private String country_code_iso2;
        private String province;
        private String city;
        private int city_level;
        private String district;
        private String town;
        private String town_code;
        private String adcode;
        private String street;
        private String street_number;
    }
}


  1. 点位对象封装
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class CoordinateDto {
    private double longitude;
    private double latitude;

    @Override
    public String toString() {
        return longitude + "," + latitude;
    }
}

  1. BaiduMapService(方法实现)
  • requestGeoConv参数解释
    • coords: 需转换的源坐标,多组坐标以“;”我这里使用的coordinate对象重新了toString方法来构造接口参数
    • ak: 开发者密钥, 申请AK
    • model:
      • 转换方式可选值(默认值 1):
        1:amap/tencent to bd09ll
        2:gps to bd09ll
        3:bd09ll to bd09mc
        4:bd09mc to bd09ll
        5:bd09ll to amap/tencent
        6:bd09mc to amap/tencent
  • requestReverseGeocoding 参数解释
    • location: 根据经纬度坐标获取地址。(请注意这里是反过来的38.76623,116.43213lat<纬度>,lng<经度>)
    • ak: 开发者密钥, 申请AK
    • coordtype: 传入的坐标类型,目前支持的坐标类型包括:bd09ll(百度经纬度坐标)、bd09mc(百度米制坐标)、gcj02ll(国测局经纬度坐标,仅限中国)、wgs84ll( GPS经纬度)坐标系说明
      • 因为requestGeoConv方法已经给我们将经纬度转换为bd09ll标准了,所以我写死为bd09ll
    • extensions_poi: extensions_poi=0,不召回pois数据。
      extensions_poi=1,返回pois数据(默认显示周边1000米内的poi),并返回sematic_description语义化数据。
package com.applets.manager.core.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.applets.manager.core.exception.BusinessException;
import com.applets.manager.core.model.dto.BaiduApiResponse;
import com.applets.manager.core.model.dto.CoordinateDto;
import com.applets.manager.core.model.dto.GeoConvResponseDto;
import com.applets.manager.core.model.dto.ReverseGeocodingResponseDto;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class BaiduMapService {
    private static final String GEO_CONV_URL = "https://api.map.baidu.com/geoconv/v2/?";
    private static final String REVERSE_GEOCODING_URL = "https://api.map.baidu.com/reverse_geocoding/v3?";

    @Value("${baidu.service.appId}")
    private String appId;

    @Value("${baidu.service.apiKey}")
    private String apiKey;
    /**
     * 发送请求到百度地图 API,执行坐标转换
     *
     * @param coordinate  点位对象,即经纬度对象
     * @param model  转换模型
     * @return API 响应结果
     * @throws Exception
     */
    public BaiduApiResponse<List<GeoConvResponseDto>> requestGeoConv(CoordinateDto coordinate, String model) throws Exception {
        Map<String, String> params = new LinkedHashMap<>();
        params.put("coords", coordinate.toString());
        params.put("model", model);
        params.put("ak", apiKey);
        String res = sendGetRequest(GEO_CONV_URL, params);
        BaiduApiResponse<List<GeoConvResponseDto>> response = null;
        if (StringUtils.isNotEmpty(res)){
            response = JSON.parseObject(res, new TypeReference<BaiduApiResponse<List<GeoConvResponseDto>>>() {});
            if (0 != response.getStatus()){
                log.info("坐标转换结果:{}", response);
                throw new BusinessException("百度接口请求错误:"+response.getResult());
            }
        }

        return response;
    }

    /**
     * 发送请求到百度地图 API,执行逆地理编码
     *
     * @param coordinate  点位对象,即经纬度对象
     * @return API 响应结果
     * @throws Exception
     */
    public BaiduApiResponse<ReverseGeocodingResponseDto> requestReverseGeocoding(CoordinateDto coordinate) throws Exception {
        Map<String, String> params = new LinkedHashMap<>();
        params.put("ak", apiKey);
        params.put("output", "json");
        params.put("coordtype", "bd09ll");
        params.put("extensions_poi", "0");
        params.put("location", coordinate.getLatitude()+","+coordinate.getLongitude());

        String res = sendGetRequest(REVERSE_GEOCODING_URL, params);

        BaiduApiResponse<ReverseGeocodingResponseDto> response = null;
        if (StringUtils.isNotEmpty(res)){
            response = JSON.parseObject(res, new TypeReference<BaiduApiResponse<ReverseGeocodingResponseDto>>() {});
            if (0 != response.getStatus()){
                log.info("坐标转换结果:{}", response);
                throw new BusinessException("百度接口请求错误:"+response.getResult());
            }
        }
        return response;
    }

    /**
     * 通用的 GET 请求方法
     *
     * @param strUrl API URL
     * @param param 请求参数
     * @return 响应字符串
     * @throws Exception
     */
    private String sendGetRequest(String strUrl, Map<String, String> param) throws Exception {
        if (strUrl == null || strUrl.isEmpty() || param == null || param.isEmpty()) {
            throw new IllegalArgumentException("URL 和参数不能为空");
        }

        StringBuilder queryString = new StringBuilder(strUrl);
        for (Map.Entry<String, String> entry : param.entrySet()) {
            queryString.append(entry.getKey()).append("=")
                    .append(UriUtils.encode(entry.getValue(), "UTF-8")).append("&");
        }

        // 删除最后一个 '&' 字符
        queryString.deleteCharAt(queryString.length() - 1);

        URL url = new URL(queryString.toString());
        HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.connect();

        try (InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
             BufferedReader reader = new BufferedReader(isr)) {

            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            log.info("BaiduMapService.sendGetRequest.response:{}",response.toString());

            return response.toString();
        }
    }

}

测试

import com.alibaba.fastjson.JSON;
import com.applets.manager.api.StartApplication;
import com.applets.manager.core.model.dto.BaiduApiResponse;
import com.applets.manager.core.model.dto.CoordinateDto;
import com.applets.manager.core.model.dto.GeoConvResponseDto;
import com.applets.manager.core.model.dto.ReverseGeocodingResponseDto;
import com.applets.manager.core.service.BaiduMapService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.geotools.referencing.GeodeticCalculator;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.web.util.UriUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zr 2024/4/17
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StartApplication.class)
@Slf4j
public class BaiduMapTest {

    @Autowired
    private BaiduMapService baiduMapService;

    @Test
    public void requestGeoConv() {
        try {
            BaiduApiResponse<List<GeoConvResponseDto>> geoConvResponseDtoBaiduApiResponse = baiduMapService.requestGeoConv(new CoordinateDto(103.979967,30.990777), "1");
            log.info("requestGeoConv: " + JSON.toJSONString(geoConvResponseDtoBaiduApiResponse));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void requestReverseGeocoding() {
        try {
            BaiduApiResponse<ReverseGeocodingResponseDto> response = baiduMapService.requestReverseGeocoding(new CoordinateDto(103.98657912268618,30.996470768223653));
            log.info("requestReverseGeocoding: " + JSON.toJSONString(response));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

坐标转换测试

初始点位是我随便再腾讯地图上找的点位

注意:这里百度地图返回的地址是一个list

全球逆地理编码测试

使用第一步转换的结果进行逆地址解析

返回json实例

{"result":{"addressComponent":{"adcode":"510182","city":"成都市","city_level":2,"country":"中国","country_code":0,"country_code_iso":"CHN","country_code_iso2":"CN","district":"彭州市","province":"四川省","street":"什彭路","street_number":"","town":"天彭街道","town_code":"510182001"},"business":"","cityCode":75,"edz":{"name":""},"formatted_address":"四川省成都市彭州市什彭路","formatted_address_poi":"","location":{"lat":30.99647061454463,"lng":103.98657912268614},"poiRegions":[],"pois":[],"roads":[],"sematic_description":""},"status":0}

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

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

相关文章

vue注册全局组件,其他地方可以直接方便的调用

文章目录 问题注册全局组件完结 问题 本来我们想使用某个组件&#xff0c;需要在各个地方引入对应的参数&#xff0c;并配置好components内容&#xff0c;才可以使用 但是随着用的越来越多&#xff0c;这种方法变得重复且易出错 注册全局组件 修改main.js文件&#xff0c;放…

Kubernetes 10 问,测测你对 k8s 的理解程度

Kubernetes 10 问 假设集群有 2 个 node 节点&#xff0c;其中一个有 pod&#xff0c;另一个则没有&#xff0c;那么新的 pod 会被调度到哪个节点上&#xff1f; 应用程序通过容器的形式运行&#xff0c;如果 OOM&#xff08;Out-of-Memory&#xff09;了&#xff0c;是容器重…

Java项目实战II基于微信小程序的课堂助手(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化教…

高光谱深度学习调研

综述 高光谱深度学习只有小综述&#xff0c;没有大综述。小综述里面场景分类、目标检测的综述比较多。 Wang C, Liu B, Liu L, et al. A review of deep learning used in the hyperspectral image analysis for agriculture[J]. Artificial Intelligence Review, 2021, 54(7)…

抖音热门素材去哪找?优质抖音视频素材网站推荐!

是不是和我一样&#xff0c;刷抖音刷到停不下来&#xff1f;越来越多的朋友希望在抖音上创作出爆款视频&#xff0c;但苦于没有好素材。今天就来推荐几个超级实用的抖音视频素材网站&#xff0c;让你的视频内容立刻变得高大上&#xff01;这篇满是干货&#xff0c;直接上重点&a…

人工智能之数学基础:数学在人工智能领域中的地位

人工智能&#xff08;AI&#xff09;是一种新兴的技术&#xff0c;它的目标是构建能够像人类一样思考、学习、推理和解决问题的智能机器。AI已经成为了许多行业的重要组成部分&#xff0c;包括医疗、金融、交通、教育等。而数学则是AI领域中不可或缺的基础学科。本文将阐述数学…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(十三)图优化SLAM的本质

一、直白解释slam与图优化的结合 我从b站上学习理解的这个概念。 视频的大概位置是1个小时以后&#xff0c;在第75min到80min之间。图优化SLAM是怎么一回事。 slam本身是有运动方程的&#xff0c;也就是运动状态递推方程&#xff0c;也就是预测过程。通过t1时刻&#xff0c…

STM32单片机设计防儿童人员误锁/滞留车内警报系统

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 近年来在车辆逐渐普及的情况下&#xff0c;由于家长的疏忽&#xff0c;将…

stm32——通用定时器时钟知识点

&#xff08;该图来自小破站 铁头山羊老师的stm32标准库教学&#xff09;

GPIO相关的寄存器(重要)

目录 一、GPIO相关寄存器概述 二、整体介绍 三、详细介绍 1、端口配置低寄存器&#xff08;GPIOx_CRL&#xff09;&#xff08;xA...E&#xff09; 2、端口配置高寄存器&#xff08;GPIOx_CRH&#xff09;&#xff08;xA...E&#xff09; 3、端口输入数据寄存器&#xff…

CSS基础也要进行模电实验

盒子阴影 圆角边框已经介绍过哩&#xff0c;现在先介绍一下盒子阴影的效果如何实现 CSS3中新增了盒子阴影&#xff0c;可以使用box-shadow属性为盒子添加阴影 这是固定的语法&#xff1a; text-shadow: h-shadow v-shadow blur color; 它有这些可选的值&#xff1a; 哦。 …

i春秋-登陆(sql盲注爆字段,.git缓存利用)

练习平台地址 竞赛中心 题目描述 先登陆再说 题目内容 就是一个登录框 测试登录 用户名&#xff1a;admin or 11# 密码&#xff1a;随便输 返回密码错误 用户名&#xff1a;随便输 密码&#xff1a;随便输 返回用户名不存在 这里就可以确定时一个bool盲注了 这里提供一个lik…

探索KubeVirt:如何利用InfiniBand提升虚拟机性能

在高性能计算&#xff08;HPC&#xff09;中&#xff0c;网络性能对于集群效率起着至关重要的作用。为了支持大规模并行计算&#xff0c;HPC集群通常依赖高带宽、低延迟的网络&#xff0c;而InfiniBand&#xff08;IB&#xff09;正是其中的首选技术。它能够提供超过100Gbps的带…

基于树莓派的边缘端 AI 目标检测、目标跟踪、姿态估计 视频分析推理 加速方案:Hailo with ultralytics YOLOv8 YOLOv11

文件大纲 加速原理硬件安装软件安装基本设置系统升级docker 方案Demo 测试目标检测姿态估计视频分析参考文献前序树莓派文章hailo加速原理 Hailo 发布的 Raspberry Pi AI kit 加速原理,有几篇文章介绍的不错 https://ubuntu.com/blog/hackers-guide-to-the-raspberry-pi-ai-ki…

小白进!QMK 键盘新手入门指南

经常玩键盘的伙伴应该都知道&#xff0c;现在的键盘市场可谓是百花齐放&#xff0c;已经不是之前的单一功能产品化时代。我们可以看到很多诸如&#xff1a;机械轴键盘、磁轴键盘、光轴键盘、电感轴键盘&#xff0c;以及可能会上市的光磁轴键盘&#xff0c;更有支持屏幕的、带旋…

《操作系统 - 清华大学》3 -3:连续内存分配:内存碎片与分区的动态分配

文章目录 0. 概述1. 内存碎片问题2. 动态分配3. 首次适配算法4. 最优适配算法5. 最差适配算法 0. 概述 内存分配是操作系统管理过程中很重要的环节&#xff0c;首先需要考虑的是一块连续区域分配的过程&#xff0c;这个过程中会有很多问题&#xff0c;首先比较关注的一个问题是…

vue内置指令和自定义指令

常见的指令&#xff1a; v-bind : 单向绑定解析表达式, 可简写为 :xxx v-model : 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on : 绑定事件监听, 可简…

蓝桥杯备赛(持续更新)

16届蓝桥杯算法类知识图谱.pdf 1. 格式打印 %03d&#xff1a;如果是两位数&#xff0c;将会在前面添上一位0 %.2f&#xff1a;会保留两位小数 如果是long&#xff0c;必须在数字后面加上L。 2. 进制转化 2.1. 十进制转任意进制&#xff1a; 十进制转任意进制时&#xff…

vue 项目使用 nginx 部署

前言 记录下使用element-admin-template 改造项目踩过的坑及打包部署过程 一、根据权限增加动态路由不生效 原因是Sidebar中路由取的 this.$router.options.routes,需要在计算路由 permission.js 增加如下代码 // generate accessible routes map based on roles const acce…

TensorFlow 2.0 环境配置

官方文档&#xff1a;CUDA Installation Guide for Windows 官方文档有坑&#xff0c;windows的安装指南直接复制了linux的指南内容&#xff1a;忽略这些离谱的信息即可。 可以从官方文档知悉&#xff0c;cuda依赖特定版本的C编译器。但是我懒得为了一个编译器就下载整个visua…