package com.ruoyi.common.utils.ip; import java.io.InputStream; import org.lionsoul.ip2region.service.Config; import org.lionsoul.ip2region.service.Ip2Region; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.utils.StringUtils; /** * ip2region 离线 IP 归属地查询工具。 */ public final class Ip2RegionUtils { private static final Logger log = LoggerFactory.getLogger(Ip2RegionUtils.class); private static final String XDB_CLASSPATH = "/ip2region/ip2region_v4.xdb"; private static volatile Ip2Region ip2Region; private static volatile boolean initAttempted; private Ip2RegionUtils() { } /** * 查询 IP 归属地原始字符串,格式:Country|Province|City|ISP|Code。 */ public static String searchRegion(String ip) { if (StringUtils.isEmpty(ip)) { return null; } Ip2Region service = getIp2Region(); if (service == null) { return null; } try { return service.search(ip.trim()); } catch (Exception ex) { log.warn("ip2region 查询失败 ip={}: {}", ip, ex.getMessage()); return null; } } /** * 从 ip2region 结果中提取可用于区县展示的名称。 */ public static String extractDistrictName(String region) { if (StringUtils.isEmpty(region)) { return null; } String[] parts = region.split("\\|"); String city = parts.length > 2 ? nullIfZero(parts[2]) : null; String province = parts.length > 1 ? nullIfZero(parts[1]) : null; String country = parts.length > 0 ? nullIfZero(parts[0]) : null; return firstNonEmpty(city, province, country); } private static Ip2Region getIp2Region() { if (!initAttempted) { synchronized (Ip2RegionUtils.class) { if (!initAttempted) { initAttempted = true; ip2Region = createIp2Region(); } } } return ip2Region; } private static Ip2Region createIp2Region() { try (InputStream inputStream = Ip2RegionUtils.class.getResourceAsStream(XDB_CLASSPATH)) { if (inputStream == null) { log.warn("ip2region 数据库未找到: {}", XDB_CLASSPATH); return null; } Config v4Config = Config.custom() .setCachePolicy(Config.BufferCache) .setXdbInputStream(inputStream) .asV4(); return Ip2Region.create(v4Config, null); } catch (Exception ex) { log.error("ip2region 初始化失败", ex); return null; } } private static String nullIfZero(String value) { if (StringUtils.isEmpty(value) || "0".equals(value.trim())) { return null; } return value.trim(); } private static String firstNonEmpty(String... values) { if (values == null) { return null; } for (String value : values) { if (StringUtils.isNotEmpty(value)) { return value; } } return null; } }