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を入手するには、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.maxmind.geoip2%22%20AND%20a%3Aで入手できます。 %22geoip2%22[メイヴン中央]。

2.2. データベースのダウンロード

次に、http://dev.maxmind.com/geoip/geoip2/geolite2/[GeoLite2データベース]をダウンロードする必要があります。このチュートリアルでは、GeoLite 2 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 オブジェクトには、都市名以外のいくつかの情報が含まれています。データベースを開き、IPアドレスの都市情報を取得し、 CityResponse からこの情報を抽出する方法を示すサンプルのJUnitテストです。

@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の使用

ユーザーのパブリックIPアドレスから位置情報データを取得し、その場所を地図上に表示するサンプルWebアプリケーションを見てみましょう。

/spring-mvc-tutorial[基本のSpring Web MVCアプリケーション]というリンクから始めます。次に、POSTリクエストでIPアドレスを受け取り、GeoIP2 APIから推定された都市、緯度、経度を含むJSONレスポンスを返す Controller を作成します。

最後に、ユーザーのパブリックIPアドレスをフォームにロードし、Ajax POSTリクエストを Controller に送信してGoogleマップに表示するHTMLとJavaScriptを作成します。

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. スプリングコントローラー

地理位置情報応答データを取得するために“ ipAddress”リクエストパラメータをサービスクラスに送信するSpring MVCの Controller を見てみましょう。

@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フォーム

IPアドレスを含むHTMLフォームから始めて、Springの__Controllerを呼び出すためのフロントエンドコードを追加しましょう。

<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とhttps://www.ipify.org/[ipify.org]JavaScript APIを使用して、「ipAddress」テキストフィールドにユーザーのパブリックIPアドレスを事前入力しましょう。

<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マップで場所を表示する

Googleマップに場所を表示するには、HTMLコードにGoogleマップAPIを含める必要があります。

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

Googleデベロッパーコンソールを使用してGoogleマップのAPIキーを取得できます。

地図画像を含めるためのHTML <div> タグも定義する必要があります。

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

Googleマップに座標を表示するには、次の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
    });
}

Webアプリケーションを起動したら、マップページのURLを開きます。

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

接続の現在のパブリックIPアドレスがテキストボックスに読み込まれます。

GeoIP2とipifyはどちらもIPv4アドレスとIPv6アドレスをサポートしています。

フォームを送信すると、パブリックIPアドレスに対応する都市、緯度、経度などのJSON応答テキストが表示されます。その下に、自分の場所を指すGoogleマップが表示されます。

5.まとめ

このチュートリアルでは、JUnitテストを使用して、MaxMind GeoIP2 Java APIと無料のMaxMind GeoLite2 Cityデータベースの使用方法を確認しました。

次に、IPアドレスから地理位置データ(都市、緯度、経度)を取得するためにSpring MVC Controller とサービスを構築しました。

最後に、Googleマップにユーザーの位置を表示するためにこの機能を使用する方法を示すために、HTML/JavaScriptフロントエンドを作成しました。

この製品には、http://www.maxmind.comから入手可能な、MaxMindによって作成されたGeoLite2データが含まれています。

このチュートリアルのコードはhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-xml[Githubサイト]にあります。