java实现获取位置
注意:由于一般生产环境比如不通外网,docker部署等。那就需要找能本地部署的工具ip2region就是一个不错的离线开源工具,只需要下载db文件即可。将db文件放在了resource下读取的。通常公司网络是加域的。
·
通常公司网络是加域的
需要获取公网ip
在线公网获取位置
思想:
1获取公网ip
2根据ip获取位置
注意:由于一般生产环境比如不通外网,docker部署等。那就需要找能本地部署的工具ip2region就是一个不错的离线开源工具,只需要下载db文件即可
windows环境查看pc的公网信息:nslookup myip.opendns.com resolver1.opendns.com
将db文件放在了resource下读取的
package com.lcfc.agent.test;
import lombok.Cleanup;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class AccurateLocationFinder {
public static void main(String[] args) {
try {
System.out.println("开始获取地理位置信息...\n");
// 第一步:获取公网IP
String publicIP = getPublicIP();
if (publicIP == null) {
System.out.println("无法获取公网IP地址,请检查网络连接");
return;
}
System.out.println("✅ 获取到公网IP: " + publicIP + "\n");
// 第二步:使用多个地理位置API查询
Map<String, Map<String, String>> results = new HashMap<>();
// 查询多个API服务
results.put("ipapi", getLocationFromIpapi(publicIP));
results.put("ip2location", getLocationFromIp2Location(publicIP));
results.put("ipinfo", getLocationFromIpinfo(publicIP));
results.put("ipapi_co", getLocationFromIpapiCo(publicIP));
// 显示所有API的结果
System.out.println("=== 各API查询结果 ===");
for (Map.Entry<String, Map<String, String>> entry : results.entrySet()) {
Map<String, String> location = entry.getValue();
if (location != null && !location.isEmpty()) {
System.out.println("\n🔹 " + entry.getKey().toUpperCase() + ":");
System.out.println(" 国家: " + location.getOrDefault("country", "未知"));
System.out.println(" 省份: " + location.getOrDefault("region", "未知"));
System.out.println(" 城市: " + location.getOrDefault("city", "未知"));
System.out.println(" 运营商: " + location.getOrDefault("isp", "未知"));
System.out.println(" 坐标: " + location.getOrDefault("lat", "未知") + ", " +
location.getOrDefault("lon", "未知"));
}
}
// 第三步:智能分析最可能的位置
System.out.println("\n=== 综合分析结果 ===");
analyzeAndShowBestResult(results);
} catch (Exception e) {
System.err.println("程序执行错误: " + e.getMessage());
}
}
/**
* @param ip
* @Description: ip获取归属地
* @return: java.lang.String
* @Author: sijing.chen
* @Date: 2024/3/19 13:12
*/
public static String getSiteByIp(String ip) throws Exception {
Searcher searcher = null;
try {
// File file = ResourceUtils.getFile("classpath:ipdb/ip2region.xdb");
// String dbPath = file.getPath();
// searcher = Searcher.newWithFileOnly(dbPath);
//本地环境使用相对路径是可以的,但是部署的时候是linux环境,所以使用ResponseEntity(封装HTTP响应的相关信息), 且使用ip2region这个工具(需要下载离线包放在本地路径上,没有网络也可以使用)todo 如果想要自动更新ip库可参考官网https://github.com/lionsoul2014/ip2region 或者https://gitee.com/lionsoul/ip2region
ResponseEntity<byte[]> ip2region = getStream("ipdb/ip2region.xdb");
searcher = Searcher.newWithBuffer(ip2region.getBody());
System.out.println ("获取ip2region.xdb:" + searcher) ;
} catch (Exception e) {
e.printStackTrace();
}
String site = null;
site = searcher.search(ip);
// 输出 region ip2region的地址固定格式是:国家|区域|省份|城市|ISP,缺省的地域信息默认是0
return site;
}
/**
* @param templateName 路径
* @Description: 获取文件byte[]
* @return: org.springframework.http.ResponseEntity<byte [ ]>
* @Author: sijing.chen
* @Date: 2024/3/19 11:06
*/
public static ResponseEntity<byte[]> getStream(String templateName) throws IOException {
ClassPathResource classPathResource = new ClassPathResource(templateName);
String filename = classPathResource.getFilename();
System.out.println("获取该路径下的ip2region.xdb文件:" + filename);
@Cleanup InputStream inputStream = classPathResource.getInputStream();
byte[] bytes = FileCopyUtils.copyToByteArray(inputStream);
String fileName = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);
return new ResponseEntity<>(bytes, headers, HttpStatus.CREATED);
}
/**
* 获取公网IP地址
*/
private static String getPublicIP() {
String[] ipApis = {
"https://api.ipify.org?format=json",
"https://icanhazip.com",
"https://ident.me",
"https://ipecho.net/plain"
};
for (String api : ipApis) {
try {
URL url = new URL(api);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
conn.setReadTimeout(3000);
if (conn.getResponseCode() == 200) {
Scanner scanner = new Scanner(conn.getInputStream());
String response = scanner.useDelimiter("\\A").next();
System.out.println("使用工具 " + api +"获取公网ip,返回值是"+response);
scanner.close();
// 解析IP地址
String ip;
if (response.contains("{")) {
// JSON格式
ip = response.split("\"ip\":\"")[1].split("\"")[0];
} else {
// 纯文本格式
ip = response.trim();
}
if (isValidIP(ip)) {
System.out.println("✅ 获取到公网IP,使用的工具是: " + api );
System.out.println("获取到公网ip之后使用离线ip2 :" + getSiteByIp(ip) );
return ip;
}
}
} catch (Exception e) {
// 继续尝试下一个API
}
}
return null;
}
/**
* 从ipapi.com获取地理位置(免费版)
*/
private static Map<String, String> getLocationFromIpapi(String ip) {
try {
URL url = new URL("http://ipapi.com/ip_api.php?ip=" + ip);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
Scanner scanner = new Scanner(conn.getInputStream());
String response = scanner.useDelimiter("\\A").next();
scanner.close();
// 解析JSON响应
Map<String, String> result = new HashMap<>();
String[] parts = response.split("\"");
for (int i = 0; i < parts.length - 1; i++) {
if (parts[i].equals("country_name")) {
result.put("country", parts[i + 2]);
} else if (parts[i].equals("region_name")) {
result.put("region", parts[i + 2]);
} else if (parts[i].equals("city")) {
result.put("city", parts[i + 2]);
} else if (parts[i].equals("latitude")) {
result.put("lat", parts[i + 1].replace(":", "").replace(",", ""));
} else if (parts[i].equals("longitude")) {
result.put("lon", parts[i + 1].replace(":", "").replace(",", ""));
}
}
return result;
}
} catch (Exception e) {
System.out.println("ipapi.com查询失败: " + e.getMessage());
}
return null;
}
/**
* 从ip2location.com获取地理位置
*/
private static Map<String, String> getLocationFromIp2Location(String ip) {
try {
URL url = new URL("https://api.ip2location.com/v2/?ip=" + ip + "&key=demo");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
Scanner scanner = new Scanner(conn.getInputStream());
String response = scanner.useDelimiter("\\A").next();
scanner.close();
Map<String, String> result = new HashMap<>();
// 简化的解析逻辑
if (response.contains("country_name")) {
String country = extractJsonValue(response, "country_name");
String city = extractJsonValue(response, "city_name");
String region = extractJsonValue(response, "region_name");
result.put("country", country);
result.put("region", region);
result.put("city", city);
}
return result;
}
} catch (Exception e) {
System.out.println("ip2location查询失败: " + e.getMessage());
}
return null;
}
/**
* 从ipinfo.io获取地理位置
*/
private static Map<String, String> getLocationFromIpinfo(String ip) {
try {
URL url = new URL("https://ipinfo.io/" + ip + "/json");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
Scanner scanner = new Scanner(conn.getInputStream());
String response = scanner.useDelimiter("\\A").next();
scanner.close();
Map<String, String> result = new HashMap<>();
if (response.contains("\"country\"")) {
result.put("country", extractJsonValue(response, "country"));
result.put("region", extractJsonValue(response, "region"));
result.put("city", extractJsonValue(response, "city"));
result.put("isp", extractJsonValue(response, "org"));
// 解析坐标
if (response.contains("\"loc\"")) {
String loc = extractJsonValue(response, "loc");
if (loc.contains(",")) {
String[] coords = loc.split(",");
result.put("lat", coords[0]);
result.put("lon", coords[1]);
}
}
}
return result;
}
} catch (Exception e) {
System.out.println("ipinfo.io查询失败: " + e.getMessage());
}
return null;
}
/**
* 从ipapi.co获取地理位置
*/
private static Map<String, String> getLocationFromIpapiCo(String ip) {
try {
URL url = new URL("https://ipapi.co/" + ip + "/json/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
Scanner scanner = new Scanner(conn.getInputStream());
String response = scanner.useDelimiter("\\A").next();
scanner.close();
Map<String, String> result = new HashMap<>();
if (response.contains("\"country_name\"")) {
result.put("country", extractJsonValue(response, "country_name"));
result.put("region", extractJsonValue(response, "region"));
result.put("city", extractJsonValue(response, "city"));
result.put("isp", extractJsonValue(response, "org"));
result.put("lat", extractJsonValue(response, "latitude"));
result.put("lon", extractJsonValue(response, "longitude"));
}
return result;
}
} catch (Exception e) {
System.out.println("ipapi.co查询失败: " + e.getMessage());
}
return null;
}
/**
* 从JSON字符串中提取值
*/
private static String extractJsonValue(String json, String key) {
try {
String search = "\"" + key + "\":";
int start = json.indexOf(search) + search.length();
if (start > search.length()) {
int end = json.indexOf(",", start);
if (end == -1) end = json.indexOf("}", start);
if (end > start) {
String value = json.substring(start, end).trim();
// 去除引号
if (value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
return value;
}
}
} catch (Exception e) {
// 忽略解析错误
}
return "未知";
}
/**
* 智能分析最可能的位置
*/
private static void analyzeAndShowBestResult(Map<String, Map<String, String>> results) {
Map<String, Integer> countryCount = new HashMap<>();
Map<String, Integer> cityCount = new HashMap<>();
// 统计各个位置的出现次数
for (Map<String, String> location : results.values()) {
if (location != null) {
String country = location.get("country");
String city = location.get("city");
if (!"未知".equals(country)) {
countryCount.put(country, countryCount.getOrDefault(country, 0) + 1);
}
if (!"未知".equals(city)) {
cityCount.put(city, cityCount.getOrDefault(city, 0) + 1);
}
}
}
// 找出最常出现的结果
String mostLikelyCountry = findMostFrequent(countryCount);
String mostLikelyCity = findMostFrequent(cityCount);
System.out.println("📍 最可能的位置:");
System.out.println(" 国家: " + mostLikelyCountry);
System.out.println(" 城市: " + mostLikelyCity);
// 显示准确度评估
int validResults = (int) results.values().stream()
.filter(loc -> loc != null && !loc.isEmpty())
.count();
System.out.println("\n📊 准确度评估:");
System.out.println(" 成功查询的API数量: " + validResults + "/" + results.size());
System.out.println(" 置信度: " + (validResults * 25) + "%");
System.out.println("\n💡 提示: IP定位通常精确到城市级别,");
System.out.println(" 实际位置可能与显示位置有几十公里的误差");
}
/**
* 找出出现次数最多的值
*/
private static String findMostFrequent(Map<String, Integer> countMap) {
if (countMap.isEmpty()) return "未知";
return countMap.entrySet().stream()
.max(Map.Entry.comparingByValue())
.get().getKey();
}
/**
* 验证IP地址格式
*/
private static boolean isValidIP(String ip) {
return ip.matches("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
}
}
更多推荐
所有评论(0)