通过IP来查找对应城市信息(Kotlin+redis实现)

通过IP来查找对应城市信息(Kotlin+redis实现)

通过IP来查找对应城市信息(Kotlin+redis实现)

环境
- kotlin:1.5.3.RELEASE
- redis:3.2.8

1、获得IP与城市信息的CVS表

GeoLiteCity-latest.zip

有以下文件:
- GeoLiteCity-Blocks.csv :IP与城市编号对应的表
- GeoLiteCity-Location.csv :城市详细信息表

2、将CVS表中信息导入redis中

import com.google.gson.Gson
import com.yc.kotlin.entity.City
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVParser
import org.apache.commons.csv.CSVRecord
import redis.clients.jedis.Jedis
import redis.clients.jedis.JedisPool
import redis.clients.jedis.JedisPoolConfig
import java.io.File
import java.io.FileReader

var GEOLITECITY_LOCATION = "C:\\Users\\Administrator\\Desktop\\GeoLiteCity_20170801\\GeoLiteCity-Location.csv"

var GEOLITECITY_BLOCKS = "C:\\Users\\Administrator\\Desktop\\GeoLiteCity_20170801\\GeoLiteCity-Blocks.csv"
var IP2CITYID = "ip2cityid:"
var CITYID2CITY = "cityid2city:"

fun getJedis(): Jedis {

    // 池基本配置
    val config = JedisPoolConfig()
    config.maxTotal = 100
    config.maxIdle = 5
    config.maxWaitMillis = 100000
    config.testOnBorrow = false

    val jedisPool = JedisPool(config, "192.168.10.1", 6379, 10000, "redis")
    return jedisPool.resource
}

/**
 * 将IP转换为数字
 */
fun ipToScore(ipAddress:String):Long{
    var score = 0L
    for(v in ipAddress.split(".")){
        score = score * 256 + v.toLong()
    }
    return score
}

/**
 * 从文件中读取IP与城市编号存入redis中
 */
fun importIpToRedis(jedis:Jedis,file:File){

    val pipeline = jedis.pipelined()

    println("导入ip地址开始")
    val startTime = System.currentTimeMillis()
    val reader = FileReader(file)
    val parser = CSVParser(reader, CSVFormat.newFormat(','))

    val records = parser.records

    for (i in records.indices){

        val recordNumber = records[i].recordNumber
        if (recordNumber < 3)
            continue
        val start = replaceSprit(records[i].get(0)).toDouble()
        val id = records[i].get(2)
        // 将开始IP与对应的城市编号存入Set中
        pipeline.zadd(IP2CITYID,start,replaceSprit(id + "_" + i))
        println("start:" + start.toString()  + ",id:" + id)
    }
    pipeline.syncAndReturnAll()
    pipeline.close()
    val endTime = System.currentTimeMillis();
    println("------------------")
    println("导入IP地址完成")
    println("耗时:" + (endTime - startTime)/1000.0)
}

fun citiesToRedis(jedis: Jedis,file: File){

    val gson = Gson ()
    val pipeline = jedis.pipelined()
    try {

        println("导入城市地址开始")
        val startTime = System.currentTimeMillis()
        val reader = FileReader(file)
        val parser = CSVParser(reader, CSVFormat.newFormat(','))

        val list = parser.records
        for (i in list.indices){
            // 本行元素数
            val num = list[i].recordNumber
            if(num < 3)
                continue
            val city = record2City(record = list[i])
            val json = gson.toJson(city)
            println("cityId:" + city.cityId + ",info:" + json)
            // 将城市详细信息存入Hash中
            pipeline.hset(CITYID2CITY,city.cityId,json)
        }
        pipeline.syncAndReturnAll()
        pipeline.close()
        val endTime = System.currentTimeMillis();
        println("------------------")
        println("导入IP地址完成")
        println("耗时:" + (endTime - startTime)/1000.0)
    } catch (e: Exception){
        e.printStackTrace()
    }
}

fun record2City(record: CSVRecord):City {
    val city:City = City()
    city.cityId = replaceSprit(record.get(0))
    city.country = replaceSprit(record.get(1))
    city.region = replaceSprit(record.get(2))
    city.city = replaceSprit(record.get(3))
    city.postalCode = replaceSprit(record.get(4))
    city.latitude = replaceSprit(record.get(5))
    city.longitude = replaceSprit(record.get(6))
    city.metroCode = replaceSprit(record.get(7))
    city.areaCode = replaceSprit(record.get(8))
    return city
}

fun replaceSprit(str: String): String {
    return str.replace("\"".toRegex(), "")
}

fun findByIp(jedis: Jedis,ip: String):City?{

    var score = ipToScore(ip)
    println(score)
    // 从有序Set中获取开始IP最接近传入IP的对象
    val results = jedis.zrevrangeByScore(IP2CITYID,score.toDouble(),0.0,0,1)
    if (0 == results.size)
        return null
    var cityId = results.iterator().next()
    cityId = cityId.substring(0, cityId.indexOf('_'))
    val city = Gson().fromJson<City>(jedis.hget(CITYID2CITY, cityId),City::class.java)
    return city
}

3、测试通过IP查找对应城市信息


fun main(args: Array<String>) {

    // ip导入redis中
    importIpToRedis(getJedis(),File(GEOLITECITY_BLOCKS))
    // 将cityId与对应的城市信息导入redis中
    citiesToRedis(getJedis(),File(GEOLITECITY_LOCATION))

    // Tokyo
    var ipAddress = "52.196.210.28"
    var city = findByIp(jedis = getJedis(), ip = ipAddress)
    println(city)
    // Shenzhen
    ipAddress = "58.60.230.138"
    city = findByIp(jedis = getJedis(), ip = ipAddress)
    println(city)
}

执行结果:

City(cityId=659898, country=JP, region=40, city=Tokyo, postalCode=100-0001, latitude=35.6427, longitude=139.7677, metroCode=, areaCode=)
City(cityId=47667, country=CN, region=30, city=Guangzhou, postalCode=, latitude=23.1167, longitude=113.2500, metroCode=, areaCode=)

表中对应的关系并没有涵盖所有的城市,也就导致会出现像上面那样的不准确的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值