Java實現(xiàn)通過IP計算分析歸屬地實例分享
在產品中可能存在不同客戶端,請求同一個服務端接口的場景。
例如小程序和App或者瀏覽器中,如果需要對請求的歸屬地進行分析,前提是需要先獲取請求所在的國家或城市,這種定位通常需要主動授權,而用戶一般是不愿意提供的,就需要通過請求的IP來進行歸屬地計算。
IP地址一般分為兩種,IPV4和IPV6,相應的計算方式也有差異,以國家維度來參考,每個國家都有對應的網(wǎng)段范圍,計算網(wǎng)段中的最小和最大IP地址的對應數(shù)值,然后對比請求的IP地址,來判斷屬于哪個國家的網(wǎng)段范圍。
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.util.StrUtil;
import java.math.BigInteger;
import java.net.InetAddress;
public class IpCalculate {
public static void main(String[] args) throws Exception {
// IPv4 網(wǎng)段
String ipv4Network = "IPv4 網(wǎng)段";
String[] ipv4Param = StrUtil.splitToArray(ipv4Network, "/");
// IPv4 起始和結束IP
String ipv4StartIp = Ipv4Util.getBeginIpStr(ipv4Param[0],Integer.parseInt(ipv4Param[1]));
String ipv4OverIp = Ipv4Util.getEndIpStr(ipv4Param[0],Integer.parseInt(ipv4Param[1]));
System.out.println(ipv4StartIp);
System.out.println(ipv4OverIp);
// IPv4 起始和結束IP對應的Long值
System.out.println(Ipv4Util.ipv4ToLong(ipv4StartIp));
System.out.println(Ipv4Util.ipv4ToLong(ipv4OverIp));
// IPv6 網(wǎng)段
String ipv6Network = "IPv6 網(wǎng)段";
String[] ipv6Param =ipv6Network.split("/");
int prefixLength = Integer.parseInt(ipv6Param[1]);
// IPv6 起始和結束IP
InetAddress baseAddress = InetAddress.getByName(ipv6Param[0]);
BigInteger baseValue = new BigInteger(1, baseAddress.getAddress());
BigInteger mask = BigInteger.ONE.shiftLeft(128).subtract(BigInteger.ONE)
.shiftRight(128 - prefixLength).shiftLeft(128 - prefixLength);
BigInteger minIp = baseValue.and(mask);
BigInteger maxIp = minIp.add(BigInteger.ONE.shiftLeft(128 - prefixLength).subtract(BigInteger.ONE));
System.out.println(toIPv6String(minIp));
System.out.println(toIPv6String(maxIp));
// IPv6 起始和結束IP對應的Long值
System.out.println(minIp);
System.out.println(maxIp);
}
private static String toIPv6String(BigInteger value) throws Exception {
byte[] bytes = value.toByteArray();
byte[] ipv6Bytes = new byte[16];
int start = bytes.length > 16 ? bytes.length - 16 : 0;
int length = Math.min(bytes.length, 16);
System.arraycopy(bytes, start, ipv6Bytes, 16 - length, length);
return InetAddress.getByAddress(ipv6Bytes).getHostAddress();
}
}
不過網(wǎng)段地址和國家的對應關系需要進行維護,如果歸屬地分析不需要非常精準,可以直接使用開源的字典庫,比如使用比較多的就是GeoIP2組件。
<dependency> <groupId>com.maxmind.geoip2groupId> <artifactId>geoip2</artifactId> </dependency>
通過組件中提供的API加載相應的文件字典,然后傳入IP地址進行歸屬地判斷,這里要注意爭議和敏感地區(qū)的處理,如果出錯產品可不止是上熱搜的問題了。
import com.maxmind.geoip2.DatabaseReader;
import java.io.File;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
public class GeoIpTool {
public static void main(String[] args) throws Exception {
// 讀取IP庫文件
File ipFile = new File("IP文件庫");
DatabaseReader reader = new DatabaseReader.Builder(ipFile).build();
// IPV4地址
InetAddress ipV4 = InetAddress.getByName("IPV4");
if (ipV4 instanceof Inet4Address){
System.out.println(reader.country(ipV4));
System.out.println(reader.country(ipV4).getCountry());
// 默認英文名
System.out.println(reader.country(ipV4).getCountry().getName());
// 查詢中文名
System.out.println(reader.country(ipV4).getCountry().getNames().get("zh-CN"));
}
// IPV6地址
InetAddress ipV6 = InetAddress.getByName("IPV6");
if (ipV6 instanceof Inet6Address){
System.out.println(reader.country(ipV6));
System.out.println(reader.country(ipV6).getCountry());
// 默認英文名
System.out.println(reader.country(ipV6).getCountry().getName());
// 查詢中文名
System.out.println(reader.country(ipV6).getCountry().getNames().get("zh-CN"));
}
}
}
如果需要非常精確的實時歸屬地分析,可以購買專業(yè)的IP網(wǎng)段數(shù)據(jù),實時更新到本地的數(shù)據(jù)庫中,作為IP字典使用,獲取請求的IP后,直接范圍匹配即可。
CREATE TABLE `ip_place` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `network` varchar(100) DEFAULT NULL COMMENT '網(wǎng)段區(qū)間', `min_ip` bigint(20) DEFAULT NULL COMMENT '最小IP', `max_ip` bigint(20) DEFAULT NULL COMMENT '最大IP', `min_ip_number` bigint(20) DEFAULT NULL COMMENT '最小IP數(shù)值', `max_ip_number` bigint(20) DEFAULT NULL COMMENT '最大IP數(shù)值', `ip_place` varchar(100) DEFAULT NULL COMMENT '歸屬地', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP歸屬地';
最后需要補充說一句,對于很多標準的數(shù)據(jù),盡可能在項目最初就設計好字典枚舉或者數(shù)據(jù)表,避免后續(xù)規(guī)范時面臨數(shù)據(jù)清洗的問題。
到此這篇關于Java實現(xiàn)通過IP計算分析歸屬地實例分享的文章就介紹到這了,更多相關通過IP計算分析歸屬地內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java NIO實例UDP發(fā)送接收數(shù)據(jù)代碼分享
這篇文章主要介紹了Java NIO實例UDP發(fā)送接收數(shù)據(jù)代碼分享,分享了客戶端和服務端完整代碼,小編覺得還是挺不錯的,共需要的朋友參考。2017-11-11
springboot使用redis實現(xiàn)從配置到實戰(zhàn)
本文主要介紹了springboot使用redis ,采用的是RedisTemplate的形式,還有一種采用spring支持的注解進行訪問緩存,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
解決SpringCloud Gateway配置自定義路由404的坑
這篇文章主要介紹了解決SpringCloud Gateway配置自定義路由404的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Fluent Mybatis,原生Mybatis,Mybatis Plus三者功能對比
本文主要介紹了Fluent Mybatis,原生Mybatis,Mybatis Plus三者功能對比,分享給大家,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
mybatis Invalid bound statement(not foun
這篇文章主要介紹了mybatis Invalid bound statement(not found)排坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06

