引言
Java 中是如何获取 IP 属地的
首先需要写一个 IP 获取的工具类
内置的三种查询算法
使用方法
项目用到的全部依赖
引言最近,各大平台都新增了评论区显示发言者ip归属地的功能,例如哔哩哔哩,微博,知乎等等。
Java 中是如何获取 IP 属地的主要分为以下几步
通过 HttpServletRequest 对象,获取用户的 IP 地址
通过 IP 地址,获取对应的省份、城市
首先需要写一个 IP 获取的工具类因为每一次用户的 Request 请求,都会携带上请求的 IP 地址放到请求头中。
public class IpUtils {
/**
* 获取ip地址
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request){
String ipAddress = null;
try {
ipAddress = request.getHeader("X-Forwarded-For");
if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ipAddress.indexOf(",") != -1) {
ipAddress = ipAddress.split(",")[0];
}
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
}
}catch (Exception e) {
log.error("IPUtils ERROR ",e);
}
return ipAddress;
}
对这里出现的几个名词解释一下:
X-Forwarded-For:一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址。每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。
Proxy-Client-IP:这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头
WL-Proxy-Client-IP:也是通过 Apache http 服务器,在 weblogic 插件加上的头。
X-Real-IP:一般只记录真实发出请求的客户端IP
HTTP_CLIENT_IP:代理服务器发送的HTTP头。如果是“超级匿名代理”,则返回none值。
这里,要着重介绍一下Ip2region项目。
github地址:github.com/lionsoul201…
一个准确率 99.9% 的离线 IP 地址定位库,0.0x 毫秒级查询,ip2region.db 数据库只有数MB,提供了 java,php,c,python,nodejs,golang,c# 等查询绑定和Binary,B树,内存三种查询算法。
内置的三种查询算法全部的查询客户端单次查询都在 0.x 毫秒级别,内置了三种查询算法
memory 算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。
binary 算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别。
b-tree 算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。
使用方法1、引入ip2region依赖
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
2、下载仓库中的ip2region.db 文件,放到工程resources目录下
3、编写方法加载ip2region文件,对用户ip地址进行转换。
/**
* 获取ip属地
* @param ip
* @return
* @throws Exception
*/
public static String getCityInfo(String ip) throws Exception {
//获得文件流时,因为读取的文件是在打好jar文件里面,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("ip2region.db");
Resource resource = resources[0];
InputStream is = resource.getInputStream();
File target = new File("ip2region.db");
FileUtils.copyInputStreamToFile(is, target);
is.close();
if (StringUtils.isEmpty(String.valueOf(target))) {
log.error("Error: Invalid ip2region.db file");
return null;
}
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config, String.valueOf(target));
//查询算法
//B-tree, B树搜索(更快)
int algorithm = DbSearcher.BTREE_ALGORITHM;
try {
//define the method
Method method;
method = searcher.getClass().getMethod("btreeSearch", String.class);
DataBlock dataBlock;
if (!Util.isIpAddress(ip)) {
log.error("Error: Invalid ip address");
}
dataBlock = (DataBlock) method.invoke(searcher, ip);
String ipInfo = dataBlock.getRegion();
if (!StringUtils.isEmpty(ipInfo)) {
ipInfo = ipInfo.replace("|0", "");
ipInfo = ipInfo.replace("0|", "");
}
return ipInfo;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
4、由于 ip 属地在国内的话,只会展示省份,而国外的话,只会展示国家。所以我们还需要对这个方法进行一下封装,得到获取 IP 属地的信息。
public static String getIpPossession(String ip) throws Exception {
String cityInfo = IpUtils.getCityInfo(ip);
if (!StringUtils.isEmpty(cityInfo)) {
cityInfo = cityInfo.replace("|", " ");
String[] cityList = cityInfo.split(" ");
if (cityList.length > 0) {
// 国内的显示到具体的省
if ("中国".equals(cityList[0])) {
if (cityList.length > 1) {
return cityList[1];
}
}
// 国外显示到国家
return cityList[0];
}
}
return "未知";
}
5、编写测试类。
public static void main(String[] args) throws Exception {
//国内ip
String ip1 = "220.248.12.158";
String cityInfo1 = IpUtils.getCityInfo(ip1);
System.out.println(cityInfo1);
String address1 = IpUtils.getIpPossession(ip1);
System.out.println(address1);
//国外ip
String ip2 = "67.220.90.13";
String cityInfo2 = IpUtils.getCityInfo(ip2);
System.out.println(cityInfo2);
String address2 = IpUtils.getIpPossession(ip2);
System.out.println(address2);
}
6、测试结果
项目用到的全部依赖想了解的小伙伴可以学习一下!
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
以上就是Java根据ip地址获取归属地实例详解的详细内容,更多关于Java根据ip获取归属地的资料请关注易知道(ezd.cc)其它相关文章!