Springboot利于第三方服務(wù)進行ip定位獲取省份城市
在web應(yīng)用的開發(fā)中,我們或許會想知道我們的用戶請求的來源分布情況。本文基于springboot框架,調(diào)用百度地圖、高德地圖的開放平臺api,在線對對請求來源的ip進行定位、解析,獲取目標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; }
定義接口
實現(xiàn)該接口,并在配置類中注入接口的實現(xiàn)類,即可拓展ip定位的更多實現(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; } }
二.百度地圖開放平臺實現(xiàn)
1. 使用準備
閱讀文檔普通IP定位 | 百度地圖API SDK (baidu.com),成為開發(fā)者,獲取服務(wù)密鑰(AK)
2. 封裝實體類
/** * @author 擺渡人 * @description 地址解析的結(jié)果 * @date 2023/7/10 20:29 */ @Data public class IpAnalyzeBaiduResponse implements Serializable { /** * 返回狀態(tài)碼 */ private Integer status; /** * 錯誤信息 */ private String message; /** * 地址 */ private String address; /** * 詳細內(nèi)容 */ private IpAnalyzeContent content; }
/** * @author 擺渡人 * @description 詳細內(nèi)容 * @date 2023/7/10 20:42 */ @Data public class IpAnalyzeContent implements Serializable { /** * 簡要地址 */ private String address; /** * 詳細地址信息 */ @JsonProperty("address_detail") private IpAnalyzeAddressDetail addressDetail; /** * 百度經(jīng)緯度坐標值 */ @JsonProperty("point") private IpAnalyzePoint point; }
/** * @author 擺渡人 * @description 詳細地址信息 * @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)緯度坐標值 * @date 2023/7/10 20:43 */ @Data public class IpAnalyzePoint implements Serializable { private String x; private String y; }
3.實現(xiàn)接口IPlatFormIpAnalyzeService
/** * @author 擺渡人 * @description 百度地圖開發(fā)平臺實現(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(); } } }
三.高德地圖開放平臺實現(xiàn)
1. 使用準備
根據(jù)文檔獲取Key-創(chuàng)建工程-開發(fā)指南-Web服務(wù) API|高德地圖API (amap.com)指引獲取key
2. 封裝實體類
/** * @author 擺渡人 * @description 高德地圖ip定位響應(yīng)類 * @date 2023/7/14 0:00 */ @Data public class IpAnalyzeGaodeResponse { /** * 返回結(jié)果狀態(tài)值,值為0或1,0表示失?。?表示成功 */ private String status; /** * 返回狀態(tài)說明,status為0時,info返回錯誤原因,否則返回“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ū)域范圍,所在城市范圍的左下右上對標對,如:116.0119343,39.66127144;116.7829835,40.2164962 */ private String rectangle; }
3.實現(xiàn)接口IPlatFormIpAnalyzeService
/** * @author 擺渡人 * @description 高德地圖開放平臺ip定位實現(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進行解析 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: # 您的高德地圖開放平臺key
2.配置類
根據(jù)配置參數(shù)中platform.mode
的值選擇接口IPlatFormIpAnalyzeService
的一個服務(wù)類注入Spring容器中去
/** * @author 擺渡人 * @description 接口實現(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")); } }
運行結(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ù)進行ip定位獲取省份城市的文章就介紹到這了,更多相關(guān)Springboot ip定位獲取省份城市內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript與jsp發(fā)送請求到servlet的幾種方式實例
本文分別給出了javascript發(fā)送請求到servlet的5種方式實例與 jsp發(fā)送請求到servlet的6種方式實例2018-03-03SpringCloud?Tencent?全套解決方案源碼分析
Spring Cloud Tencent實現(xiàn)Spring Cloud標準微服務(wù)SPI,開發(fā)者可以基于Spring Cloud Tencent開發(fā)Spring Cloud微服務(wù)架構(gòu)應(yīng)用,Spring Cloud Tencent 的核心依托騰訊開源的一站式服務(wù)發(fā)現(xiàn)與治理平臺 Polarismesh,實現(xiàn)各種分布式微服務(wù)場景,感興趣的朋友一起看看吧2022-07-07解決子線程無法訪問父線程中通過ThreadLocal設(shè)置的變量問題
這篇文章主要介紹了解決子線程無法訪問父線程中通過ThreadLocal設(shè)置的變量問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07Spring Boot整合elasticsearch的詳細步驟
這篇文章主要介紹了Spring Boot整合elasticsearch的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Java設(shè)計模式之解釋器模式(Interpreter模式)介紹
這篇文章主要介紹了Java設(shè)計模式之解釋器模式(Interpreter模式)介紹,Interpreter定義:定義語言的文法,并且建立一個解釋器來解釋該語言中的句子,需要的朋友可以參考下2015-03-03