JSON-OBJECT Software Engineering Blog

Professional Senior Backend Engineer. Specializing in high volume traffic and distributed processing with Kotlin and Spring Boot as core technologies.

View on GitHub
15 August 2023

Kotlin + Spring Boot, IP 주소로부터 Geolocation 정보 조회하기

by Taehyeong Lee

개요

GeoLite2 로컬 데이터베이스 다운로드

$ wget -nv -O GeoLite2-ASN.mmdb https://git.io/GeoLite2-ASN.mmdb
$ wget -nv -O GeoLite2-City.mmdb https://git.io/GeoLite2-City.mmdb
$ wget -nv -O GeoLite2-Country.mmdb https://git.io/GeoLite2-Country.mmdb
GeoLite2-ASN.mmdb / 7.83 MB
GeoLite2-City.mmdb / 68.4 MB
GeoLite2-Country.mmdb / 5.91 MB

build.gradle.kts

dependencies {
    implementation("com.maxmind.geoip2:geoip2:4.1.0")
}

GeoLocationConfig.kt

import com.maxmind.db.CHMCache
import com.maxmind.geoip2.DatabaseReader
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.io.File
 
@Configuration
class GeoLocationConfig {
 
    @Bean("databaseReader")
    fun databaseReader(): DatabaseReader {
 
        return DatabaseReader
            .Builder(File("/GeoLite2-City.mmdb"))
            .withCache(CHMCache())
            .build()
    }
}

GeoLocationService.kt

import com.maxmind.geoip2.DatabaseReader
import com.maxmind.geoip2.model.CityResponse
import com.maxmind.geoip2.record.Country
import org.springframework.stereotype.Service
import java.io.Serializable
import java.net.InetAddress
 
@Service
class GeoLocationService(
    private val databaseReader: DatabaseReader
) {
    fun getGeoLocation(ipAddress: String?): GeoLocationDTO? {
 
        if (ipAddress.isNullOrBlank()) return null
 
        return try {
 
            val response: CityResponse = databaseReader.city(InetAddress.getByName(ipAddress))
            val country: Country = response.country
            val subdivision = response.getMostSpecificSubdivision()
 
            GeoLocationDTO(
                ipAddress = ipAddress,
                country = country.name,
                countryCode = country.isoCode,
                subdivision = subdivision.name,
                subdivisionCode = subdivision.isoCode
            )
 
        } catch (ex: Exception) {
            null
        }
    }
}
 
data class GeoLocationDTO(
 
    var ipAddress: String? = null,
    var country: String? = null,
    var countryCode: String? = null,
    var subdivision: String? = null,
    var subdivisionCode: String? = null
 
) : Serializable

사용 예

// country: South Korea, country_code: KR, subdivision: Seoul, subdivision_code: 11
val geolocation = geoLocationService.getGeoLocation({ip-address})

프로덕션 도입 경험

참고 글

tags: Kotlin - Geolocation