demo源代码:https://github.com/CrownP/geolite2_demo

一、需求

通过输入一个IP地址,解析并获取信息,比如国家、国家代码、省份、省份代码、城市、邮政编码、经纬度等等信息

例如,解析ip(128.101.101.101)的信息如下:

 

二、实现形式

使用在线第三方提供的api:

  • ip-api.com
  • ip.taotao.com
  • 百度地图api
  • 新浪 iplookup

使用离线查询方式:

  • 纯真库
  • GeoLite2
  • 埃文科技

数据丰富度对比:

查询准确率比较:


查询速度比较:

 

总结:
       需要速度用离线,需要准确率用在线,需要数据丰富性GeoLite2、埃文科技,需要免费用GeoLite2(埃文科技虽说国内头头,奈何收费)


 

三、Java使用GeoLite2教程

1、官网下载离线的IP数据文件

https://dev.maxmind.com/geoip/geoip2/geolite2/

下载City的mmdb数据文件,较于其他两者信息更丰富。

这三种离线数据包都是免费的,相对应的也有收费版本 Geo-IP2,提供更准确更详细的信息,如果需要解析获取IPS则需要用到收费版本,如下,提供了7种不同的离线数据文件:

2、使用参照收费版的geo-ip2文档说明

提供了多种语言使用,https://dev.maxmind.com/geoip/geoip2/downloadable/#MaxMind_APIs

 

3、Java使用GeoLite2教程

demo源代码:https://github.com/CrownP/geolite2_demo

添加maven依赖

<!-- GeoLite2依赖 -->
<dependency>
    <groupId>com.maxmind.geoip2</groupId>
    <artifactId>geoip2</artifactId>
    <version>2.12.0</version>
</dependency>

封装IP解析后的数据实体

package com.qgp.my_demo.GeoLite2Demo;
import lombok.Data;

/**
 * @ClassName IPEntity
 * @Author qgp
 * @Date 2019/9/24 17:50
 **/
@Data
public class IPEntity {

    //国家
    String countryName;
    //国家代码
    String countryCode;

    //省份
    String provinceName;
    String provinceCode;

    //城市名称
    String cityName;

    //邮政编码
    String postalCode;

    //经度
    Double longitude;
    //纬度
    Double latitude;

}

编写解析IP的工具方法,GeoLite2-City.mmdb数据文件放在resources目录下,通过InputStream流式读取,保证了,打包成Jar包部署服务器后,依然能读取文件。

/**
 * @ClassName IPUtils
 * @Author qgp
 * @Date 2019/9/24 17:51
 **/
public class IPUtils {
    private static Logger logger = LoggerFactory.getLogger(IPUtils.class);

    /**
     * 全局静态变量,DatabaseReader,保证类加载时加载一次
     */
    private static DatabaseReader reader;

    /**
     * 静态代码块,保证项目启动只获取一次文件
     */
    static {

        File database = null;

        try {
            //绝对路径读取文件方式
            //database = new File("F:\\IDEA project\\my_demo\\src\\main\\resources\\GeoLite2-City.mmdb");  

            // 通过 InputStream 流式读取文件,目的解决无法通过File方式读取jar包内的文件的问题·1
            database = getFile("GeoLite2-City.mmdb","geolite2.mmdb");
            logger.info("-------加载文件");
            reader = new DatabaseReader.Builder(database).build();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 解析IP
     * @param ip
     * @return
     */
    public static IPEntity getIPMsg(String ip){

        IPEntity msg = new IPEntity();

        try {
            InetAddress ipAddress = InetAddress.getByName(ip);
            CityResponse response = reader.city(ipAddress);
            Country country = response.getCountry();
            Subdivision subdivision = response.getMostSpecificSubdivision();
            City city = response.getCity();
            Postal postal = response.getPostal();
            Location location = response.getLocation();

            msg.setCountryName(country.getNames().get("zh-CN"));
            msg.setCountryCode(country.getIsoCode());
            msg.setProvinceName(subdivision.getNames().get("zh-CN"));
            msg.setProvinceCode(subdivision.getIsoCode());
            msg.setCityName(city.getNames().get("zh-CN"));
            msg.setPostalCode(postal.getCode());
            //经度
            msg.setLongitude(location.getLongitude());
            //纬度
            msg.setLatitude(location.getLatitude());

        } catch (IOException e) {
            e.printStackTrace();
        } catch (GeoIp2Exception e) {
            e.printStackTrace();
        }

        return msg;
    }


    /**
     * 读取classpath下的文件
     * @param fileName 原文件全名
     * @param newFileName  缓存的新文件的名称
     * @return
     * @throws IOException
     */
    public static File getFile(String fileName, String newFileName) throws IOException {
        //读取 ClassPath 路径下指定资源的输入流
        ClassPathResource resource = new ClassPathResource(fileName);
        InputStream inputStream = resource.getInputStream();

        File file = new File(newFileName);

        inputstreamToFile(inputStream, file);

        return file;
    }

    /**
     * InputStream -> File
     * @param inputStream
     * @param file
     */
    private static void inputstreamToFile(InputStream inputStream,File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

参考文章:https://zhuanlan.zhihu.com/p/55075356

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐