上篇在本地测试调用Ip2Resigon解析行政区划 Ip2Region的Java本地实现运行正常,但部署到测试环境,抛出数组越界(java.lang.ArrayIndexOutOfBoundsException)异常。
环境信息
ip2Resion是2.7版本,对应文件后缀为 xdb。
一、代码展示
调用解析关键代码如下所示。
@Service
public class Ip2RegionService implements IIp2RegionService {
/**
* 功能:通过ip转化行政区划 并发使用,用整个 xdb 数据缓存创建的查询对象可安全的用于并发,
* 把这个 searcher 对象做成全局对象去跨线程访问。
* @param ip
* @return
*/
@Override
public Ip2RegionCommon getDistrictByIp(String ip) {
logger.info("getDistrictByIp方法入参为:" + ip);
String region = "未解析到位置信息";
// 数据文件路径
String dbPath = this.getClass().getClassLoader().getResource("xdb/ip2region.xdb").getPath();
logger.info("getDistrictByIp获取的dbPath为:" + dbPath);
long startTime = System.currentTimeMillis();
try {
byte[] cBuff = null;
Searcher searcher;
// 1、加载整个 xdb 到内存。
cBuff = Searcher.loadContentFromFile(dbPath);
// 2、创建一个完全基于内存的查询对象。
searcher = Searcher.newWithBuffer(cBuff);
// 3、调用查询方法
region = searcher.search(ip);
long endTime = System.currentTimeMillis();
// 4、关闭资源 - 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher
logger.info("getDistrictByIp解析出来的region为:" + region);
// searcher.close();
logger.info("getDistrictByIp方法执行耗时:" + (endTime - startTime) + "ms");
} catch (Exception e) {
logger.info("getDistrictByIp 执行出错,错误信息为:%s",e.getMessage());
logger.logException("getDistrictByIp 执行出错,错误信息为:%s", e);
}
return this.getReginResult(region);
}
/**
* 功能:转换结果
* 数据格式: 国家|区域|省份|城市|ISP
* 内网IP格式: 0|0|0|内网IP|内网IP
* @param region
* @return
*/
public Ip2RegionCommon getReginResult(String region) {
Ip2RegionCommon info = new Ip2RegionCommon();
if(region.contains("|")) {
String[] split = StringUtils.split(region, "|");
info.setDistrictCountry(split[0]);
info.setDistrictProvince(this.suppleDistrict(split[2]));
info.setDistrictCity(split[3]);
info.setDistrictIsp(split[4]);
}
return info;
}
/**
* 功能:补全省份名称
* @param provinceName
* @return
*/
private String suppleDistrict(String provinceName) {
String province = "省份未知";
switch(provinceName) {
case "北京" :
province = "北京市";
break;
case "天津" :
province = "天津市";
break;
case "上海" :
province = "上海市";
break;
case "重庆" :
province = "重庆市";
break;
case "广西" :
province = "广西壮族自治区";
break;
case "西藏" :
province = "西藏自治区";
break;
case "宁夏" :
province = "宁夏回族自治区";
break;
case "新疆" :
province = "新疆维吾尔自治区";
break;
case "黑龙江" :
province = "黑龙江省";
break;
case "内蒙古" :
province = "内蒙古自治区";
break;
default :
province = provinceName;
}
return province;
}
}
异常信息日志展示如下。
二、问题分析
从打印日志看数据xdb文件读取成功,searcher对象创建成功,进入search方法里,在arraycopy时报错。
猜想是Java启动时给的内存不足,加大内存未见好使;
取到ip地址在本地单元测试执行,顺利解析,应该不是ip地址的问题;
再次想会不会只是创建了searcher对象,没有读取到内容呢?于是在网上继续查找,终于看到码云上有说少配置,详细可见参考文档。
maven resources 拷贝文件是默认会做 filter,会导致数据文件发生变化,导致文件不能被读。
三、处理方案
明确原因后,在Java打包的pom文件中添加以下内容。指定 nonFilteredFileExtension 格式为xdb,问题解决。
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xdb</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
参考文档
【1】https://gitee.com/596392912/mica/blob/master/mica-ip2region/README.md