← На главную

Определение страны и города по IP-адресу на Java/Scala

Задача определения города и страны по IP-адресу встречается довольно часто. Когда пользователь заходит на сайт, желательно сразу показать ему интерфейс на том языке, который пользователь с наибольшей вероятностью понимает. А зная приблизительные координаты пользователя, можно перенаправить его запросы на ближайший сервер, уменьшив тем самым время ответа. В этой небольшой заметке мы посмотрим, как эта задача может быть решена на Scala или любом другом JVM-языке.

Не будем ходить вокруг да около. Тут можно скачать базу, а здесь – посмотреть исходники клиента к ней.

Качаем и распаковываем бесплатную версию базу:

wget geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz gunzip GeoLiteCity.dat.gz

Запускаем REPL с подгруженной зависимостью:

screpl "com.maxmind.geoip%geoip-api%1.2.14"

… где screpl – это вот такой скрипт, лежащий где-то в $PATH:

#!/bin/sh /usr/bin/sbt -Dsbt.version=0.13.7 -Dsbt.main.class=sbt.ConsoleMain "$@"

Примечание: Кстати, когда я изучал Scala, почему-то для меня было большой проблемой понять, как использовать зависимости в REPL. Сделать это можно как описано выше, или, если вы не просто экспериментируете с библиотекой, а работаете над полноценным проектом, командой sbt console. Если же вы пользуетесь возможностью SBT создавать много проектов внутри одного (multi project builds), то команда будет sbt myproject/console. Кроме того, это возможно через Scala Console в IntelliJ IDEA. При использованием multi project builds опять-таки важно указать правильный проект.

Инициализируем клиент:

scala> import com.maxmind.geoip._ import com.maxmind.geoip._ scala> val srv = { | new LookupService("./GeoLiteCity.dat", | LookupService.GEOIP_MEMORY_CACHE) | }

Получаем информацию об IP:

scala> val loc = srv.getLocation("123.45.67.89")

Смотрим в интересующие нас поля:

scala> loc.countryCode res0: String = RU scala> loc.countryName res1: String = Russian Federation scala> loc.city res2: String = Moscow scala> loc.latitude res3: Float = 55.752197 scala> loc.longitude res4: Float = 37.6156

Важно! Приведенные выше значения могут быть и null, поэтому в боевом коде обязательно оборачивайте их в Option.

Как видите, все предельно просто.

Правда, не совсем понятно, как правильно доставлять базу на сервера. Все-таки 12 Мб в сжатом виде – достаточно большой размер для упаковки в deb- или rpm-пакет, а полная (не lite) версия базы весит еще больше. Как бы вы предложили решить эту проблему?