通过IP来查找对应城市信息(Kotlin+redis实现)
环境
- kotlin:1.5.3.RELEASE
- redis:3.2.8
1、获得IP与城市信息的CVS表
有以下文件:
- 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=)
表中对应的关系并没有涵盖所有的城市,也就导致会出现像上面那样的不准确的情况