近期,国内多平台上线了 IP
归属地功能,国内显示到省份/地区,国外显示到国家。
该功能在技术层面上有两种实现方案:
手机设备端开启 GPS
定位功能,APP
端调用设备能力获取到定位信息。 根据用户访问的 IP
地址获取归属地。 本文主要介绍根据 IP
地址获取归属地的功能实现。
ip2region
Ip2region (2.0 - xdb)
是一个离线 IP
地址管理框架和定位器,支持数十亿数据段,十微秒的搜索性能。提供多种编程语言的 xdb
引擎实现。
GitHub
地址:https://github.com/lionsoul2014/ip2region
maven
依赖1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.lionsoul</groupId > <artifactId > ip2region</artifactId > <version > 2.6.6</version > </dependency > <dependency > <groupId > commons-io</groupId > <artifactId > commons-io</artifactId > <version > 2.11.0</version > </dependency >
拷贝 xdb
数据文件 xdb
数据文件位于 https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.xdb 。下载后将其拷贝至项目的 resources
目录下的 ip2region
文件夹内。
编写工具类 完整用法可查看 https://github.com/lionsoul2014/ip2region/tree/master/binding/java 。下面提供缓存整个 xdb
数据的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 package io.github.llnancy.mojian.log.util;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.FileUtils;import org.apache.commons.lang3.ArrayUtils;import org.apache.commons.lang3.StringUtils;import org.lionsoul.ip2region.xdb.Searcher;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.core.io.support.ResourcePatternResolver;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.util.Objects;@Slf4j public class Ip2regionUtils { private static final String IP2REGION_LOCATION = "ip2region/ip2region.xdb" ; private static final String LOCALHOST_REGION = "内网IP" ; private static final String UNKNOWN_REGION = "未知" ; private static Searcher searcher; static { loadIp2regionXdb(); initSearcher(); } private static void loadIp2regionXdb () { if (Objects.nonNull(searcher)) { return ; } InputStream is = null ; try { ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver (); Resource[] resources = resolver.getResources(IP2REGION_LOCATION); if (ArrayUtils.isEmpty(resources)) { log.warn("ip2region.xdb resource file does not exist." ); return ; } Resource resource = resources[0 ]; is = resource.getInputStream(); File dest = new File (IP2REGION_LOCATION); FileUtils.copyInputStreamToFile(is, dest); } catch (IOException e) { log.warn("init ip2region.xdb error." , e); } finally { try { if (Objects.nonNull(is)) { is.close(); } } catch (IOException ignore) { } } } private static void initSearcher () { try { byte [] buf = Searcher.loadContentFromFile(IP2REGION_LOCATION); searcher = Searcher.newWithBuffer(buf); } catch (IOException e) { log.warn("init ip2region's searcher error." , e); } } @SneakyThrows public static String searchRegion (String ip) { return searcher.search(ip); } public static String searchFriendlyRegion (String ip) { return friendlyRegion(searchRegion(ip)); } public static String friendlyRegion (String region) { if (region.contains(LOCALHOST_REGION)) { return LOCALHOST_REGION; } region = region.replace("|0" , StringUtils.EMPTY) .replace("0|" , StringUtils.EMPTY) .replace("省" , StringUtils.EMPTY); String[] address = region.split("\\|" ); if (ArrayUtils.isEmpty(address)) { return UNKNOWN_REGION; } if (Objects.equals("中国" , address[0 ])) { if (address.length > 1 ) { return address[1 ]; } } else { if (address.length > 1 ) { return buildAddress1(address).toString(); } } return buildAddress0(address).toString(); } private static StringBuilder buildAddress1 (String[] address) { return buildAddress0(address).append(address[1 ]); } private static StringBuilder buildAddress0 (String[] address) { return new StringBuilder ().append(address[0 ]); } @SneakyThrows public static void closeSearcher () { searcher.close(); } }
测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void testIp2region () { String ip = "183.136.182.140" ; String region = Ip2regionUtils.searchRegion(ip); String friendlyRegion = Ip2regionUtils.searchFriendlyRegion(ip); System.out.println(region); System.out.println(friendlyRegion); ip = "67.220.90.13" ; region = Ip2regionUtils.searchRegion(ip); friendlyRegion = Ip2regionUtils.searchFriendlyRegion(ip); System.out.println(region); System.out.println(friendlyRegion); }
运行结果:
1 2 3 4 中国|0|浙江省|杭州市|电信 浙江 美国|0|犹他|盐湖城|0 美国犹他