今天在做系统日志的功能时,需要根据ip获取客户端的归属地,于是决定使用ip2region工具来实现,但是在实际使用过程中(使用场景见springboot+aop+线程池+ip2region+mybatisplus实现异步系统日志记录),遇到了两个坑
1.程序正常运行,测试环境根据正常ip获取到的归属地全部为未知位置,同样的ip地址在本地测试获取到的却是正常归属地
2.解决坑1之后,又莫名其妙出现searcher.btreeSearch(ip)报空指针异常。
先说解决方案(最终版代码可到文末去取):
- 如果是springboot项目,用IpUtils.class.getClassLoader().getResourceAsStream(“ip2region.db”)代替IpUtils.class.getResource(“/ip2region.db”).getPath(),因此创建DbSearcher对象用DbSearcher(DbConfig
dbConfig, byte[] dbBinStr)而不是DbSearcher( DbConfig dbConfig, String
dbFile ) - 用memorySearch算法,而不是binarySearch算法和btreeSearch算法
接下来,踩坑和解决历程且听我娓娓道来。。。
问题探索历程
首先引入ip2region依赖
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
下载ip2region.db文件将他放到项目的resources目录下
编写IpUtils工具类
public final class IpUtils {
private static final String UNKOWN_ADDRESS = "未知位置";
/**
* 根据IP获取地址
*
* @return 国家|区域|省份|城市|ISP
*/
public static String getAddress(String ip) throws Exception {
return getAddress(ip, DbSearcher.BTREE_ALGORITHM);
}
public static String getAddress(String ip, int algorithm) throws Exception {
if (!Util.isIpAddress(ip)) {
return UNKOWN_ADDRESS;
}
String dbPath = IpUtils.class.getResource("/ip2region.db").getPath();
File file = new File(dbPath);
if (!file.exists()) {
return UNKOWN_ADDRESS;
}
DbSearcher searcher = new DbSearcher(new DbConfig(), dbPath);
DataBlock dataBlock;
switch (algorithm) {
case DbSearcher.BTREE_ALGORITHM:
dataBlock = searcher.btreeSearch(ip);
break;
case DbSearcher.BINARY_ALGORITHM:
dataBlock = searcher.binarySearch(ip);
break;
case DbSearcher.MEMORY_ALGORITYM:
dataBlock = searcher.memorySearch(ip);
break;
default:
return UNKOWN