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

4 декабря 2015

Задача определения города и страны по 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) версия базы весит еще больше. Как бы вы предложили решить эту проблему?

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.