mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 14:56:06 +08:00
refactor(ip-region): 移除 ip2region 旧版区域字段兼容, 统一 v4.xdb 五段格式并补单测
This commit is contained in:
@@ -64,10 +64,10 @@ public class IpRegionDemoController {
|
||||
IpRegion region = ipToRegionService.getRegionByIp(ip);
|
||||
if (Objects.nonNull(region)) {
|
||||
result.setCountry(region.getCountry())
|
||||
.setRegion(region.getRegion())
|
||||
.setProvince(region.getProvince())
|
||||
.setCity(region.getCity())
|
||||
.setIsp(region.getIsp())
|
||||
.setCountryCode(region.getCountryCode())
|
||||
.setInnerIp(region.isInnerIp())
|
||||
.setChinaIp(region.isChinaIp());
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ public class IpRegionDemoResult {
|
||||
/// 国家
|
||||
private String country;
|
||||
|
||||
/// 区域
|
||||
private String region;
|
||||
|
||||
/// 省份
|
||||
private String province;
|
||||
|
||||
@@ -29,6 +26,9 @@ public class IpRegionDemoResult {
|
||||
/// ISP 运营商
|
||||
private String isp;
|
||||
|
||||
/// 国家码(iso-alpha2, 如 CN/HK/US)
|
||||
private String countryCode;
|
||||
|
||||
/// 格式化后的归属地文本(与审计日志 location 字段同源)
|
||||
private String regionStr;
|
||||
|
||||
|
||||
@@ -71,6 +71,13 @@
|
||||
<artifactId>common-translate</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 测试包 -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.List;
|
||||
|
||||
/// # IP对应地址区域信息
|
||||
///
|
||||
/// 官方 ip2region v4.xdb 数据格式: `国家|省份|城市|ISP|国家码(iso-alpha2)`, 五段定长。
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class IpRegion {
|
||||
@@ -17,18 +18,18 @@ public class IpRegion {
|
||||
/// 国家
|
||||
private String country;
|
||||
|
||||
/// 区域
|
||||
private String region;
|
||||
|
||||
/// 省份
|
||||
private String province;
|
||||
|
||||
/// 城市
|
||||
private String city;
|
||||
|
||||
/// ISP
|
||||
/// ISP 运营商
|
||||
private String isp;
|
||||
|
||||
/// 国家码(iso-alpha2, v4 末尾段, 如 CN/HK/US)
|
||||
private String countryCode;
|
||||
|
||||
/// 是否内网地址
|
||||
public boolean isInnerIp(){
|
||||
return "内网IP".equals(isp);
|
||||
@@ -40,30 +41,51 @@ public class IpRegion {
|
||||
}
|
||||
|
||||
/// 是否国内直辖市
|
||||
///
|
||||
/// v4 数据省名可能带"市"后缀(如"北京市"), 归一化后比对, 与 GeoFenceUtil.normalizeRegionName 口径一致
|
||||
public boolean isProvinceLevel(){
|
||||
return "中国".equals(country)&&
|
||||
PROVINCE_LEVEL_CITY.contains(province);
|
||||
PROVINCE_LEVEL_CITY.contains(normalizeName(province));
|
||||
}
|
||||
|
||||
/// 是否港澳台
|
||||
public boolean isBigChina(){
|
||||
return "中国".equals(country)&&
|
||||
BIG_CHINA.contains(province);
|
||||
BIG_CHINA.contains(normalizeName(province));
|
||||
}
|
||||
|
||||
/// 国家|区域|省份|城市|ISP
|
||||
/// 官方 v4.xdb 格式: 国家|省份|城市|ISP|国家码
|
||||
///
|
||||
/// 防御性取值: 记录段数可能不足(国外/内网等短记录), 逐段判空, 不足不抛异常
|
||||
public static IpRegion init(List<String> ipInfo){
|
||||
IpRegion ipRegion = new IpRegion();
|
||||
if (CollUtil.isEmpty(ipInfo)){
|
||||
return ipRegion;
|
||||
}
|
||||
ipRegion.country = ipInfo.get(0);
|
||||
ipRegion.region = ipInfo.get(1);
|
||||
ipRegion.province = ipInfo.get(2);
|
||||
ipRegion.city = ipInfo.get(3);
|
||||
ipRegion.isp = ipInfo.get(4);
|
||||
ipRegion.country = safeGet(ipInfo, 0);
|
||||
ipRegion.province = safeGet(ipInfo, 1);
|
||||
ipRegion.city = safeGet(ipInfo, 2);
|
||||
ipRegion.isp = safeGet(ipInfo, 3);
|
||||
ipRegion.countryCode = safeGet(ipInfo, 4);
|
||||
|
||||
return ipRegion;
|
||||
|
||||
}
|
||||
|
||||
/// 安全取值: 越界返回 null 而非抛异常
|
||||
private static String safeGet(List<String> ipInfo, int index) {
|
||||
return index < ipInfo.size() ? ipInfo.get(index) : null;
|
||||
}
|
||||
|
||||
/// 归一化地区名: 去首尾空格, 去掉结尾一个"市"或"省"
|
||||
private static String normalizeName(String name) {
|
||||
if (name == null) {
|
||||
return "";
|
||||
}
|
||||
String result = name.trim();
|
||||
if (result.endsWith("市") || result.endsWith("省")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public class IpToRegionService {
|
||||
}
|
||||
|
||||
try {
|
||||
// 城市Id|国家|区域|省份|城市|ISP
|
||||
// 官方 v4.xdb 格式: 国家|省份|城市|ISP|国家码(iso-alpha2)
|
||||
String search = searcher.search(ip);
|
||||
List<String> ipInfo = StrUtil.split(search, "|");
|
||||
return IpRegion.init(ipInfo);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package cn.daxpay.open.platform.capability.audit.log.service.ip2region;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/// # IpRegion 解析单元测试
|
||||
///
|
||||
/// 锁定官方 ip2region v4.xdb 五段格式 `国家|省份|城市|ISP|国家码` 的字段映射,
|
||||
/// 防止再次退化为旧版 v2/v3 的 `国家|区域|省份|城市|ISP` 错位解析。
|
||||
class IpRegionTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("v4 标准五段记录: 字段映射正确")
|
||||
void init_standardV4Record_shouldMapFields() {
|
||||
// 国家|省份|城市|ISP|国家码
|
||||
IpRegion region = IpRegion.init(List.of("中国", "山东省", "济南市", "电信", "CN"));
|
||||
|
||||
assertEquals("中国", region.getCountry());
|
||||
assertEquals("山东省", region.getProvince());
|
||||
assertEquals("济南市", region.getCity());
|
||||
assertEquals("电信", region.getIsp());
|
||||
assertEquals("CN", region.getCountryCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空记录: 返回空对象不抛异常")
|
||||
void init_emptyList_shouldReturnBlank() {
|
||||
IpRegion region = IpRegion.init(List.of());
|
||||
|
||||
assertNull(region.getCountry());
|
||||
assertNull(region.getProvince());
|
||||
assertNull(region.getCity());
|
||||
assertNull(region.getIsp());
|
||||
assertNull(region.getCountryCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("短记录(3段): 防御取值, 后段为 null 不抛异常")
|
||||
void init_shortRecord_shouldNotThrow() {
|
||||
IpRegion region = IpRegion.init(List.of("中国", "山东省", "济南市"));
|
||||
|
||||
assertEquals("中国", region.getCountry());
|
||||
assertEquals("山东省", region.getProvince());
|
||||
assertEquals("济南市", region.getCity());
|
||||
assertNull(region.getIsp());
|
||||
assertNull(region.getCountryCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("国内普通城市: isChinaIp=true, isProvinceLevel=false")
|
||||
void isChinaIp_normalCity_shouldPass() {
|
||||
IpRegion region = IpRegion.init(List.of("中国", "山东省", "济南市", "电信", "CN"));
|
||||
|
||||
assertTrue(region.isChinaIp());
|
||||
assertFalse(region.isProvinceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("直辖市(省名带市后缀): isProvinceLevel 归一化后识别")
|
||||
void isProvinceLevel_directCityWithSuffix_shouldDetect() {
|
||||
// v4 数据省名可能带"市"后缀
|
||||
IpRegion region = IpRegion.init(List.of("中国", "北京市", "北京", "电信", "CN"));
|
||||
|
||||
assertTrue(region.isProvinceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("港澳台: isBigChina 识别")
|
||||
void isBigChina_hk_shouldDetect() {
|
||||
IpRegion region = IpRegion.init(List.of("中国", "香港", "香港", "HKT", "HK"));
|
||||
|
||||
assertTrue(region.isBigChina());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user