Java 中的 IP 地理定位
1. 简介
在本文中,我们将探讨如何使用 MaxMind GeoIP2 Java API 和免费的 GeoLite2 数据库从 IP 地址获取地理位置数据。
我们还将使用一个简单的 Spring MVC Web 演示应用程序看到这一点。
2. 入门
要开始使用,您需要从 MaxMind 下载 GeoIP2 API 和 GeoLite2 数据库。
2.1. Maven 依赖
要在 Maven 项目中包含 MaxMind GeoIP2 API,请将以下内容添加到pom.xml文件中:
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.8.0</version>
</dependency>
要获取最新版本的 API,您可以在Maven Central 上找到它。
2.2. 下载数据库
接下来,您需要下载GeoLite2 数据库 。对于本教程,我们使用的是 GeoLite2 City 数据库的二进制 gzip 版本。
解压缩存档后,您将拥有一个名为GeoLite2-City.mmdb的文件。这是一个专有 MaxMind 二进制格式的 IP 到位置映射的数据库。
3. 使用 GeoIP2 Java API
让我们使用 GeoIP2 Java API 从数据库中获取给定 IP 地址的位置数据。首先,让我们创建一个DatabaseReader来查询数据库:
File database = new File(dbLocation);
DatabaseReader dbReader = new DatabaseReader.Builder(database).build();
接下来,让我们使用*city()*方法获取 IP 地址的城市数据:
CityResponse response = dbReader.city(ipAddress);
CityResponse对象包含多个信息,而不仅仅是城市名称。下面是一个示例 JUnit 测试,展示了如何打开数据库、获取 IP 地址的城市信息以及从CityResponse中提取此信息:
@Test
public void givenIP_whenFetchingCity_thenReturnsCityData()
throws IOException, GeoIp2Exception {
String ip = "your-ip-address";
String dbLocation = "your-path-to-mmdb";
File database = new File(dbLocation);
DatabaseReader dbReader = new DatabaseReader.Builder(database)
.build();
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse response = dbReader.city(ipAddress);
String countryName = response.getCountry().getName();
String cityName = response.getCity().getName();
String postal = response.getPostal().getCode();
String state = response.getLeastSpecificSubdivision().getName();
}
4. 在 Web 应用程序中使用 GeoIP
让我们看一个示例 Web 应用程序,它从用户的公共 IP 地址获取地理位置数据并在地图上显示该位置。
我们将从一个基本的 Spring Web MVC 应用程序 开始。然后我们将编写一个Controller,它在 POST 请求中接受 IP 地址并返回包含从 GeoIP2 API 推导出的城市、纬度和经度的 JSON 响应。
最后,我们将编写一些 HTML 和 JavaScript,将用户的公共 IP 地址加载到表单中,向我们的Controller提交一个 Ajax POST 请求,并在 Google 地图中显示结果。
4.1. 响应实体类
让我们首先定义将保存地理位置响应的类:
public class GeoIP {
private String ipAddress;
private String city;
private String latitude;
private String longitude;
// constructors, getters and setters...
}
4.2. 服务类
现在让我们编写使用 GeoIP2 Java API 和 GeoLite2 数据库获取地理位置数据的服务类:
public class RawDBDemoGeoIPLocationService {
private DatabaseReader dbReader;
public RawDBDemoGeoIPLocationService() throws IOException {
File database = new File("your-mmdb-location");
dbReader = new DatabaseReader.Builder(database).build();
}
public GeoIP getLocation(String ip)
throws IOException, GeoIp2Exception {
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse response = dbReader.city(ipAddress);
String cityName = response.getCity().getName();
String latitude =
response.getLocation().getLatitude().toString();
String longitude =
response.getLocation().getLongitude().toString();
return new GeoIP(ip, cityName, latitude, longitude);
}
}
4.3. Spring 控制器
让我们看一下 Spring MVC 的Controller,它将“ipAddress”请求参数发送到我们的服务类以获取地理位置响应数据:
@RestController
public class GeoIPTestController {
private RawDBDemoGeoIPLocationService locationService;
public GeoIPTestController() throws IOException {
locationService = new RawDBDemoGeoIPLocationService();
}
@PostMapping("/GeoIPTest")
public GeoIP getLocation(
@RequestParam(value="ipAddress", required=true) String ipAddress
) throws Exception {
GeoIPLocationService<String, GeoIP> locationService
= new RawDBDemoGeoIPLocationService();
return locationService.getLocation(ipAddress);
}
}
4.4. HTML 表单
让我们添加前端代码来调用我们的 Spring 控制器,从一个包含 IP 地址的 HTML 表单开始:
<body>
<form id="ipForm" action="GeoIPTest" method="POST">
<input type="text" name = "ipAddress" id = "ip"/>
<input type="submit" name="submit" value="submit" />
</form>
...
</body>
4.5. 在客户端加载公共 IP 地址
现在让我们使用 jQuery 和ipify.org JavaScript API使用用户的公共 IP 地址预先填充“ipAddress”文本字段:
<script src
="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready (function () {
$.get( "https://api.ipify.org?format=json",
function( data ) {
$("#ip").val(data.ip) ;
});
...
</script>
4.6. 提交 Ajax POST 请求
提交表单后,我们将向 Spring Controller发出 Ajax POST 请求,以检索带有地理位置数据的 JSON 响应:
$( "#ipForm" ).submit(function( event ) {
event.preventDefault();
$.ajax({
url: "GeoIPTest",
type: "POST",
contentType:
"application/x-www-form-urlencoded; charset=UTF-8",
data: $.param( {ipAddress : $("#ip").val()} ),
complete: function(data) {},
success: function(data) {
$("#status").html(JSON.stringify(data));
if (data.ipAddress !=null) {
showLocationOnMap(data);
}
},
error: function(err) {
$("#status").html("Error:"+JSON.stringify(data));
},
});
});
4.7. 示例 JSON 响应
来自 Spring Controller的 JSON 响应将具有以下格式:
{
"ipAddress":"your-ip-address",
"city":"your-city",
"latitude":"your-latitude",
"longitude":"your-longitude"
}
4.8. 在谷歌地图上显示位置
要在 Google 地图上显示位置,您需要在 HTML 代码中包含 Google 地图 API:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR-API-KEY"
async defer></script>
您可以使用 Google Developer Console 获取 Google Maps 的 API 密钥。 您还需要定义一个 HTML <div>标签来包含地图图像:
<div id="map" style="height: 500px; width:100%; position:absolute"></div>
您可以使用以下 JavaScript 函数在 Google 地图上显示坐标:
function showLocationOnMap (location) {
var map;
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: Number(location.latitude),
lng: Number(location.longitude)},
zoom: 15
});
var marker = new google.maps.Marker({
position: {
lat: Number(location.latitude),
lng: Number(location.longitude)},
map: map,
title:
"Public IP:"+location.ipAddress
+" @ "+location.city
});
}
启动 Web 应用程序后,打开地图页面的 URL:
http://localhost:8080/spring-mvc-xml/GeoIpTest.jsp
您将在文本框中看到您连接的当前公共 IP 地址:
请注意,GeoIP2 和 ipify 都支持 IPv4 地址和 IPv6 地址。
当您提交表单时,您会看到 JSON 响应文本,包括与您的公共 IP 地址对应的城市、纬度和经度,并且在其下方,您会看到指向您所在位置的 Google 地图: