Java-通过IP获取真实地址

news2024/12/23 9:39:50

文章目录

    • 前言
    • 功能实现
    • 测试

前言

最近写了一个日志系统,需要通过访问的 IP 地址来获取真实的地址,并且存到数据库中,我也是在网上看了一些文章,遂即整理了一下供大家参考。


功能实现

这个是获取正确 IP 地址的方法,可以直接使用的。


    /**
     * 获取 IP 地址
     */
    public static String getIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst(ParameterConstants.X_FORWARDED_FOR);
        if (ip != null && ip.length() != 0 && !ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
            if (ip.contains(",")) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst(ParameterConstants.PROXY_CLIENT_IP);
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst(ParameterConstants.WL_PROXY_CLIENT_IP);
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst(ParameterConstants.HTTP_CLIENT_IP);
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst(ParameterConstants.HTTP_X_FORWARDED_FOR);
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst(ParameterConstants.X_REAL_IP);
        }
        if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();
            if (ip.equals(ParameterConstants.LOCAL_IP_V4) || ip.equals(ParameterConstants.LOCAL_IP_V6)) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                    ip = inet.getHostAddress();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }
        return ip;
    }

    /**
     * 获取请求IP.
     * @return String ip
     */
    public static String getIpAddress(HttpServletRequest request) {
        String ip = null;
        Enumeration<?> enu = request.getHeaderNames();
        while (enu.hasMoreElements()) {
            String name = (String) enu.nextElement();
            if (ParameterConstants.CDN_SRC_IP.equalsIgnoreCase(name)
                    || ParameterConstants.X_FORWARDED_FOR.equalsIgnoreCase(name)
                    || ParameterConstants.PROXY_CLIENT_IP.equalsIgnoreCase(name)
                    || ParameterConstants.WL_PROXY_CLIENT_IP.equalsIgnoreCase(name)
                    || ParameterConstants.X_REAL_IP.equalsIgnoreCase(name)) {
                ip = request.getHeader(name);
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(ip)){
                break;
            }
        }
        if (StringUtils.isBlank(ip)){
            ip = request.getRemoteAddr();
        }

        if (ip.equals(ParameterConstants.LOCAL_IP_V4) || ip.equals(ParameterConstants.LOCAL_IP_V6)) {
            // 根据网卡取本机配置的IP
            InetAddress inet = null;
            try {
                inet = InetAddress.getLocalHost();
                ip = inet.getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        return ip;
    }

通过以上方法你可以获取到访问者的 IP 地址,只有获取到了 IP 地址,才能够拿到真实的地址

通过 IP 获取真实地址的方法有很多种,这里我只说两个:

  • 方式一:离线 IP 地址定位查询
  • 方式二:在线 IP 地址定位查询

方式一 我们需要在本地保存一个 IP 地址定位的文档,方式二就是通过 http 请求的方式访问一些可以查询 IP 地址所属地理位置的网址。

方式一就是查询比较快,但是有些地址可能查询不到,方式二就是基本上都能查到,但是要建立请求,会有点慢,所以将二者结合起来就行了。

导入依赖:

		<!-- 离线IP地址定位库 -->
        <dependency>
            <groupId>org.lionsoul</groupId>
            <artifactId>ip2region</artifactId>
            <version>1.7.2</version>
        </dependency>
        
        <!-- ali地域 -->
        <dependency>
            <groupId>com.maxmind.geoip2</groupId>
            <artifactId>geoip2</artifactId>
            <version>2.6.0</version>
        </dependency>

添加离线 IP 地址库:

src/main/resources下新建 ip2region 复制文件 ip2region.db 到目录下

------------------ ip2region.db 资源下载 -----------------
链接:百度网盘
提取码:v7se
---------------------------------------------------------

添加工具类:

RegionUtil.java

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Objects;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

/**
 * 根据ip离线查询地址
 *
 * @author ruoyi
 */
public class RegionUtil {
    private static final Logger log = LoggerFactory.getLogger(RegionUtil.class);

    private static final String JAVA_TEMP_DIR = "java.io.tmpdir";

    static DbConfig config = null;
    static DbSearcher searcher = null;

    // 初始化IP库
    static {
        try {
            // 因为jar无法读取文件,复制创建临时文件
            String dbPath = Objects.requireNonNull(RegionUtil.class.getResource("/ip2region/ip2region.db")).getPath();
            File file = new File(dbPath);
            if (!file.exists()) {
                String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR);
                dbPath = tmpDir + "ip2region.db";
                file = new File(dbPath);
                ClassPathResource cpr = new ClassPathResource("ip2region" + File.separator + "ip2region.db");
                InputStream resourceAsStream = cpr.getInputStream();
                FileUtils.copyInputStreamToFile(resourceAsStream, file);
            }
            config = new DbConfig();
            searcher = new DbSearcher(config, dbPath);
            log.info("bean [{}]", config);
            log.info("bean [{}]", searcher);
        } catch (Exception e) {
            log.error("init ip region error:{}", e.toString());
        }
    }

    /**
     * 解析IP
     *
     * @param ip
     * @return
     */
    public static String getRegion(String ip) {
        try {
            // db
            if (searcher == null || StringUtils.isEmpty(ip)) {
                log.error("DbSearcher is null");
                return StringUtils.EMPTY;
            }
            long startTime = System.currentTimeMillis();
            // 查询算法
            Method method = searcher.getClass().getMethod("memorySearch", String.class);

            DataBlock dataBlock = null;
            if (!Util.isIpAddress(ip)) {
                log.warn("warning: Invalid ip address");
            }
            dataBlock = (DataBlock) method.invoke(searcher, ip);
            String result = dataBlock.getRegion();
            long endTime = System.currentTimeMillis();
            log.debug("region use time[{}] result[{}]", endTime - startTime, result);
            return result;

        } catch (Exception e) {
            log.error("error:{}", e.toString());
        }
        return StringUtils.EMPTY;
    }

}

PureNetUtils.java

package com.mike.common.core.utils;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * 网络访问工具类
 */
public class PureNetUtils {

    private static final Logger log = LoggerFactory.getLogger(PureNetUtils.class);

    /**
     * get方法直接调用post方法
     *
     * @param url 网络地址
     * @return 返回网络数据
     */
    public static String get(String url) {
        return post(url, null);
    }

    /**
     * 设定post方法获取网络资源,如果参数为null,实际上设定为get方法
     *
     * @param url   网络地址
     * @param param 请求参数键值对
     * @return 返回读取数据
     */
    public static String post(String url, Map<String, String> param) {
        HttpURLConnection conn = null;
        try {
            URL u = new URL(url);
            conn = (HttpURLConnection) u.openConnection();
            StringBuilder sb = null;
            if (param != null) {// 如果请求参数不为空
                sb = new StringBuilder();
                /*
                 * A URL connection can be used for input and/or output. Set the
                 * DoOutput flag to true if you intend to use the URL connection
                 * for output, false if not. The default is false.
                 */
                // 默认为false,post方法需要写入参数,设定true
                conn.setDoOutput(true);
                // 设定post方法,默认get
                conn.setRequestMethod("POST");
                // 获得输出流
                OutputStream out = conn.getOutputStream();
                // 对输出流封装成高级输出流
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
                // 将参数封装成键值对的形式
                for (Map.Entry<String, String> s : param.entrySet()) {
                    sb.append(s.getKey()).append("=").append(s.getValue()).append("&");
                }
                // 将参数通过输出流写入
                writer.write(sb.deleteCharAt(sb.toString().length() - 1).toString());
                writer.close();// 一定要关闭,不然可能出现参数不全的错误
                sb = null;
            }
            conn.connect();// 建立连接
            sb = new StringBuilder();
            // 获取连接状态码
            int recode = conn.getResponseCode();
            BufferedReader reader = null;
            if (recode == 200) {
                // Returns an input stream that reads from this open connection
                // 从连接中获取输入流
                InputStream in = conn.getInputStream();
                // 对输入流进行封装
                reader = new BufferedReader(new InputStreamReader(in));
                String str = null;
                sb = new StringBuilder();
                // 从输入流中读取数据
                while ((str = reader.readLine()) != null) {
                    sb.append(str).append(System.getProperty("line.separator"));
                }
                // 关闭输入流
                reader.close();
                if (sb.toString().length() == 0) {
                    return null;
                }
                return sb.toString().substring(0,
                        sb.toString().length() - System.getProperty("line.separator").length());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (conn != null)// 关闭连接
                conn.disconnect();
        }
        return null;
    }

    /**
     * 获取 ip 所属地址
     *
     * @param ip IP 地址
     * @return 所属地址
     */
    public static String getAlibaba(String ip) {
        Map<String, String> map = new HashMap<>();
        map.put("ip", ip);
        map.put("accessKey", "alibaba-inc");
        String result = PureNetUtils.post("http://ip.taobao.com/outGetIpInfo", map);
        log.info("{} => POST: http://ip.taobao.com/outGetIpInfo || result: {}", ip, result);
        String address = null;
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            // 请求成功,解析响应数据
            if ("query success".equals(jsonObject.get("msg"))) {
                JSONObject dataMap = JSONObject.parseObject(jsonObject.getString("data"));
                String country = dataMap.getString("country");
                String region = dataMap.getString("region");
                String city = dataMap.getString("city");
                address = country + region + city;
            }
        }
        return address;
    }

}

AddressUtils .java

import com.mike.common.core.utils.PureNetUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 获取地址类
 *
 * @author ruoyi
 */
public class AddressUtils {
    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);

    // 未知地址
    public static final String UNKNOWN = "未知地址";

    public static String getRealAddress(String ip) {
        // 内网不查询
        if (internalIp(ip)) {
            return "内网IP";
        }
        try {
            String rspStr = RegionUtil.getRegion(ip);
            if (StringUtils.isNotEmpty(rspStr)) {
                String[] obj = rspStr.split("\\|");
                String region = obj[2];
                String city = obj[3];

                return String.format("%s%s", region, city);
            }
        } catch (Exception e) {
            log.error("获取地理位置异常 {}", e.toString());
        }
        // ali地域查询
        return PureNetUtils.getAlibaba(ip);
    }

    /* 判断是否是内网IP */
    public static boolean internalIp(String ipAddress) {
        boolean isInnerIp = false;
        long ipNum = getIpNum(ipAddress);
        /*
         * 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类
         * 192.168.0.0-192.168.255.255 当然,还有127这个网段是环回地址
         */
        long aBegin = getIpNum("10.0.0.0");
        long aEnd = getIpNum("10.255.255.255");
        long bBegin = getIpNum("172.16.0.0");
        long bEnd = getIpNum("172.31.255.255");
        long cBegin = getIpNum("192.168.0.0");
        long cEnd = getIpNum("192.168.255.255");
        isInnerIp = isInner(ipNum, aBegin, aEnd)
                || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
                || ipAddress.equals("127.0.0.1");
        return isInnerIp;
    }

    /* 获取IP数 */
    private static long getIpNum(String ipAddress) {
        String[] ip = ipAddress.split("\\.");
        long a = Integer.parseInt(ip[0]);
        long b = Integer.parseInt(ip[1]);
        long c = Integer.parseInt(ip[2]);
        long d = Integer.parseInt(ip[3]);
        return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
    }

    private static boolean isInner(long userIp, long begin, long end) {
        return (userIp >= begin) && (userIp <= end);
    }

    public static void main(String[] args) {
        String realAddress = getRealAddress("117.136.79.113");
        System.out.println("realAddress = " + realAddress);
    }
}
           String region = dataMap.getString("region");
                String city = dataMap.getString("city");
                address = country + region + city;
            }
        }
        return address;
    }

    /* 获取IP数 */
    private static long getIpNum(String ipAddress) {
        String[] ip = ipAddress.split("\\.");
        long a = Integer.parseInt(ip[0]);
        long b = Integer.parseInt(ip[1]);
        long c = Integer.parseInt(ip[2]);
        long d = Integer.parseInt(ip[3]);
        return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
    }

    private static boolean isInner(long userIp, long begin, long end) {
        return (userIp >= begin) && (userIp <= end);
    }

    public static void main(String[] args) {
        String realAddress = getRealAddress("117.136.79.113");
        System.out.println("realAddress = " + realAddress);
    }
}


测试

运行 AddressUtils.javamain 方法测试

在这里插入图片描述


参考博客:
Java如何通过IP获得真实地址:https://blog.csdn.net/qq_39486119/article/details/107857455
集成ip2region实现离线IP地址定位:http://doc.ruoyi.vip/ruoyi/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/744862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chinese_lite ocr使用教程

一、简介 超轻量级中文ocr&#xff0c;支持竖排文字识别, 支持ncnn、mnn、tnn推理 ( dbnet(1.8M) crnn(2.5M) anglenet(378KB)) 总模型仅4.7M 二、环境 python3.6linux/macos/windows 三、项目地址 https://github.com/DayBreak-u/chineseocr_lite 下载项目后, 执行 pip…

服务器上的Notebook在本地运行

3090TI的服务器&#xff0c;用的是Ubuntu系统&#xff0c;在使用的时候&#xff0c;如何让服务器资源在本地的JupyterNotebook运行呢&#xff1f; 目录 一、在3090TI服务器上指定一个特定的访问端口 二、本地端口配置 三、本地JupyterNotebook访问服务器 一、在3090TI服务器…

数据结构(Map、Set)

文章目录 一、搜索树1.1 概念1.2 操作1.3 与java类集的关系 二、Map 和 Set2.1 概述2.2 Map2.3 Set 三、哈希表3.1 概念3.2 冲突3.3 其他 一、搜索树 1.1 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为…

字符串函数和字符函数

文章目录 前言strlen()实现strlen&#xff08;&#xff09; strcpy&#xff08;&#xff09;模拟实现 strcat()strcat()模拟实现 strcmp()模拟实现strcmp() strstr()模拟实现strstr() strncpy(),strncmp(),strncat()strtok()memcpy()memcpy()的模拟实现 memmove()memmove()的模…

ELK + Filebeat 部署及 logstash 的四大插件(grok、date、mutate、multiline)

目录 FilebeatFilebeat 结合 logstash 带来好处&#xff1a;FluentdELK Filebeat 部署1&#xff0e;安装 Filebeat & Httpd2&#xff0e;设置 filebeat 的主配置文件4&#xff0e;在 Logstash 组件所在节点上新建一个 Logstash 配置文件5&#xff0e;浏览器访问 http://19…

凯迪正大数显电动调压控制台

数显电动调压控制台使用方法 1、核对试验变压器&#xff0c;测量绕阻额定输出电压&#xff0c;使之与操作箱&#xff08;台&#xff09;相吻合。 2、按接线示意图接好试验变压器与操作箱&#xff08;台&#xff09;及感应调压器之间的联线。 3、接通电源&#xff0c;通电源指…

el-select 右侧icon样式问题

el-select 右侧icon样式问题 样式问题如图&#xff1a; 解决方法&#xff1a; el-input__suffix {display: flex;align-items: center;justify-content: center; }注意&#xff1a;样式需写在没有scoped的style标签里

在VSCODE编辑器是用ctrl+c和ctrl+s(复制粘贴)失效怎么办

有时我们在开发过程中&#xff0c;由于使用vsccode太长时间导致复制ctrlc和ctrls会失效&#xff0c;之前我的处理方式是重启浏览器&#xff0c;但有时候这样太耗时间了&#xff0c;但发现一个方法可以解决&#xff0c;就是刷新下编辑器的timeline就行&#xff0c;如下图&#x…

快速构建一个 GitLab + Jenkins + Harbor 的云原生 DevOps 环境

今天我们要搭建一条怎样的工具链呢&#xff1f;且看效果图&#xff1a; GitLab Jenkins Harbor Toolchain Workflow 首先我们需要完成 GitLab、Jenkins 和 Harbor 三个工具的部署&#xff1b; 接着我们需要在 GitLab 上创建一个代码库&#xff0c;并且在 Jenkins 上创建相应…

若依系统学习笔记记录1

下载后的文件列表 先按照nocos. Nacos: 概览 欢迎来到 Nacos 的世界&#xff01; Nacos 致力于帮助您发现、配置和管理微服务Nacos: 概览 欢迎来到 Nacos 的世界&#xff01; Nacos 致力于帮助您发现、配置和管理微服务 cd nacos/ mvn命令如果是idea,需要用Ctrlshiftenter来执…

【软件测试】MySQL数据库场景问题+解决方案

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 问题1&#xff1a…

2023年测试岗,自动化测试如何学?如何卷出测试圈?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 怎么学习自动化测…

初识FreeRTOS

一、FreeRTOS 介绍 什么是 FreeRTOS &#xff1f; Free即免费的&#xff0c;RTOS的全称是Real time operating system&#xff0c;中文就是实时操作系统。 注意&#xff1a;RTOS不是指某一个确定的系统&#xff0c;而是指一类操作系统。比如&#xff1a;uc/OS&#xff0c;Fre…

STM32 Proteus仿真LCD12864火灾检测烟雾火焰温度报警器MQ2 -0064

STM32 Proteus仿真LCD12864火灾检测烟雾火焰温度报警器MQ2 -0064 Proteus仿真小实验&#xff1a; STM32 Proteus仿真LCD12864火灾检测烟雾火焰温度报警器MQ2 -0064 功能&#xff1a; 硬件组成&#xff1a;STM32F103R6单片机 LCD12864 液晶显示DS18B20 温度传感器多个按键电位…

阿里云配置端口安全组策略

文章目录 为何配置安全组安全组设置安全组应用到实例中 为何配置安全组 nginx正确配置了83端口&#xff0c;却无法访问资源&#xff0c;报502错误&#xff0c;这大概就是服务器的安全策略原因 安全组设置 安全组配置地址 安全组应用到实例中 配置地址

pandas 各种存储格式速度对比:CSV、hdf5、SQL、pickle、feather、parquet

前言&#xff1a;目前我在做一个callback函数&#xff0c;需要将数据重复的读取、写入&#xff0c;再供使用&#xff0c;并且数据量比较大&#xff0c;所以需要使用一个读写速度快的存储方式&#xff0c;不太考虑占用的磁盘空间 直接看结果 csv的文件存储&#xff0c;在读取的…

Java虚拟机(JVM)

Java虚拟机&#xff08;JVM&#xff09; 类加载 类加载 Java类加载的过程可以分为以下几个步骤&#xff1a; 加载&#xff08;Loading&#xff09;&#xff1a;类加载的第一步是将类的字节码文件加载到内存中。 通过类的全名&#xff0c;全限定名&#xff08;包括包名和类名&…

C++之std::enable_if_t用法(一百五十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

“人工智能的崛起:挑战与机遇并存“

近日&#xff0c;一位美国网络安全高级官员发出警告&#xff0c;称如果科技公司未能自我约束并与政府合作控制人工智能的力量&#xff0c;我们可能面临着巨大的风险。这位官员的言论是在数百名科技领袖和公众人物支持的联合声明之后发表的&#xff0c;该声明将人工智能的存在威…

mysql练习---存储过程/存储函数

创建表并插入数据 字段名 数据类型 主键 外键 非空 唯一 自增 id INT 是 否 是 是 否 name VARCHAR(50) 否 否 是 否 否 glass VARCHAR(50) 否 否 是 否 否 sch 表内容 id name glass 1 xiaommg glass 1 2 xiaojun glass 2 1、创建一个可以统计表格内记录条数的存储函数 &#…