Springboot利于第三方服務(wù)進(jìn)行ip定位獲取省份城市
在web應(yīng)用的開發(fā)中,我們或許會(huì)想知道我們的用戶請求的來源分布情況。本文基于springboot框架,調(diào)用百度地圖、高德地圖的開放平臺api,在線對對請求來源的ip進(jìn)行定位、解析,獲取目標(biāo)ip所對應(yīng)的省份、城市、經(jīng)緯度等信息,方便開發(fā)者將相關(guān)數(shù)據(jù)記錄在操作日志中。
一. 共用部分
統(tǒng)一響應(yīng)類
/**
* @author 擺渡人
* @description 統(tǒng)一響應(yīng)類
* @date 2023/7/13 23:26
*/
@Data
@Builder
public class IpAnalyzeResponse {
/**
* 狀態(tài)碼
*/
private String status;
/**
* 是否成功
*/
private Boolean successFlag;
/**
* 失敗原因
*/
private String msg;
/**
* 省份名稱
*/
private String province;
/**
* 城市名稱
*/
private String city;
/**
* 經(jīng)度
*/
private Double x;
/**
* 維度
*/
private Double y;
}定義接口
實(shí)現(xiàn)該接口,并在配置類中注入接口的實(shí)現(xiàn)類,即可拓展ip定位的更多實(shí)現(xiàn)方式
/**
* @author 擺渡人
* @description ip定位接口
* @date 2023/7/13 23:25
*/
public interface IPlatFormIpAnalyzeService {
/**
* ip定位解析
* @param ip
* @return
*/
IpAnalyzeResponse ipAnalyze(String ip);
}http請求工具類(用于發(fā)送http請求)
源碼來自SmartAdmin
/**
* [ HttpUtils ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2019 1024lab.netInc. All rights reserved.
* @date
* @since JDK1.8
*/
public class SmartHttpUtil {
public static String sendGet(String url, Map<String, String> params, Map<String, String> header) throws Exception {
HttpGet httpGet = null;
String body = "";
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
List<String> mapList = new ArrayList<>();
if (params != null) {
for (Entry<String, String> entry : params.entrySet()) {
mapList.add(entry.getKey() + "=" + entry.getValue());
}
}
if (CollectionUtils.isNotEmpty(mapList)) {
url = url + "?";
String paramsStr = StringUtils.join(mapList, "&");
url = url + paramsStr;
}
httpGet = new HttpGet(url);
httpGet.setHeader("Content-type", "application/json; charset=utf-8");
httpGet.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
if (header != null) {
for (Entry<String, String> entry : header.entrySet()) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
}
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new RuntimeException("請求失敗");
} else {
body = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
throw e;
} finally {
if (httpGet != null) {
httpGet.releaseConnection();
}
}
return body;
}
public static String sendPostJson(String url, String json, Map<String, String> header) throws Exception {
HttpPost httpPost = null;
String body = "";
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
httpPost = new HttpPost(url);
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
if (header != null) {
for (Entry<String, String> entry : header.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
StringEntity entity = new StringEntity(json, Charset.forName("UTF-8"));
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new RuntimeException("請求失敗");
} else {
body = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
throw e;
} finally {
if (httpPost != null) {
httpPost.releaseConnection();
}
}
return body;
}
public static String sendPostForm(String url, Map<String, String> params, Map<String, String> header) throws Exception {
HttpPost httpPost = null;
String body = "";
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
httpPost = new HttpPost(url);
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
if (header != null) {
for (Entry<String, String> entry : header.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
List<NameValuePair> nvps = new ArrayList<>();
if (params != null) {
for (Entry<String, String> entry : params.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
//設(shè)置參數(shù)到請求對象中
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
HttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new RuntimeException("請求失敗");
} else {
body = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
throw e;
} finally {
if (httpPost != null) {
httpPost.releaseConnection();
}
}
return body;
}
}二.百度地圖開放平臺實(shí)現(xiàn)
1. 使用準(zhǔn)備
閱讀文檔普通IP定位 | 百度地圖API SDK (baidu.com),成為開發(fā)者,獲取服務(wù)密鑰(AK)
2. 封裝實(shí)體類
/**
* @author 擺渡人
* @description 地址解析的結(jié)果
* @date 2023/7/10 20:29
*/
@Data
public class IpAnalyzeBaiduResponse implements Serializable {
/**
* 返回狀態(tài)碼
*/
private Integer status;
/**
* 錯(cuò)誤信息
*/
private String message;
/**
* 地址
*/
private String address;
/**
* 詳細(xì)內(nèi)容
*/
private IpAnalyzeContent content;
}/**
* @author 擺渡人
* @description 詳細(xì)內(nèi)容
* @date 2023/7/10 20:42
*/
@Data
public class IpAnalyzeContent implements Serializable {
/**
* 簡要地址
*/
private String address;
/**
* 詳細(xì)地址信息
*/
@JsonProperty("address_detail")
private IpAnalyzeAddressDetail addressDetail;
/**
* 百度經(jīng)緯度坐標(biāo)值
*/
@JsonProperty("point")
private IpAnalyzePoint point;
}/**
* @author 擺渡人
* @description 詳細(xì)地址信息
* @date 2023/7/10 20:41
*/
@Data
public class IpAnalyzeAddressDetail implements Serializable {
/**
* 城市
*/
private String city;
/**
* 百度城市代碼
*/
@JsonProperty("city_code")
private Integer cityCode;
/**
* 區(qū)縣
*/
private String district;
/**
* 省份
*/
private String province;
/**
* 街道
*/
private String street;
/**
* 門地址
*/
@JsonProperty("street_number")
private String streetNumber;
}/**
* @author 擺渡人
* @description 百度經(jīng)緯度坐標(biāo)值
* @date 2023/7/10 20:43
*/
@Data
public class IpAnalyzePoint implements Serializable {
private String x;
private String y;
}3.實(shí)現(xiàn)接口IPlatFormIpAnalyzeService
/**
* @author 擺渡人
* @description 百度地圖開發(fā)平臺實(shí)現(xiàn)類
* @date 2023/7/10 20:27
*/
@Slf4j
public class PlatformBaiduService implements IPlatFormIpAnalyzeService {
/**
* 響應(yīng)成功狀態(tài)碼
*/
private final Integer OK_CODE = 0;
@Value("${platform.conf.baidu.ak}")
public String ak;
@Override
public IpAnalyzeResponse ipAnalyze(String ip) {
String URL = "http://api.map.baidu.com/location/ip";
Map<String,String> params = new HashMap<>();
params.put("ip", ip);
params.put("ak", ak);
params.put("coor", "bd09ll");
try {
String json = SmartHttpUtil.sendGet(URL, params, null);
IpAnalyzeBaiduResponse response = JSONUtil.toBean(json, IpAnalyzeBaiduResponse.class);
if(OK_CODE.equals(response.getStatus())) {
return IpAnalyzeResponse.builder()
.status(response.getStatus() + "")
.successFlag(true)
.msg(response.getMessage())
.province(response.getContent().getAddressDetail().getProvince())
.city(response.getContent().getAddressDetail().getCity())
.x(Double.parseDouble(response.getContent().getPoint().getX()))
.y(Double.parseDouble(response.getContent().getPoint().getY()))
.build();
}
return IpAnalyzeResponse.builder()
.status(response.getStatus() + "")
.successFlag(false)
.msg(response.getMessage())
.build();
} catch (Exception e) {
return IpAnalyzeResponse.builder()
.status("500")
.successFlag(false)
.msg(e.getMessage())
.build();
}
}
}三.高德地圖開放平臺實(shí)現(xiàn)
1. 使用準(zhǔn)備
根據(jù)文檔獲取Key-創(chuàng)建工程-開發(fā)指南-Web服務(wù) API|高德地圖API (amap.com)指引獲取key
2. 封裝實(shí)體類
/**
* @author 擺渡人
* @description 高德地圖ip定位響應(yīng)類
* @date 2023/7/14 0:00
*/
@Data
public class IpAnalyzeGaodeResponse {
/**
* 返回結(jié)果狀態(tài)值,值為0或1,0表示失??;1表示成功
*/
private String status;
/**
* 返回狀態(tài)說明,status為0時(shí),info返回錯(cuò)誤原因,否則返回“OK
*/
private String info;
/**
* 返回狀態(tài)說明,10000代表正確,詳情參閱info狀態(tài)表
*/
private String infocode;
/**
* 若為直轄市則顯示直轄市名稱;
*
* 如果在局域網(wǎng) IP網(wǎng)段內(nèi),則返回“局域網(wǎng)”;
*
* 非法IP以及國外IP則返回空
*/
private String province;
/**
* 若為直轄市則顯示直轄市名稱;
*
* 如果為局域網(wǎng)網(wǎng)段內(nèi)IP或者非法IP或國外IP,則返回空
*/
private String city;
/**
* 城市的adcode編碼
*/
private String adcode;
/**
* 所在城市矩形區(qū)域范圍,所在城市范圍的左下右上對標(biāo)對,如:116.0119343,39.66127144;116.7829835,40.2164962
*/
private String rectangle;
}3.實(shí)現(xiàn)接口IPlatFormIpAnalyzeService
/**
* @author 擺渡人
* @description 高德地圖開放平臺ip定位實(shí)現(xiàn)類
* @date 2023/7/13 23:56
*/
@Slf4j
public class PlatformGaodeService implements IPlatFormIpAnalyzeService {
/**
* 響應(yīng)成功狀態(tài)碼
*/
private final String OK_CODE = "1";
@Value("${platform.conf.gaode.key}")
private String key;
@Override
public IpAnalyzeResponse ipAnalyze(String ip) {
String URL = "https://restapi.amap.com/v3/ip";
Map<String,String> params = new HashMap<>();
params.put("key",key);
params.put("ip",ip);
try {
String json = SmartHttpUtil.sendGet(URL, params, null);
IpAnalyzeGaodeResponse response = JSONUtil.toBean(json, IpAnalyzeGaodeResponse.class);
if(OK_CODE.equals(response.getStatus())) {
IpAnalyzeResponse ipAnalyzeResponse = IpAnalyzeResponse.builder()
.status(response.getInfocode())
.successFlag(true)
.msg(response.getInfo())
.province(response.getProvince())
.city(response.getCity())
.build();
// 對rectangle進(jìn)行解析
String rectangle = response.getRectangle();
String[] split = rectangle.split(";|,");
if(split.length == 1) {
ipAnalyzeResponse.setSuccessFlag(false);
ipAnalyzeResponse.setStatus("0");
ipAnalyzeResponse.setMsg("ip[" + ip + "]非法");
return ipAnalyzeResponse;
}
ipAnalyzeResponse.setX((Double.parseDouble(split[0]) + Double.parseDouble(split[2])) / 2.0);
ipAnalyzeResponse.setY((Double.parseDouble(split[1]) + Double.parseDouble(split[3])) / 2.0);
return ipAnalyzeResponse;
}
return IpAnalyzeResponse.builder()
.status(response.getInfocode())
.successFlag(false)
.msg(response.getInfo())
.build();
} catch (Exception e) {
e.printStackTrace();
return IpAnalyzeResponse.builder()
.status(“500”)
.successFlag(false)
.msg(e.getMessage())
.build();
}
}
}四. 使用
1.配置參數(shù)
# 第三方開放平臺的服務(wù)
platform:
# 目前支持百度[baidu] 高德[gaode]
mode: # 您選擇的服務(wù)
# 相關(guān)配置
conf:
# 百度
baidu:
ak: # 您的百度地圖開放平臺服務(wù)密鑰(AK)
# 高德
gaode:
key: # 您的高德地圖開放平臺key2.配置類
根據(jù)配置參數(shù)中platform.mode的值選擇接口IPlatFormIpAnalyzeService的一個(gè)服務(wù)類注入Spring容器中去
/**
* @author 擺渡人
* @description 接口實(shí)現(xiàn)類配置
* @date 2023/7/14 0:16
*/
@Configuration
public class PlatFormConfig {
@Bean
@ConditionalOnProperty(prefix = "platform",name = "mode",havingValue = "baidu")
public IPlatFormIpAnalyzeService initBaiduIpAnalyzeService() {
return new PlatformBaiduService();
}
@Bean
@ConditionalOnProperty(prefix = "platform",name = "mode",havingValue = "gaode")
public IPlatFormIpAnalyzeService initGaodeIpAnalyzeService() {
return new PlatformGaodeService();
}
}3.單元測試
/**
* @author 擺渡人
* @description
* @date 2023/7/14 0:23
*/
@Slf4j
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class PlatformTest {
@Autowired
private IPlatFormIpAnalyzeService platFormIpAnalyzeService;
@Test
public void testIpAnalyzeService() {
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze(null));
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze(""));
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze("127.0.0.1"));
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze("114.247.50.2"));
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze("219.137.148.0"));
log.info("解析結(jié)果:{}",platFormIpAnalyzeService.ipAnalyze("114.80.166.240"));
}
}運(yùn)行結(jié)果如下:
platform.mode=gaode

[2023-07-22 22:42:40,426][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[null]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:26)
[2023-07-22 22:42:40,662][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:27)
[2023-07-22 22:42:40,898][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=false, msg=ip[127.0.0.1]非法, province=[], city=[], x=null, y=null) (PlatformTest.java:28)
[2023-07-22 22:42:41,132][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=北京市, city=北京市, x=116.3974589, y=39.93888382) (PlatformTest.java:29)
[2023-07-22 22:42:41,365][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=廣東省, city=廣州市, x=113.3893937, y=23.15653812) (PlatformTest.java:30)
[2023-07-22 22:42:41,600][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=10000, successFlag=true, msg=OK, province=上海市, city=上海市, x=121.4767528, y=31.224348955) (PlatformTest.java:31)
platform.mode=baidu

[2023-07-22 22:40:48,774][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=2, successFlag=false, msg=Request Parameter Error:ip illegal, province=null, city=null, x=null, y=null) (PlatformTest.java:26)
[2023-07-22 22:40:48,825][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=廣東省, city=廣州市, x=113.27143134, y=23.13533631) (PlatformTest.java:27)
[2023-07-22 22:40:48,862][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=1, successFlag=false, msg=Internal Service Error:ip[127.0.0.1] loc failed, province=null, city=null, x=null, y=null) (PlatformTest.java:28)
[2023-07-22 22:40:48,899][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=北京市, city=北京市, x=116.4133837, y=39.91092455) (PlatformTest.java:29)
[2023-07-22 22:40:48,949][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=廣東省, city=廣州市, x=113.27143134, y=23.13533631) (PlatformTest.java:30)
[2023-07-22 22:40:48,988][INFO ][main] 解析結(jié)果:IpAnalyzeResponse(status=0, successFlag=true, msg=null, province=上海市, city=上海市, x=121.48789949, y=31.24916171) (PlatformTest.java:31)
到此這篇關(guān)于Springboot利于第三方服務(wù)進(jìn)行ip定位獲取省份城市的文章就介紹到這了,更多相關(guān)Springboot ip定位獲取省份城市內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot自動(dòng)配置沒有生效的問題定位(條件斷點(diǎn))
- Springboot啟動(dòng)報(bào)錯(cuò)時(shí)實(shí)現(xiàn)異常定位
- SpringBoot整合Mybatis實(shí)現(xiàn)高德地圖定位并將數(shù)據(jù)存入數(shù)據(jù)庫的步驟詳解
- SpringBoot中定位切點(diǎn)的兩種常用方法
- SpringBoot上傳圖片到指定位置并返回URL的實(shí)現(xiàn)
- SpringBoot整合Ip2region獲取IP地址和定位的詳細(xì)過程
- Springboot集成百度地圖實(shí)現(xiàn)定位打卡的示例代碼
相關(guān)文章
javascript與jsp發(fā)送請求到servlet的幾種方式實(shí)例
本文分別給出了javascript發(fā)送請求到servlet的5種方式實(shí)例與 jsp發(fā)送請求到servlet的6種方式實(shí)例2018-03-03
java?String拼接json的方式實(shí)現(xiàn)
本文主要介紹了java?String拼接json的方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09
SpringCloud?Tencent?全套解決方案源碼分析
Spring Cloud Tencent實(shí)現(xiàn)Spring Cloud標(biāo)準(zhǔn)微服務(wù)SPI,開發(fā)者可以基于Spring Cloud Tencent開發(fā)Spring Cloud微服務(wù)架構(gòu)應(yīng)用,Spring Cloud Tencent 的核心依托騰訊開源的一站式服務(wù)發(fā)現(xiàn)與治理平臺 Polarismesh,實(shí)現(xiàn)各種分布式微服務(wù)場景,感興趣的朋友一起看看吧2022-07-07
解決子線程無法訪問父線程中通過ThreadLocal設(shè)置的變量問題
這篇文章主要介紹了解決子線程無法訪問父線程中通過ThreadLocal設(shè)置的變量問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Spring Boot整合elasticsearch的詳細(xì)步驟
這篇文章主要介紹了Spring Boot整合elasticsearch的詳細(xì)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Java設(shè)計(jì)模式之解釋器模式(Interpreter模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之解釋器模式(Interpreter模式)介紹,Interpreter定義:定義語言的文法,并且建立一個(gè)解釋器來解釋該語言中的句子,需要的朋友可以參考下2015-03-03
java反射遍歷實(shí)體類屬性和類型,并賦值和獲取值的簡單方法
下面小編就為大家?guī)硪黄猨ava反射遍歷實(shí)體類屬性和類型,并賦值和獲取值的簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04

