记录根据用户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 对象做成全局对象去跨线程访问。
    }*/

}

 

 

 

 

 

 
 
 
posted @ 2023-08-03 17:40  Doyourself!  阅读(160)  评论(0编辑  收藏  举报