Geolocation by IP in Java – 在Java中通过IP进行地理定位

最后修改: 2016年 11月 24日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this article, we will explore how to get geographic location data from an IP address using the MaxMind GeoIP2 Java API with the free GeoLite2 database.

在这篇文章中,我们将探讨如何使用MaxMind GeoIP2 Java API与免费的GeoLite2数据库从IP地址获取地理位置数据。

We will also see this in action using a simple Spring MVC Web demo application.

我们还将使用一个简单的Spring MVC Web演示应用程序来观察其操作。

2. Getting Started

2.开始

To get started, you’ll need to download the GeoIP2 API and GeoLite2 database from MaxMind.

要开始使用,您需要从MaxMind下载GeoIP2 API和GeoLite2数据库。

2.1. Maven Dependency

2.1.Maven的依赖性

To include the MaxMind GeoIP2 API in your Maven project, add the following to the pom.xml file:

要将MaxMind GeoIP2 API纳入您的Maven项目,请在pom.xml文件中添加以下内容。

<dependency>
    <groupId>com.maxmind.geoip2</groupId>
    <artifactId>geoip2</artifactId>
    <version>2.8.0</version>
</dependency>

To get the latest version of the API, you can find it on Maven Central.

要获得最新版本的API,您可以在Maven Central上找到它。

2.2. Downloading the Database

2.2.下载数据库

Next, you’ll need to download the GeoLite2 database. For this tutorial, we are using the binary gzipped version of the GeoLite2 City database.

接下来,你需要下载GeoLite2数据库。在本教程中,我们使用的是GeoLite2城市数据库的二进制gzipped版本。

After you unpack the archive, you’ll have a file named GeoLite2-City.mmdb. This is a database of IP-to-location mappings in the proprietary MaxMind binary format.

在你解压后,你会有一个名为GeoLite2-City.mmdb的文件。这是一个以MaxMind专有的二进制格式的IP-to-location映射的数据库。

3. Using the GeoIP2 Java API

3.使用GeoIP2 Java API

Let’s use the GeoIP2 Java API to fetch location data for a given IP address from the database. First, let’s create a DatabaseReader to query the database:

让我们使用GeoIP2 Java API从数据库中获取一个给定IP地址的位置数据。首先,让我们创建一个DatabaseReader来查询数据库。

File database = new File(dbLocation);
DatabaseReader dbReader = new DatabaseReader.Builder(database).build();

Next, let’s use the city() method to obtain the city data for an IP address:

接下来,让我们使用city()方法来获取一个IP地址的城市数据。

CityResponse response = dbReader.city(ipAddress);

The CityResponse object contains several pieces of information other than just the city name. Here’s a sample JUnit test showing how to open the database, fetch the city information for an IP address, and extract this information from the CityResponse:

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. Using GeoIP in a Web Application

4.在网络应用中使用GeoIP

Let’s look at a sample web application that fetches geolocation data from a user’s public IP address and displays the location on a map.

让我们看看一个网络应用的样本,它从用户的公共IP地址获取地理位置数据并在地图上显示位置。

We will start with a basic Spring Web MVC Application. Then we’ll write a Controller that accepts an IP address in a POST request and returns a JSON response containing city, latitude, and longitude deduced from the GeoIP2 API.

我们将从一个基本的Spring Web MVC应用程序开始。然后我们将编写一个控制器,该控制器在POST请求中接受一个IP地址,并返回一个包含从GeoIP2 API推导出的城市、纬度和经度的JSON响应。

Finally, we’ll write some HTML and JavaScript that will load the user’s public IP address into the form, submit an Ajax POST request to our Controller, and display the result in Google Maps.

最后,我们将编写一些HTML和JavaScript,将用户的公共IP地址加载到表单中,向我们的Controller提交Ajax POST请求,并在Google Maps中显示结果。

4.1. The Response Entity Class

4.1.响应实体类

Let’s start by defining the class which will hold the geolocation response:

让我们从定义将容纳地理位置响应的类开始。

public class GeoIP {
    private String ipAddress;
    private String city;
    private String latitude;
    private String longitude;
    // constructors, getters and setters... 
}

4.2. The Service Class

4.2.服务类

Now let’s write the service class which fetches the geolocation data using the GeoIP2 Java API and GeoLite2 database:

现在让我们来写一个服务类,使用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. The Spring Controller

4.3.Spring控制器

Let’s have a look at the Controller for Spring MVC which sends the “ipAddress” request parameter to our service class to get the geolocation response data:

让我们看看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. The HTML Form

4.4.HTML表格

Let’s add the front-end code to call our Spring Controller, beginning with an HTML form containing the IP address:

让我们添加前端代码来调用我们的Spring Controller,以一个包含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. Loading the Public IP Address on the Client

4.5.在客户端加载公共IP地址

Now let’s pre-populate the “ipAddress” text field with the user’s public IP address, using jQuery and the ipify.org JavaScript API:

现在让我们使用jQuery和ipify.orgJavaScript 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. Submitting the Ajax POST Request

4.6.提交Ajax POST请求

When the form is submitted, we will make an Ajax POST request to the Spring Controller to retrieve the JSON Response with geolocation data:

当表单提交后,我们将向Spring Controller发出Ajax POST请求,以检索包含地理位置数据的JSON Response。

$( "#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. Sample JSON Response

4.7.JSON响应样本

The JSON response from our Spring Controller will have the following format:

来自我们Spring Controller的JSON响应将有以下格式。

{
    "ipAddress":"your-ip-address",
    "city":"your-city",
    "latitude":"your-latitude",
    "longitude":"your-longitude"
}

4.8. Displaying the Location on Google Maps

4.8.在谷歌地图上显示位置

To display the location on Google Maps, you’ll need to include the Google Maps API in your HTML code:

要在谷歌地图上显示位置,你需要在你的HTML代码中包括谷歌地图API。

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR-API-KEY" 
async defer></script>

You can obtain an API Key for Google Maps using the Google Developer Console.

你可以使用谷歌开发者控制台获得谷歌地图的API密钥。

You’ll also need to define an HTML <div> tag to contain the map image:

你还需要定义一个HTML<div>标签来包含地图图像。

<div id="map" style="height: 500px; width:100%; position:absolute"></div>

You can use the following JavaScript function to display the coordinates on Google Maps:

你可以使用以下JavaScript函数在谷歌地图上显示坐标。

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
    });   
}

After starting the web application, open the URL for the map page:

启动网络应用程序后,打开地图页面的URL。

http://localhost:8080/spring-mvc-xml/GeoIpTest.jsp

You will see the current public IP address for your connection loaded into the text box:

你会看到你的连接的当前公共IP地址被加载到文本框中。

Capture-2

Note that both GeoIP2 and ipify support IPv4 addresses as well as IPv6 addresses.

请注意,GeoIP2和ipify都支持IPv4地址,也支持IPv6地址。

When you submit the form, you’ll see the JSON response text, including the city, latitude, and longitude corresponding to your public IP Address, and below that, you’ll see a Google Map pointing to your location:

当你提交表格时,你会看到JSON响应文本,包括与你的公共IP地址相对应的城市、纬度和经度,在这下面,你会看到一个指向你的位置的谷歌地图。

Capture-3

5. Conclusion

5.总结

In this tutorial, we reviewed the usage of the MaxMind GeoIP2 Java API and free MaxMind GeoLite2 City database using a JUnit test.

在本教程中,我们使用JUnit测试回顾了MaxMind GeoIP2 Java API和免费的MaxMind GeoLite2城市数据库的用法。

Then we built a Spring MVC Controller and service to obtain the geolocation data (city, latitude, longitude) from an IP address.

然后我们建立了一个Spring MVCController和服务,从IP地址获取地理位置数据(城市,纬度,经度)。

Finally, we built an HTML/JavaScript front end to demonstrate how this feature can be used to display a user’s location on Google Maps.

最后,我们建立了一个HTML/JavaScript前端,以演示如何利用这一功能在谷歌地图上显示用户的位置。

This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com.

本产品包括由MaxMind创建的GeoLite2数据,可从http://www.maxmind.com获得。

The code for this tutorial can be found on the Github site.

本教程的代码可以在Github网站上找到。