Java通过百度地图API获取定位-普通IP定位
项目中有一个登录邮箱提醒的功能,需要根据IP地址获取定位信息,从而更好地提示用户账号登录的所在地。为此,花费了一些时间来实现这个功能。
在CSDN搜索了一下,发现关于获取定位的文章说明都不够详细,于是决定自己创作一篇文章,希望能够帮助到有需求的小伙伴~
因为博主日常生活中用的导航APP就是百度地图,所以使用百度地图的API来实现这个功能。
目录
百度地图开放平台
开始前的准备工作
学习官网API文档
修改API的AK配置
Java代码获取定位
通过官网生成代码
运行生成的代码
创建接口返回对象
Point.java
Location.java
Content.java
AddressDetail.java
将JSON字符串转成Location对象
代码的最后优化
百度地图开放平台
本篇文章都是围绕百度地图的开放平台官网的相关说明来展开的,访问下面的链接
百度地图开放平台 | 百度地图API SDK | 地图开发https://lbsyun.baidu.com/index.php?title=%E9%A6%96%E9%A1%B5这是开放平台的首页截图
开始前的准备工作
点击上方导航菜单的开发文档-Web服务API总览
紧接着,点击左侧菜单中的定位,点击普通IP定位
然后根据开发文档的提示完成步骤1、2、3
学习官网API文档
最后点击步骤4,开始使用百度地图的API
如上图,文档已经给出了API的接口地址和参数说明,以及API接口返回的参数格式。
{"address": "CN|北京市|北京市|None|None|100|91","content": {"address": "北京市","address_detail": {"adcode": "110000","city": "北京市","city_code": 131,"district": "","province": "北京市","street": "","street_number": ""},"point": {"x": "116.41338370","y": "39.91092455"}},"status": 0
}
修改API的AK配置
在这里,需要修改一下创建的应用的相关设置。
点击上图的设置按钮来到这个页面,然后拉到页面的底部,修改应用的请求校验方式为sn校验方式,然后点击提交按钮。
把AK复制到示例代码的输入框中,点击确认按钮自动生成获取定位的Java代码,可以说非常方便。
Java代码获取定位
通过官网生成代码
新建一个类SearchHttpAK,把示例代码复制到SearchHttpAK类里,复制按钮在下图红框内。
调整之后的代码如下(真实的AK和SK都已经被博主替换了,这里的5个x改成自己的AK和SK就行了)。
package cn.edu.sgu.www.authority.util;import org.springframework.web.util.UriUtils;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;/*** 选择AK使用SN校验:* @author heyunlin* @version 1.0*/
public class SearchHttpSN {public static String AK = "xxxxx";public static String SK = "xxxxx";public static String URL = "https://api.map.baidu.com/location/ip?";public static void main(String[] args) throws Exception {SearchHttpSN snCal = new SearchHttpSN();Map<String, String> params = new LinkedHashMap<>(4);params.put("ip", "111.206.214.37");params.put("coor", "bd09ll");params.put("ak", AK);params.put("sn", snCal.caculateSn());snCal.requestGetSN(URL, params);}/*** 选择了ak,使用SN校验:* 根据您选择的AK已为您生成调用代码* 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码* @param strUrl* @param param* @throws Exception*/public void requestGetSN(String strUrl, Map<String, String> param) throws Exception {if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {return;}StringBuilder queryString = new StringBuilder();queryString.append(strUrl);for (Map.Entry<?, ?> pair : param.entrySet()) {queryString.append(pair.getKey()).append("=");// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");}if (queryString.length() > 0) {queryString.deleteCharAt(queryString.length() - 1);}java.net.URL url = new URL(queryString.toString());System.out.println(queryString.toString());URLConnection httpConnection = (HttpURLConnection) url.openConnection();httpConnection.connect();InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());BufferedReader reader = new BufferedReader(isr);StringBuilder buffer = new StringBuilder();String line;while ((line = reader.readLine()) != null) {buffer.append(line);}reader.close();isr.close();System.out.println("SN: " + buffer);}public String caculateSn() throws UnsupportedEncodingException,NoSuchAlgorithmException {SearchHttpSN snCal = new SearchHttpSN();// 计算sn跟参数对出现顺序有关,get请求请使用LinkedHashMap保存<key,value>,该方法根据key的插入顺序排序;post请使用TreeMap保存<key,value>,该方法会自动将key按照字母a-z顺序排序。// 所以get请求可自定义参数顺序(sn参数必须在最后)发送请求,但是post请求必须按照字母a-z顺序填充body(sn参数必须在最后)。// 以get请求为例:http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak,paramsMap中先放入address,再放output,然后放ak,放入顺序必须跟get请求中对应参数的出现顺序保持一致。Map<String, String> paramsMap = new LinkedHashMap<>(3);paramsMap.put("ip", "111.206.214.37");paramsMap.put("coor", "bd09ll");paramsMap.put("ak", AK);// 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakString paramsStr = snCal.toQueryString(paramsMap);// 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyourskString wholeStr = new String("/location/ip?" + paramsStr + SK);System.out.println(wholeStr);// 对上面wholeStr再作utf8编码String tempStr = URLEncoder.encode(wholeStr, "UTF-8");// 调用下面的MD5方法得到最后的sn签名String sn = snCal.MD5(tempStr);System.out.println(sn);return sn;}// 对Map内所有value作utf8编码,拼接返回结果public String toQueryString(Map<?, ?> data) {StringBuilder queryString = new StringBuilder();for (Map.Entry<?, ?> pair : data.entrySet()) {queryString.append(pair.getKey()).append("=");// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");}if (queryString.length() > 0) {queryString.deleteCharAt(queryString.length() - 1);}return queryString.toString();}// 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制public String MD5(String md5) {try {java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");byte[] array = md.digest(md5.getBytes());StringBuilder sb = new StringBuilder();for (byte b : array) {sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);}return sb.toString();} catch (java.security.NoSuchAlgorithmException ignored) { }return null;}
}
注意,不要修改这里的map的放入顺序,否则请求接口会报错~
Map<String, String> params = new LinkedHashMap<>(4);params.put("ip", "111.206.214.37");
params.put("coor", "bd09ll");
params.put("ak", AK);params.put("sn", snCal.caculateSn());
运行生成的代码
然后运行一下代码,如果能看到下面这样的运行结果,恭喜你,你已经成功了一大半~
不要纠结获取到的位置信息里很多16进制,因为马上就要把他转成一个自定义的实体类
创建接口返回对象
根据这个API返回的JSON格式字符串的结构,创建4个对应的实体类
Point.java
import lombok.Data;/*** @author heyunlin* @version 1.0*/
@Data
public class Point {private String x;private String y;
}
Location.java
import lombok.Data;/*** @author heyunlin* @version 1.0*/
@Data
public class Location {private Integer status;private String address;private Content content;
}
Content.java
import lombok.Data;/*** @author heyunlin* @version 1.0*/
@Data
public class Content {private Point point;private String address;private AddressDetail address_detail;
}
AddressDetail.java
import lombok.Data;/*** @author heyunlin* @version 1.0*/
@Data
public class AddressDetail {private String adcode;private String city;private String city_code;private String province;private String district;private String street;private String street_number;
}
将JSON字符串转成Location对象
修改一下部分方法的名称,然后把字符串通过fastjson的API转成Location对象
package cn.edu.sgu.www.authority.util;import cn.edu.sgu.www.authority.location.Location;
import com.alibaba.fastjson.JSON;
import org.springframework.web.util.UriUtils;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;/*** 选择AK使用SN校验:* @author heyunlin* @version 1.0*/
public class SearchHttpSN {public static String AK = "xxxxx";public static String SK = "xxxxx";public static String URL = "https://api.map.baidu.com/location/ip?";public static void main(String[] args) throws Exception {String ip = "111.206.214.37";String location = getLocation(ip);System.out.println(JSON.parseObject(location, Location.class));}public static String getLocation(String ip) throws Exception {Map<String, String> params = new LinkedHashMap<>(4);params.put("ip", ip);params.put("coor", "bd09ll");params.put("ak", AK);params.put("sn", caculateSn());return getLocation(URL, params);}/*** 选择了ak,使用SN校验:* 根据您选择的AK已为您生成调用代码* 检测您当前的AK设置了sn检验,本示例中已为您生成sn计算代码* @param strUrl* @param param* @throws Exception*/public static String getLocation(String strUrl, Map<String, String> param) throws Exception {if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {return null;}StringBuilder queryString = new StringBuilder();queryString.append(strUrl);for (Map.Entry<?, ?> pair : param.entrySet()) {queryString.append(pair.getKey()).append("=");// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");}if (queryString.length() > 0) {queryString.deleteCharAt(queryString.length() - 1);}java.net.URL url = new URL(queryString.toString());System.out.println(queryString);URLConnection httpConnection = url.openConnection();httpConnection.connect();InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());BufferedReader reader = new BufferedReader(isr);StringBuilder sb = new StringBuilder();String line;while ((line = reader.readLine()) != null) {sb.append(line);}reader.close();isr.close();return sb.toString();}public static String caculateSn() throws UnsupportedEncodingException {// 计算sn跟参数对出现顺序有关,get请求请使用LinkedHashMap保存<key,value>,该方法根据key的插入顺序排序;post请使用TreeMap保存<key,value>,该方法会自动将key按照字母a-z顺序排序。// 所以get请求可自定义参数顺序(sn参数必须在最后)发送请求,但是post请求必须按照字母a-z顺序填充body(sn参数必须在最后)。// 以get请求为例:http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak,paramsMap中先放入address,再放output,然后放ak,放入顺序必须跟get请求中对应参数的出现顺序保持一致。Map<String, String> paramsMap = new LinkedHashMap<>(3);paramsMap.put("ip", "111.206.214.37");paramsMap.put("coor", "bd09ll");paramsMap.put("ak", AK);// 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakString paramsStr = toQueryString(paramsMap);// 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyourskString wholeStr = new String("/location/ip?" + paramsStr + SK);System.out.println(wholeStr);// 对上面wholeStr再作utf8编码String tempStr = URLEncoder.encode(wholeStr, "UTF-8");// 调用下面的MD5方法得到最后的sn签名return MD5(tempStr);}// 对Map内所有value作utf8编码,拼接返回结果public static String toQueryString(Map<?, ?> data) {StringBuilder queryString = new StringBuilder();for (Map.Entry<?, ?> pair : data.entrySet()) {queryString.append(pair.getKey()).append("=");// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可// queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8")).append("&");}if (queryString.length() > 0) {queryString.deleteCharAt(queryString.length() - 1);}return queryString.toString();}// 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制public static String MD5(String md5) {try {java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");byte[] array = md.digest(md5.getBytes());StringBuilder sb = new StringBuilder();for (byte b : array) {sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);}return sb.toString();} catch (java.security.NoSuchAlgorithmException ignored) { }return null;}}
运行代码,效果如下:
在使用的时候,只需要传入IP地址即可获取到定位信息~
代码的最后优化
上面的代码已经是进行了一定的优化,除此之外,可以把AK和SK配置到application.yml中,可以动态地修改。最后重命名一下这个类,改成类似LocationUtils这样的名字。
好了,文章就分享到这里了,看完如果觉得对你有所帮助,不要忘了点赞+收藏哦~
相关文章:

Java通过百度地图API获取定位-普通IP定位
项目中有一个登录邮箱提醒的功能,需要根据IP地址获取定位信息,从而更好地提示用户账号登录的所在地。为此,花费了一些时间来实现这个功能。 在CSDN搜索了一下,发现关于获取定位的文章说明都不够详细,于是决定自己创作一…...

5月13号作业
使用消息队列实现的2个终端之间的互相聊天 并使用信号控制消息队列的读取方式: 当键盘按ctrlc的时候,切换消息读取方式,一般情况为读取指定编号的消息,按ctrlc之后,指定的编号不读取,读取其他所有编号的消息…...

【计算机网络】Socket网络编程
💻文章目录 📄前言Socket编程基础概念工作原理 Socket API介绍socket函数绑定、监听函数accept、connect接受/发送函数 Socket API的应用Socket类与其派生类的设计服务器与客户端的设计使用 📓总结 📄前言 现今我们的日常生活当中…...

Ansible自动运维工具之playbook
目录 一.inventory主机清单 1.定义 2.变量 (1)主机变量 (2)组变量 (3)组嵌套 二.playbook基本内容 1.组成 (1)Tasks: 任务,即调用模块完成的某操作 ࿰…...

【启明智显技术分享】SSD201/SSD202D核心板UI界面开发全攻略:LVGL使用指南
提示:作为Espressif(乐鑫科技)大中华区合作伙伴及sigmastar(厦门星宸)VAD合作伙伴,我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考。同时也用心整理了乐鑫及星宸…...

数据可视化(九):Pandas北京租房数据分析——房源特征绘图、箱线图、动态可视化等高级操作
Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊! 喜欢我的博客的话,记得…...

ADOP带你了解:跳线与交叉电缆有何不同?
如果您想将设备连接到互联网,您可能想知道要使用的正确电缆。跳线和交叉电缆都是类型的以太网电缆,可帮助连接计算机、调制解调器、路由器和交换机等设备。那么,跳线和交叉电缆有什么区别呢?让我们讨论这两种类型的电缆࿰…...
Django 和 Spring Boot
标题 Django (Python)Django提供的组件Django 的处理逻辑 Spring Boot (Java)Spring Boot 的特点Spring Boot 的处理逻辑 MVC设计模式模型(Model)视图(View)控制器(Controller)逻辑处理过程 Django 和 Spri…...

上位机图像处理和嵌入式模块部署(树莓派4b的替代品)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 实话实说,树莓派4b的产品力还是比较优秀的,价格还算适中。但是和国产卡片电脑比起来,则逊色不少。功能差不多的…...

Springboot整合 Spring Cloud Gateway
1.Gateway介绍 1.是spring cloud官方推出的响应式的API网关框架,旨在为微服务架构提供一种简单有效的API路由的管理方式,并基于Filter的方式提供网关的基本功能,例如:安全认证,监控,限流等等。 2.功能特征…...

Rust开发工具有哪些?
目录 一、JetBrains公司的RustRover编辑 二、微软公司的Visual Studio Code 三、Rust编译工具 一、JetBrains公司的RustRover RustRover是由JetBrains开发的一款专为Rust开发量身定制的新兴IDE,目前还处于早期访问阶段。它支持Rust、Cargo、TOML、Web和数据库等…...

20240514基于深度学习的弹性超材料色散关系预测与结构逆设计
论文:Dispersion relation prediction and structure inverse design of elastic metamaterials via deep learning DOI:https://doi.org/10.1016/j.mtphys.2022.100616 1、摘要 精心设计的超材料结构给予前所未有的性能,保证了各种各样的具…...

SAP:FI 财务凭证行项目文本前台修改
一、问题描述 财务凭证行项目文本点击修改,但是前台有的行可以修改,有的行是灰色的不能修改,如下图所示,这个文本信息有误,必须修改怎么办? 二、思路分析 有的行可以修改,有的行不能修改&#x…...

【linux系统学习教程 Day02】网络安全之Linux系统学习教程,管道,文件内容统计,过滤排序,去重,目录介绍
1-4 管道 管道符号: | ,可以将前面指令的执行结果,作为后面指令的操作内容。 ## 比如过滤ip地址 ip addr | tail -4 | head -1 解释一下就是先执行 ip addr ,得到的结果当做 tail -4 的输入,意思就是查看ip addr 结果的后四行内容…...
Spring Cloud LoadBalancer 4.1.2
LoadBalancer位于Spring Cloud Commons 模块 Spring Cloud 提供了自己的客户端负载均衡器抽象和实现。对于负载均衡机制,添加了 ReactiveLoadBalancer 接口,并为其提供了基于Round-Robin和Random的实现。为了让实例从反应式中进行选择,使用了…...

使用Xshell工具连接ubuntu-方便快捷
使用Xshell连接ubuntu 在命令行输入 “sudo apt-get install openssh-server”安装openssh-server 开启 ssh-server,在命令行输入 “service ssh start”,然后输入密码即可...
leetcode22 括号生成-组合型回溯
题目 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 输入:n 3 输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 解析 func generateParenthesis(n int) …...

mac定时任务、自启动任务
https://quail.ink/mynotes/p/mac-startup-configuration-detailed-explanation <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.d…...

重磅 | 国家标准《网络安全技术 零信任参考体系架构》正式发布
根据2024年4月25日国家市场监督管理总局、国家标准化管理委员会发布的中华人民共和国国家标准公告(2024年第6号),其中易安联参编的国家标准GB/T 43696-2024《网络安全技术 零信任参考体系架构》正式发布,并于2024年11月1日正式施行…...

【C++】可变参数模板简单介绍
前言 可变参数模板是C11中的新特性,它能够让我们创建可以接收可变参数的函数模板和类模板,相比C98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数是一个巨大的改进,通过系统系统推演数据的类型…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...