天天看点

【Java】通过ip地址获取详细地域信息(不通过API使用本地库)

首先说一下之前使用了的是百度api和阿里免费的api查询,但是大老板说万一人家接口哪一天有限制访问怎么办,或者网络通讯哪一天不好怎么办,或者人家其实有收集我们的数据怎么办?那这里就必须有自己的库了,然后找了很久很久,大老板发现一个MaxMind GeoIP2,免费的还有维护今天是2019年6月(最新数据是2019年2月更新的),所以选择了这个....接下来正题开始

MaxMind GeoIP2

服务能识别互联网用户的地点位置与其他特征,应用广泛,包括个性化定制内容、诈欺检测、广告定向、网站流量分析、执行规定、地理目标定位、地理围栏定位 (geo-fencing)以及数字版权管理。目前使用 GeoIP 更多是配合Nginx或Apache服务器进行日志分析获取网站访问量地域分布状况。

GeoIP 分为商业版和免费版,免费版比商业版精度差了许多,经测试对于城市定位确实有差距,能否接受看你的精度要求!(老板说免费的可以了,哈哈)

下载GeoIP2的库,这个库是经常更新的,如果数据要求很高的,需要经常更新(我们不高,预计一年一次)

官网下载地址https://dev.maxmind.com/geoip/geoip2/geolite2/ 

【Java】通过ip地址获取详细地域信息(不通过API使用本地库)

但是好像网站不太稳定,我这边3个都下载好了,可【点击下载】

关于Java如何使用

不用担心,已经有开源库,maven下载一个

<dependency>
	<groupId>com.maxmind.geoip2</groupId>
	<artifactId>geoip2</artifactId>
	<version>2.12.0</version>
</dependency>
           

没有maven,怎么办?不怕,我上传了,可【点击下载】

使用用到的工具类

import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.AsnResponse;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.model.CountryResponse;
import com.maxmind.geoip2.record.City;
import com.maxmind.geoip2.record.Country;
import com.maxmind.geoip2.record.Location;
import com.maxmind.geoip2.record.Postal;
import com.maxmind.geoip2.record.Subdivision;
           

调用ASN

这个是获取自治系统编号的

public static void testAsn(String testIp) throws Exception {
	//GeoIP2数据库文件,把数据库文件直接放d盘下(可以随意喜欢的位置)
	File database = new File("D:/GeoLite2-ASN.mmdb");
				
	// 创建 DatabaseReader对象
    DatabaseReader reader = new DatabaseReader.Builder(database).build();

	InetAddress ipAddress = InetAddress.getByName(testIp);
								 
	AsnResponse response = reader.asn(ipAddress);

	System.out.println(response.getAutonomousSystemOrganization());
	System.out.println(response.getAutonomousSystemNumber());
						
}
           

调用Country

这个是获取Country级别的,数据库文件小很多,速度可以优化很多

public static void testCity(String testIp) throws Exception {
				//GeoIP2数据库文件,把数据库文件直接放d盘下(可以随意喜欢的位置)
				File database = new File("D:/test/ip/GeoLite2-City.mmdb");
				
				// 创建 DatabaseReader对象
				DatabaseReader reader = new DatabaseReader.Builder(database).build();

				InetAddress ipAddress = InetAddress.getByName(testIp);
								
				CityResponse response = reader.city(ipAddress);

				Country country = response.getCountry();
				System.out.println(country.getIsoCode());            // 'US'
				System.out.println(country.getName());               // 'United States'
				System.out.println(country.getNames().get("zh-CN")); // '美国'

				Subdivision subdivision = response.getMostSpecificSubdivision();
				System.out.println(subdivision.getName());    // 'Minnesota'
				System.out.println(subdivision.getIsoCode()); // 'MN'
				System.out.println(subdivision.getNames().get("zh-CN"));

				City city = response.getCity();
				System.out.println(city.getName()); // 'Minneapolis'
				System.out.println(city.getNames().get("zh-CN"));
				
				Postal postal = response.getPostal();
				System.out.println(postal.getCode()); // '55455'

				Location location = response.getLocation();
				System.out.println(location.getLatitude());  // 44.9733
				System.out.println(location.getLongitude()); // -93.2323
	}
           

调用City

这个是获取City级别的,文件相对比较大,看情况使用(不用担心,我们就是这样用的,速度还行暂时)

public static void testCity(String testIp) throws Exception {
				//GeoIP2-City 数据库文件,把数据库文件直接放d盘下(可以随意喜欢的位置)
				File database = new File("D:/test/ip/GeoLite2-City.mmdb");
				
				// 创建 DatabaseReader对象
				DatabaseReader reader = new DatabaseReader.Builder(database).build();

				InetAddress ipAddress = InetAddress.getByName(testIp);
								
				CityResponse response = reader.city(ipAddress);

				Country country = response.getCountry();
				System.out.println(country.getIsoCode());            // 'US'
				System.out.println(country.getName());               // 'United States'
				System.out.println(country.getNames().get("zh-CN")); // '美国'

				Subdivision subdivision = response.getMostSpecificSubdivision();
				System.out.println(subdivision.getName());    // 'Minnesota'
				System.out.println(subdivision.getIsoCode()); // 'MN'
				System.out.println(subdivision.getNames().get("zh-CN"));

				City city = response.getCity();
				System.out.println(city.getName()); // 'Minneapolis'
				System.out.println(city.getNames().get("zh-CN"));
				
				Postal postal = response.getPostal();
				System.out.println(postal.getCode()); // '55455'

				Location location = response.getLocation();
				System.out.println(location.getLatitude());  // 44.9733
				System.out.println(location.getLongitude()); // -93.2323
	}
           

测试模块

public static void main(String[] args) throws Exception {
		
		String testIp="128.101.101.101";
		
        //测试Asn
		testAsn(testIp);
		
		//测试国家
		testCountry(testIp);
		
        //测试城市
		testCity(testIp);

	}
	
           

Ps:如果ip是内网怎么办?不用担心,一定会报错,因为根本不可能找到数据,哈哈

解决方法:把ip先放进去判断是否是内网先再查询,这里我是使用正则表达式,之前发过了,请看【Java】判断IP是否内网(使用正则表达式)