根据IP解析登录地点

  • 最近在做登录日志时需要记录账号登录的地址,通过网上搜索资料,找到两种方法:
  • 第一种是通过调用第三方接口来对IP进行解析,返回IP对应的地址,主要有taobao的接口以及新浪的接口;调用第三方的API查询的结果比较准确,但是有限制,新浪的接口我没跑通,淘宝的API并发数不能大于1QPS,百度的要收费;而且第三方的服务不稳定【写这篇博客时,我只跑通了一次】,随时可能出现问题;这是淘宝返回的数据结构:
{
    "code": 0,
    "data": {
        "ip": "219.136.134.157",
        "country": "中国",
        "area": "",
        "region": "广东",
        "city": "广州",
        "county": "XX",
        "isp": "电信",
        "country_id": "CN",
        "area_id": "",
        "region_id": "440000",
        "city_id": "440100",
        "county_id": "xx",
        "isp_id": "100017"
    }
}
  • 第二种是下载开源的库到本地,在本地调用API进行查询;本地查询就不限制查询次数以及并发量了,但是信息的准确性上要差一些。这是本地库返回的数据结构:
{
    "city": {"names": {}},
    "continent": {
        "code": "NA",
        "geoNameId": 6255149,
        "name": "North America",
        "names": {
            "de": "Nordamerika",
            "ru": "Северная Америка",
            "pt-BR": "América do Norte",
            "ja": "北アメリカ",
            "en": "North America",
            "fr": "Amérique du Nord",
            "zh-CN": "北美洲",
            "es": "Norteamérica"
        }
    },
    "country": {
        "geoNameId": 6252001,
        "isoCode": "US",
        "name": "United States",
        "names": {
            "de": "USA",
            "ru": "США",
            "pt-BR": "Estados Unidos",
            "ja": "アメリカ合衆国",
            "en": "United States",
            "fr": "États-Unis",
            "zh-CN": "美国",
            "es": "Estados Unidos"
        }
    },
    "leastSpecificSubdivision": {"names": {}},
    "location": {
        "accuracyRadius": 1000,
        "latitude": 37.751,
        "longitude": -97.822
    },
    "maxMind": {},
    "mostSpecificSubdivision": {"names": {}},
    "postal": {},
    "registeredCountry": {
        "geoNameId": 6252001,
        "isoCode": "US",
        "name": "United States",
        "names": {
            "de": "USA",
            "ru": "США",
            "pt-BR": "Estados Unidos",
            "ja": "アメリカ合衆国",
            "en": "United States",
            "fr": "États-Unis",
            "zh-CN": "美国",
            "es": "Estados Unidos"
        }
    },
    "representedCountry": {"names": {}},
    "subdivisions": [],
    "traits": {
        "anonymousProxy": false,
        "ipAddress": "192.16.0.216",
        "legitimateProxy": false,
        "satelliteProvider": false
    }
}

2019/02/26更新

  • 我使用的是本地解析IP的方式,在把项目部署到服务器上去之前,又测试了一下,发现启动报错了:java.io.FileNotFoundException;然后就开始找问题,我之前是直接从IDEA上面拷贝的相对路径,直接拿过来用,现在报错了。用绝对路径是可以的,但是部署项目的时候不太方便,我选择把GeoLite2-City.mmdb文件放到项目中的resources/lib目录下,但是始终读取不到,然后我想去找这个异常是从哪里抛出来的,然后开始看源码,从build()方法开始进入:
// 这是我的代码
reader = new DatabaseReader.Builder(database).build();

// 这是DatabaseReader类的源码,DatabaseReader类里面有一个静态内部类Builder,这是内部类的构造函数
/**
 * @param database the GeoIP2 database file to use.
 */
public Builder(File database) {
    this.database = database;
    this.stream = null;
}

// 这是调用内部类的build()方法,这里面调用了DatabaseReader类的构造函数,获取到了对象,继续跟进
/**
 * @return an instance of {@code DatabaseReader} created from the
  * fields set on this builder.
  * @throws IOException if there is an error reading the database
  */
 public DatabaseReader build() throws IOException {
     return new DatabaseReader(this);
 }

// 这个是DatabaseReader的构造函数,在这里发现了问题
private DatabaseReader(Builder builder) throws IOException {
   if (builder.stream != null) {
        this.reader = new Reader(builder.stream, builder.cache);
    } else if (builder.database != null) {
    	// 最开始,异常是从这里抛出来的,然后我就想试试上面那一个构造函数
        this.reader = new Reader(builder.database, builder.mode, builder.cache);
    } else {
        // This should never happen. If it does, review the Builder class
        // constructors for errors.
        throw new IllegalArgumentException(
                "Unsupported Builder configuration: expected either File or URL");
    }
    this.om = new ObjectMapper();
    this.om.configure(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
    this.om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
            false);
    this.om.configure(
            DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
    this.locales = builder.locales;
}

// 然后我自己创建了一个输入流,这里直接就报错了,然后我想到可能是路径的问题了
FileInputStream inputStream = new FileInputStream(dbPath);
  • 源码就看到这里我就没看了,然后就开始找解决方法,将原路径private static String dbPath = “/lib/GeoLite2-City.mmdb”;修改为private static String dbPath = “./casanova-global/src/main/resources/lib/GeoLite2-City.mmdb”;之后,问题就解决了。
  • 此外,在看源码之前还想了一些解决方法,这里还找到几种读取文件的方法,看代码:
// 方式一:配置文件配置,这是资料里写好的
String path = env.getProperty("geolite2.city.db.path");
if (StringUtils.isNotBlank(path)) {
    dbPath = path;
}
File database = new File(dbPath);

// 配置文件application.properties
geolite2.city.db.path=E:/project/casanova_master_12_13/casanova_backend/casanova-global/src/main/resources/lib/GeoLite2-City.mmdb

// 方式二:将文件的绝对路径打印出来,然后获取当前路径,再拼接出文件实际的绝对路径
// E:\project\casanova_master_12_13\casanova_backend\casanova-global\src\main\resources\lib\GeoLite2-City.mmdb
String absoluteFile = database.getAbsolutePath();
String substring = absoluteFile.substring(0, absoluteFile.indexOf("\\lib"));
System.out.println(absoluteFile);
System.out.println(substring);
database = new File(substring + "\\casanova-global\\src\\main\\resources\\lib\\GeoLite2-City.mmdb");

// 方式三:使用ResourceUtils获取文件
File file1 = ResourceUtils.getFile("classpath:lib");
if (file1.exists()) {
    File[] files = file1.listFiles();
    if (files != null) {
        for (File file2 : files) {
            if (file2.getName().endsWith(".mmdb")) {
                database = file2;
            }
        }
    }
}

资料中的TIPS: 使用相对路径的时候,最好用System.out.println(new File(".").getAbsolutePath());打印出来看看当前的路径,再判断相对路径是否使用正确。

  • 嗯,上传到服务器还是不行,SpringBoot+Maven打包,变成jar包之后,整个文件的结构都变了,而且在Linux系统中,文件的路径会变,比如说classes文件夹变成了classes!,然后就找不到文件了,花了好几个小时去找资料,然后尝试,终于还是让我读到了,以下是尝试的代码(手动行号,hiahiahia)和服务器的日志:
51	logger.info("====================================");
52	logger.info(new File("GeoIPService.class").getAbsolutePath());
	String ss = this.getClass().getResource("/").getPath();
54	logger.info(ss);
55	logger.info(new File(ss).getParentFile().getPath());
56	logger.info(System.getProperty("user.dir"));
57	logger.info("====================================");
58	logger.info("/目录:" + FileResourceLoader.class.getResource("/").getPath());
	try {
	    InputStream resource = new FileInputStream(FileResourceLoader.class.getResource("/").getPath() + "lib/GeoLite2-City.mmdb");
61	    logger.info("=============读取成功================");
	} catch (Exception e) {
63	    logger.info("=============读取失败================");
	}
	
66	logger.info("/目录:  "+ FileResourceLoader.class.getResource("").getPath());
67	logger.info("/library目录:  "+ FileResourceLoader.class.getResource("/lib").getPath());
	try {
	    InputStream resource = new FileInputStream(FileResourceLoader.class.getResource("/lib").getPath() + "/GeoLite2-City.mmdb");
	    logger.info("=============读取成功================");
	} catch (Exception e) {
72	    logger.info("=============读取失败================");
	}
	
75	logger.info("====================================");
	
	try {
	    InputStream resource = FileResourceLoader.class.getResourceAsStream("/lib/GeoLite2-City.mmdb");
79	    logger.info("=============读取成功================");
	} catch (Exception e) {
	    logger.info("=============读取失败================");
	}
  • 日志:
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:51] ==> ====================================
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:52] ==> /GeoIPService.class
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:54] ==> file:/app.jar!/BOOT-INF/classes!/
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:55] ==> file:/app.jar!/BOOT-INF
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:56] ==> /
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:57] ==> ====================================
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:58] ==> /目录:file:/app.jar!/BOOT-INF/classes!/
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:63] ==> =============读取失败================
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:66] ==> /目录:  file:/app.jar!/BOOT-INF/lib/xmlbeans-2.6.0.jar!/org/apache/xmlbeans/impl/schema/
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:67] ==> /library目录:  file:/app.jar!/BOOT-INF/classes!/lib
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:72] ==> =============读取失败================
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:75] ==> ====================================
[2019-02-26 15:57:04] [main] [INFO ] [类:BaseLoggerService 方法:init 行:79] ==> =============读取成功================

参考资料:
1.Java 通过Request请求获取IP地址对应省份、城市
2.通过GeoIP2分析访问者IP获取地理位置信息
3.java 根据IP地址获取地理位置
4.springboot-项目获取resources下文件的方法
5.获取jar包内部的资源文件
6.java中jar包内的类访问jar包内部的资源文件路径和获得读取资源文件内容的问题

发布了24 篇原创文章 · 获赞 14 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/biubiu2it/article/details/87905619