记录根据用户ip地址获取用户所属地
最近有个需求,需要根据用户的登陆ip完成用户所在地。
参考ip2region 最新版本的demo:https://gitee.com/lionsoul/ip2region/tree/master/binding/java
使用的内存读取的方式,代码直接拷贝git上面的demo:
<dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.7.0</version> </dependency>
import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit; public class SearcherTest { public static void main(String[] args) { String dbPath = "ip2region.xdb file path"; // 1、从 dbPath 加载整个 xdb 到内存。 byte[] cBuff; try { cBuff = Searcher.loadContentFromFile(dbPath); } catch (Exception e) { System.out.printf("failed to load content from `%s`: %s\n", dbPath, e); return; } // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。 Searcher searcher; try { searcher = Searcher.newWithBuffer(cBuff); } catch (Exception e) { System.out.printf("failed to create content cached searcher: %s\n", e); return; } // 3、查询 try { String ip = "1.2.3.4"; long sTime = System.nanoTime(); String region = searcher.search(ip); long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime)); System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost); } catch (Exception e) { System.out.printf("failed to search(%s): %s\n", ip, e); } // 4、关闭资源 - 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher // searcher.close(); // 备注:并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。 } }
自己的系统是windows的,把上面的dbPath换成本地的ip2region.xdb的绝对路径,运行测试,一切正常。
但是打包部署到开发环境,发现一直获取为空,并且抛出
failed to search(1.202.31.54): java.lang.ArrayIndexOutOfBoundsException
奇怪了,然后去git上面搜索。
https://gitee.com/lionsoul/ip2region/issues/I7GYFY
根据这个解决了,
原因是:https://github.com/lionsoul2014/ip2region/issues/279
因为maven resources 拷贝文件是默认会做 filter,会导致我们的文件发生变化,导致不能读
顺便拷贝下代码:
package com.gwm.marketing.authcenter.util; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.resource.ResourceUtil; import org.lionsoul.ip2region.xdb.Searcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Component; import org.springframework.util.ResourceUtils; import java.io.*; import java.util.concurrent.TimeUnit; /** * @Author:hongtaofan * @Version:1.0 * @Description: * @Date: 2023/8/2 13:13 */ @Component public class SearcherUtils { @Autowired private ResourceLoader resourceLoader; private static Logger logger = LoggerFactory.getLogger(SearcherUtils.class); public String searchIp(String ip){ try { logger.info("=============start========"); //这个是服务器读取的方式,,如果是本地 windeos可以写绝对路径 Resource resource = resourceLoader.getResource("classpath:ip2region/ip2region.xdb"); if(resource == null || !resource.exists()){ return null; } logger.info("===========resource getUri=========" + resource.getURI()); logger.info("============resource fileName " + resource.getFilename()); //InputStream stream = ResourceUtil.getStream(dbPath); byte[] cBuff = IoUtil.readBytes(resource.getInputStream()); // 1、从 dbPath 加载整个 xdb 到内存。 /*byte[] cBuff; try { cBuff = Searcher.loadContentFromFile(dbPath); } catch (Exception e) { System.out.printf("failed to load content from `%s`: %s\n", dbPath, e); return null; }*/ // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。 Searcher searcher; try { searcher = Searcher.newWithBuffer(cBuff); } catch (Exception e) { logger.error("获取异常",e); System.out.printf("failed to create content cached searcher: %s\n", e); return null; } // 3、查询 try { long sTime = System.nanoTime(); String region = searcher.search(ip); long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime)); System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost); return region; } catch (Exception e) { System.out.printf("failed to search(%s): %s\n", ip, e); } return null; } catch (Exception e) { logger.error("获取地址异常",e); } return null; } /* public static void main(String[] args) { System.out.println(searchIp("121.237.31.134")); System.out.println(searchIp("47.122.18.76")); System.out.println(searchIp("123.114.36.50")); System.out.println(searchIp("35.187.132.16")); System.out.println(searchIp("49.35.162.6")); System.out.println(searchIp("5.188.210.227")); System.out.println(searchIp("64.233.173.10")); System.out.println(searchIp("74.125.151.127")); System.out.println(searchIp("74.125.212.221")); System.out.println(searchIp("95.184.60.224")); // 4、关闭资源 - 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher // searcher.close(); // 备注:并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。 }*/ }
|