离线IP地址定位库主要用于内网或想减少对外访问http带来的资源消耗。本博客使用的是ip2region + 在线获取。

Maven

<!-- 离线IP地址定位库 -->
<dependency>
    <groupId>org.lionsoul</groupId>
    <artifactId>ip2region</artifactId>
    <version>1.7.2</version>
</dependency>

AddressUtils

import com.alibaba.fastjson.JSONObject;
import com.xffjs.common.utils.http.HttpUtils;
import com.xffjs.framework.config.SystemConfig;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.io.ResourceUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Method;

/**
 * @className: AddressUtils
 * @description: ip地址获取位置工具类
 * @author: xiaofei
 * @create: 2021年04月11日
 */
public class AddressUtils {

    private final static Logger LOGGER = LoggerFactory.getLogger(AddressUtils.class);

    /**
     * {"country":"中国","province":"河南","city":"北京","isp":"移动","ip":"xxx"}
     */
    public static final String IP_URL4 = "http://ip.huomao.com/ip";

    /**
     * 根据ip获取位置
     *
     * @param ip
     * @return 国家|区域|省份|城市|ISP_
     */
    public static String getRealAddressByIp(String ip) {
        long startTime = System.currentTimeMillis();
        String address = "";
        // 内网不查询
        if (IpUtils.internalIp(ip)) {
            return "内网IP";
        }
        address = getRegion(ip);
        if (StringUtils.isEmpty(address)) {
            if (SystemConfig.isAddressEnabled()) {
                String rspStr = HttpUtils.sendPost(IP_URL4, "ip=" + ip);
                if (StringUtils.isEmpty(rspStr)) {
                    LOGGER.error("获取地理位置异常 {}", ip);
                    return address;
                }
                JSONObject obj = JSONObject.parseObject(rspStr);
                String country = obj.getString("country");
                String region = obj.getString("province");
                String city = obj.getString("city");
                String isp = obj.getString("isp");
                if (address.equals(region) && address.equals(city)) {
                    return obj.getString("country") + obj.getString("isp") + "流量";
                }
                address = country + "|" + "999|" + region + "|" + city + "|" + isp;
            }
        }
        long endTime = System.currentTimeMillis();
        LOGGER.debug("获取ip位置耗时:[{}] ", endTime - startTime);
        return address;
    }


    //********************************* 根据ip离线查询地址Star ***********************************************************

    /**
     * 根据ip离线查询地址
     */
    private static final String JAVA_TEMP_DIR = "java.io.tmpdir";
    static DbConfig config = null;
    static DbSearcher searcher = null;

    /**
     * 离线根据ip获取位置
     *
     * @param ip
     * @return 国家|区域|省份|城市|ISP_
     */
    public static String getRegion(String ip) {
        try {
            String dbPath = AddressUtils.class.getResource("/ip2region/ip2region.db").getPath();
            File file = new File(dbPath);
            if (!file.exists()) {
                String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR);
                dbPath = tmpDir + "ip2region.db";
                file = new File(dbPath);
                String classPath = "classpath:ip2region/ip2region.db";
                InputStream resourceAsStream = ResourceUtils.getInputStreamForPath(classPath);
                if (resourceAsStream != null) {
                    FileUtils.copyInputStreamToFile(resourceAsStream, file);
                }
            }
            config = new DbConfig();
            searcher = new DbSearcher(config, dbPath);
            // db
            if (searcher == null || StringUtils.isEmpty(ip)) {
                LOGGER.error("DbSearcher is null");
                return StringUtils.EMPTY;
            }
            // 查询算法
            int algorithm = DbSearcher.MEMORY_ALGORITYM;
            Method method = null;
            // memory算法、binary算法、b-tree算法
            switch (algorithm) {
                case DbSearcher.BTREE_ALGORITHM:
                    method = searcher.getClass().getMethod("btreeSearch", String.class);
                    break;
                case DbSearcher.BINARY_ALGORITHM:
                    method = searcher.getClass().getMethod("binarySearch", String.class);
                    break;
                case DbSearcher.MEMORY_ALGORITYM:
                    method = searcher.getClass().getMethod("memorySearch", String.class);
                    break;
            }
            DataBlock dataBlock = null;
            if (Util.isIpAddress(ip) == false) {
                LOGGER.warn("warning: Invalid ip address");
            }
            dataBlock = (DataBlock) method.invoke(searcher, ip);
            String result = dataBlock.getRegion();
            return result;
        } catch (Exception e) {
            LOGGER.error("error:{}", e);
        }
        return StringUtils.EMPTY;
    }

    //********************************* 根据ip离线查询地址End ***********************************************************

}