Java通過(guò)百度地圖API獲取定位(普通IP定位)的方法教程
項(xiàng)目中有一個(gè)登錄郵箱提醒的功能,需要根據(jù)IP地址獲取定位信息,從而更好地提示用戶賬號(hào)登錄的所在地。為此,花費(fèi)了一些時(shí)間來(lái)實(shí)現(xiàn)這個(gè)功能。
搜索了一下,發(fā)現(xiàn)關(guān)于獲取定位的文章說(shuō)明都不夠詳細(xì),于是決定自己創(chuàng)作一篇文章,希望能夠幫助到有需求的小伙伴~
因?yàn)椴┲魅粘I钪杏玫膶?dǎo)航APP就是百度地圖,所以使用百度地圖的API來(lái)實(shí)現(xiàn)這個(gè)功能。
百度地圖開(kāi)放平臺(tái)
本篇文章都是圍繞百度地圖的開(kāi)放平臺(tái)官網(wǎng)的相關(guān)說(shuō)明來(lái)展開(kāi)的,訪問(wèn)下面的鏈接
百度地圖開(kāi)放平臺(tái) | 百度地圖API SDK | 地圖開(kāi)發(fā) 這是開(kāi)放平臺(tái)的首頁(yè)截圖

開(kāi)始前的準(zhǔn)備工作
點(diǎn)擊上方導(dǎo)航菜單的開(kāi)發(fā)文檔-Web服務(wù)API總覽

緊接著,點(diǎn)擊左側(cè)菜單中的定位,點(diǎn)擊普通IP定位

然后根據(jù)開(kāi)發(fā)文檔的提示完成步驟1、2、3

學(xué)習(xí)官網(wǎng)API文檔
最后點(diǎn)擊步驟4,開(kāi)始使用百度地圖的API

如上圖,文檔已經(jīng)給出了API的接口地址和參數(shù)說(shuō)明,以及API接口返回的參數(shù)格式。
{
"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配置
在這里,需要修改一下創(chuàng)建的應(yīng)用的相關(guān)設(shè)置。

點(diǎn)擊上圖的設(shè)置按鈕來(lái)到這個(gè)頁(yè)面,然后拉到頁(yè)面的底部,修改應(yīng)用的請(qǐng)求校驗(yàn)方式為sn校驗(yàn)方式,然后點(diǎn)擊提交按鈕。

把AK復(fù)制到示例代碼的輸入框中,點(diǎn)擊確認(rèn)按鈕自動(dòng)生成獲取定位的Java代碼,可以說(shuō)非常方便。

Java代碼獲取定位
通過(guò)官網(wǎng)生成代碼
新建一個(gè)類SearchHttpAK,把示例代碼復(fù)制到SearchHttpAK類里,復(fù)制按鈕在下圖紅框內(nèi)。

調(diào)整之后的代碼如下(真實(shí)的AK和SK都已經(jīng)被博主替換了,這里的5個(gè)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校驗(yàn):
* @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校驗(yàn):
* 根據(jù)您選擇的AK已為您生成調(diào)用代碼
* 檢測(cè)您當(dāng)前的AK設(shè)置了sn檢驗(yàn),本示例中已為您生成sn計(jì)算代碼
* @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 自帶的轉(zhuǎn)碼方式 第二種方式使用的 spring 的轉(zhuǎn)碼方法 兩種均可
// 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();
// 計(jì)算sn跟參數(shù)對(duì)出現(xiàn)順序有關(guān),get請(qǐng)求請(qǐng)使用LinkedHashMap保存<key,value>,該方法根據(jù)key的插入順序排序;post請(qǐng)使用TreeMap保存<key,value>,該方法會(huì)自動(dòng)將key按照字母a-z順序排序。
// 所以get請(qǐng)求可自定義參數(shù)順序(sn參數(shù)必須在最后)發(fā)送請(qǐng)求,但是post請(qǐng)求必須按照字母a-z順序填充body(sn參數(shù)必須在最后)。
// 以get請(qǐng)求為例:http://api.map.baidu.com/geocoder/v2/?address=百度大廈&output=json&ak=yourak,paramsMap中先放入address,再放output,然后放ak,放入順序必須跟get請(qǐng)求中對(duì)應(yīng)參數(shù)的出現(xiàn)順序保持一致。
Map<String, String> paramsMap = new LinkedHashMap<>(3);
paramsMap.put("ip", "111.206.214.37");
paramsMap.put("coor", "bd09ll");
paramsMap.put("ak", AK);
// 調(diào)用下面的toQueryString方法,對(duì)LinkedHashMap內(nèi)所有value作utf8編碼,拼接返回結(jié)果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
String paramsStr = snCal.toQueryString(paramsMap);
// 對(duì)paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
String wholeStr = new String("/location/ip?" + paramsStr + SK);
System.out.println(wholeStr);
// 對(duì)上面wholeStr再作utf8編碼
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
// 調(diào)用下面的MD5方法得到最后的sn簽名
String sn = snCal.MD5(tempStr);
System.out.println(sn);
return sn;
}
// 對(duì)Map內(nèi)所有value作utf8編碼,拼接返回結(jié)果
public String toQueryString(Map<?, ?> data) {
StringBuilder queryString = new StringBuilder();
for (Map.Entry<?, ?> pair : data.entrySet()) {
queryString.append(pair.getKey()).append("=");
// 第一種方式使用的 jdk 自帶的轉(zhuǎn)碼方式 第二種方式使用的 spring 的轉(zhuǎn)碼方法 兩種均可
// 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();
}
// 來(lái)自stackoverflow的MD5計(jì)算方法,調(diào)用了MessageDigest庫(kù)函數(shù),并把byte數(shù)組結(jié)果轉(zhuǎn)換成16進(jìn)制
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的放入順序,否則請(qǐng)求接口會(huì)報(bào)錯(cuò)~
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());運(yùn)行生成的代碼
然后運(yùn)行一下代碼,如果能看到下面這樣的運(yùn)行結(jié)果,恭喜你,你已經(jīng)成功了一大半~

不要糾結(jié)獲取到的位置信息里很多16進(jìn)制,因?yàn)轳R上就要把他轉(zhuǎn)成一個(gè)自定義的實(shí)體類
創(chuàng)建接口返回對(duì)象
根據(jù)這個(gè)API返回的JSON格式字符串的結(jié)構(gòu),創(chuàng)建4個(gè)對(duì)應(yīng)的實(shí)體類
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字符串轉(zhuǎn)成Location對(duì)象
修改一下部分方法的名稱,然后把字符串通過(guò)fastjson的API轉(zhuǎn)成Location對(duì)象
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校驗(yàn):
* @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校驗(yàn):
* 根據(jù)您選擇的AK已為您生成調(diào)用代碼
* 檢測(cè)您當(dāng)前的AK設(shè)置了sn檢驗(yàn),本示例中已為您生成sn計(jì)算代碼
* @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 自帶的轉(zhuǎn)碼方式 第二種方式使用的 spring 的轉(zhuǎn)碼方法 兩種均可
// 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 {
// 計(jì)算sn跟參數(shù)對(duì)出現(xiàn)順序有關(guān),get請(qǐng)求請(qǐng)使用LinkedHashMap保存<key,value>,該方法根據(jù)key的插入順序排序;post請(qǐng)使用TreeMap保存<key,value>,該方法會(huì)自動(dòng)將key按照字母a-z順序排序。
// 所以get請(qǐng)求可自定義參數(shù)順序(sn參數(shù)必須在最后)發(fā)送請(qǐng)求,但是post請(qǐng)求必須按照字母a-z順序填充body(sn參數(shù)必須在最后)。
// 以get請(qǐng)求為例:http://api.map.baidu.com/geocoder/v2/?address=百度大廈&output=json&ak=yourak,paramsMap中先放入address,再放output,然后放ak,放入順序必須跟get請(qǐng)求中對(duì)應(yīng)參數(shù)的出現(xiàn)順序保持一致。
Map<String, String> paramsMap = new LinkedHashMap<>(3);
paramsMap.put("ip", "111.206.214.37");
paramsMap.put("coor", "bd09ll");
paramsMap.put("ak", AK);
// 調(diào)用下面的toQueryString方法,對(duì)LinkedHashMap內(nèi)所有value作utf8編碼,拼接返回結(jié)果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
String paramsStr = toQueryString(paramsMap);
// 對(duì)paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
String wholeStr = new String("/location/ip?" + paramsStr + SK);
System.out.println(wholeStr);
// 對(duì)上面wholeStr再作utf8編碼
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
// 調(diào)用下面的MD5方法得到最后的sn簽名
return MD5(tempStr);
}
// 對(duì)Map內(nèi)所有value作utf8編碼,拼接返回結(jié)果
public static String toQueryString(Map<?, ?> data) {
StringBuilder queryString = new StringBuilder();
for (Map.Entry<?, ?> pair : data.entrySet()) {
queryString.append(pair.getKey()).append("=");
// 第一種方式使用的 jdk 自帶的轉(zhuǎn)碼方式 第二種方式使用的 spring 的轉(zhuǎn)碼方法 兩種均可
// 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();
}
// 來(lái)自stackoverflow的MD5計(jì)算方法,調(diào)用了MessageDigest庫(kù)函數(shù),并把byte數(shù)組結(jié)果轉(zhuǎn)換成16進(jìn)制
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;
}
}運(yùn)行代碼,效果如下:

在使用的時(shí)候,只需要傳入IP地址即可獲取到定位信息~
代碼的最后優(yōu)化
上面的代碼已經(jīng)是進(jìn)行了一定的優(yōu)化,除此之外,可以把AK和SK配置到application.yml中,可以動(dòng)態(tài)地修改。最后重命名一下這個(gè)類,改成類似LocationUtils這樣的名字。
總結(jié)
到此這篇關(guān)于Java通過(guò)百度地圖API獲取定位(普通IP定位)的文章就介紹到這了,更多相關(guān)Java百度地圖API獲取定位內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringSecurity+Mysql數(shù)據(jù)庫(kù)實(shí)現(xiàn)用戶安全登錄認(rèn)證的實(shí)踐
Spring Security 是一個(gè)提供身份認(rèn)證、授權(quán)和防范常見(jiàn)攻擊的安全權(quán)限框架,本文主要介紹了SpringSecurity+Mysql數(shù)據(jù)庫(kù)實(shí)現(xiàn)用戶安全登錄認(rèn)證的實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-08-08
Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP軟件主界面(4)
這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件,F(xiàn)TP軟件主界面編寫(xiě)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
在springboot文件中如何創(chuàng)建mapper.xml文件
這篇文章主要介紹了在springboot文件中如何創(chuàng)建mapper.xml文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Spring Security與SaToken的對(duì)比與優(yōu)缺點(diǎn)分析
這篇文章主要介紹了Spring Security與SaToken的對(duì)比與優(yōu)缺點(diǎn)分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-05-05
elasticsearch如何根據(jù)條件刪除數(shù)據(jù)
Elasticsearch是一個(gè)基于Apache Lucene?的開(kāi)源搜索引擎,無(wú)論在開(kāi)源還是專有領(lǐng)域,Lucene 可以被認(rèn)為是迄今為止最先進(jìn)、性能最好的、功能最全的搜索引擎庫(kù),這篇文章主要介紹了elasticsearch如何根據(jù)條件刪除數(shù)據(jù),需要的朋友可以參考下2023-03-03
spring boot org.junit.jupiter.api不存在的解決
這篇文章主要介紹了spring boot org.junit.jupiter.api不存在的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
使用Java實(shí)現(xiàn)將多聲道音頻轉(zhuǎn)換為單聲道文件的轉(zhuǎn)換方案
在音頻處理領(lǐng)域,開(kāi)發(fā)者經(jīng)常需要對(duì)錄音文件進(jìn)行聲道數(shù)調(diào)整,例如從雙聲道轉(zhuǎn)換為單聲道,以便減小文件體積、適配語(yǔ)音識(shí)別模型或統(tǒng)一音頻輸入格式,許多項(xiàng)目會(huì)直接依賴FFmpeg,但這會(huì)引入外部依賴、部署復(fù)雜性和跨平臺(tái)兼容問(wèn)題,本文將介紹一種 純Java實(shí)現(xiàn)的音頻聲道轉(zhuǎn)換方案2025-11-11
idea中將單個(gè)java類導(dǎo)出為jar包文件的方法
這篇文章主要給大家介紹了關(guān)于idea中將單個(gè)java類導(dǎo)出為jar包文件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
Java(springboot) 讀取txt文本內(nèi)容代碼實(shí)例
這篇文章主要介紹了Java(springboot) 讀取txt文本內(nèi)容代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

