SpringBoot整合ip2region实现使用ip监控用户访问城市的详细过程

目录
  • 举个栗子
  • 快速上手
    • 第一步,将整个项目down下来,找到data目录,进入
    • 第二步,创建maven项目,引入依赖
    • 第三步,编写测试类
  • 项目实现
    • 1、思路分析
    • 2、配置文件
    • SpringBoot项目pom.xml文件
    • 3、项目代码
    • 项目结构
    • SpringbootIpApplication.java
    • TestController.java
    • Ip.java
    • IpAspect.java
    • AddressUtil.java
    • HttpContextUtil.java
    • IPUtil.java
    • 打印结果

举个栗子

最近,多平台都上线了展示近期发帖所在地功能,比如抖音、微博、百度,像下面那样:

那么这个功能都是如何实现的呢?

一般有两个方法:GPS 定位的信息和用户 IP 地址。

由于每个手机都不一定会打开 GPS,而且有时并不太需要太精确的位置(到城市这个级别即可),所以根据 IP 地址入手来分析用户位置是个不错的选择。

所以ip2region框架应运而生,GitHub上️已经10.6K,值得一用。

GitHub地址:github.com/lionsoul201…

快速上手

第一步,将整个项目down下来,找到data目录,进入

这里有三份ip地址库,我们将ip2region.xdb复制出来,等下我们的java项目中需要使用到。

第二步,创建maven项目,引入依赖

pom.xml依赖如下:

<!-- ip2region  -->
<dependency>
	<groupId>org.lionsoul</groupId>
	<artifactId>ip2region</artifactId>
    <version>2.6.3</version>
</dependency>
<!-- 用于读取ip2region.xdb文件使用 -->
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.6</version>
</dependency>

加好依赖后,在resources目录下创建ip2region文件夹,把上面的ip2region.xdb文件放进去。

第三步,编写测试类

package com.example.springbootip.util;
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.File;
import java.text.MessageFormat;
import java.util.Objects;
public class AddressUtil {
    /**
     * 当前记录地址的本地DB
     */
    private static final String TEMP_FILE_DIR = "/home/admin/app/";
    /**
     * 根据IP地址查询登录来源
     *
     * @param ip
     * @return
     */
    public static String getCityInfo(String ip) {
        try {
            // 获取当前记录地址位置的文件
            String dbPath = Objects.requireNonNull(AddressUtil.class.getResource("/ip2region/ip2region.xdb")).getPath();
            File file = new File(dbPath);
            //如果当前文件不存在,则从缓存中复制一份
            if (!file.exists()) {
                dbPath =    TEMP_FILE_DIR + "ip.db";
                System.out.println(MessageFormat.format("当前目录为:[{0}]", dbPath));
                file = new File(dbPath);
                FileUtils.copyInputStreamToFile(Objects.requireNonNull(AddressUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.xdb")), file);
            }
            //创建查询对象
            Searcher searcher = Searcher.newWithFileOnly(dbPath);
            //开始查询
            return searcher.searchByStr(ip);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //默认返回空字符串
        return "";
    }
    public static void main(String[] args) {
        System.out.println(getCityInfo("1.2.3.4"));
    }
}

输出结果如下:

项目实现

1、思路分析

通过上面简单的例子我们已经可以通过ip获取地域了,那么接下来将实现如何监控Controller接口的访问地址。

首先,在一个项目中肯定有很多接口,所以我们不能直接在接口中写代码的方式去实现,这样代码复杂度、耦合度太高。所以我打算在这里使用注解切面的方式实现,只需要在接口方法上加上 @Ip 注解就可以实现。不知道切面是什么的同学可以参考这篇文章:SpringBoot整合aspectj实现面向切面编程(即AOP)

其次,有些项目中会使用Nginx等反向代理软件,则不能通过 request.getRemoteAddr()获取 IP地址,如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址。

最后,让我们来实现这个功能吧!

2、配置文件

SpringBoot项目pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-ip</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-ip</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- ip2region -->
        <dependency>
            <groupId>org.lionsoul</groupId>
            <artifactId>ip2region</artifactId>
            <version>2.6.3</version>
        </dependency>
        <!-- aop切面 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、项目代码

项目结构

SpringbootIpApplication.java

package com.example.springbootip;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootIpApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootIpApplication.class, args);
    }
}

TestController.java

package com.example.springbootip.controller;
import com.example.springbootip.ip2region.Ip;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
    @GetMapping("/hello")
    @Ip
    public String hello() {
        return "hello";
    }
}

Ip.java

package com.example.springbootip.ip2region;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ip {
}

IpAspect.java

package com.example.springbootip.ip2region;
import com.example.springbootip.util.AddressUtil;
import com.example.springbootip.util.HttpContextUtil;
import com.example.springbootip.util.IPUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.MessageFormat;
@Aspect
@Component
public class IpAspect {
    @Pointcut("@annotation(com.example.springbootip.ip2region.Ip)")
    public void pointcut() {
        // do nothing
    }
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
        String ip = IPUtil.getIpAddr(request);
        System.out.println(MessageFormat.format("当前IP为:[{0}];当前IP地址解析出来的地址为:[{1}]", ip, AddressUtil.getCityInfo(ip)));
        return point.proceed();
    }
}

AddressUtil.java

package com.example.springbootip.util;
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.xdb.Searcher;
import java.io.File;
import java.text.MessageFormat;
import java.util.Objects;
public class AddressUtil {
    /**
     * 当前记录地址的本地DB
     */
    private static final String TEMP_FILE_DIR = "/home/admin/app/";
    /**
     * 根据IP地址查询登录来源
     *
     * @param ip
     * @return
     */
    public static String getCityInfo(String ip) {
        try {
            // 获取当前记录地址位置的文件
            String dbPath = Objects.requireNonNull(AddressUtil.class.getResource("/ip2region/ip2region.xdb")).getPath();
            File file = new File(dbPath);
            //如果当前文件不存在,则从缓存中复制一份
            if (!file.exists()) {
                dbPath =    TEMP_FILE_DIR + "ip.db";
                System.out.println(MessageFormat.format("当前目录为:[{0}]", dbPath));
                file = new File(dbPath);
                FileUtils.copyInputStreamToFile(Objects.requireNonNull(AddressUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.xdb")), file);
            }
            //创建查询对象
            Searcher searcher = Searcher.newWithFileOnly(dbPath);
            //开始查询
            return searcher.searchByStr(ip);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //默认返回空字符串
        return "";
    }
    public static void main(String[] args) {
        System.out.println(getCityInfo("1.2.3.4"));
    }
}

HttpContextUtil.java

package com.example.springbootip.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
/**
 * @desc 全局获取HttpServletRequest、HttpServletResponse
 */
public class HttpContextUtil {
    private HttpContextUtil() {
    }
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }
    public static HttpServletResponse getHttpServletResponse() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
    }
}

IPUtil.java

package com.example.springbootip.util;
import javax.servlet.http.HttpServletRequest;
/**
 * @desc 查询当前访问的IP地址
 */
public class IPUtil {
    private static final String UNKNOWN = "unknown";
    protected IPUtil() {
    }
    /**
     * 获取 IP地址
     * 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,
     * X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}

打印结果

由于访问路径是:http://127.0.0.1:8080/test/hello,所以本地解析出来的是内网

到此这篇关于SpringBoot整合ip2region实现使用ip监控用户访问城市的文章就介绍到这了,更多相关SpringBoot整合ip2region内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot集成Zipkin实现分布式全链路监控

    Zipkin 简介 Zipkin is a distributed tracing system. It helps gather timing data needed to troubleshoot latency problems in service architectures. Features include both the collection and lookup of this data. If you have a trace ID in a log file, you ca

  • SpringBoot使用ip2region获取地理位置信息的方法

    目录 1.简介 2.引入依赖 3.测试 4.测试结果 1.简介 ip2region,准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法,仓库地址: https://gitee.com/lionsoul/ip2region 2.引入依赖 <!-- Ip地址获取 --> <dependency> <groupId>ne

  • SpringBoot整合ip2region实现使用ip监控用户访问城市的详细过程

    目录 举个栗子 快速上手 第一步,将整个项目down下来,找到data目录,进入 第二步,创建maven项目,引入依赖 第三步,编写测试类 项目实现 1.思路分析 2.配置文件 SpringBoot项目pom.xml文件 3.项目代码 项目结构 SpringbootIpApplication.java TestController.java Ip.java IpAspect.java AddressUtil.java HttpContextUtil.java IPUtil.java 打印结果 举

  • SpringBoot整合RedisTemplate实现缓存信息监控的步骤

    SpringBoot 整合 Redis 数据库实现数据缓存的本质是整合 Redis 数据库,通过对需要“缓存”的数据存入 Redis 数据库中,下次使用时先从 Redis 中获取,Redis 中没有再从数据库中获取,这样就实现了 Redis 做数据缓存.    按照惯例,下面一步一步的实现 Springboot 整合 Redis 来存储数据,读取数据. 1.项目添加依赖首页第一步还是在项目添加 Redis 的环境, Jedis. <dependency> <groupId>org.

  • zabbix 通过 agent 监控进程、端口的详细过程

    环境介绍 操作系统:centos 7.4 zabbix版本:zabbix server 3.4.7 客户端:zabbix-agent 3.4.7 监控进程:mysqld 监控端口:3306 tcp 进程监控 确认客户端已经安装且运行agent 查看进程 查看属于那个用户的 几个进程 mysql 的进程为root用户 两个进程 添加监控项 名称随便写 类型zabbix客户端 键值选则进程数返回数 应用集选则prosesses 进程 proc.num[<name>,<user>,<

  • springboot整合jsp,实现公交车站路线图

    开发环境: jdk 8 intellij idea tomcat 8 mysql 5.7 maven 3.6 所用技术: springboot jsp 数据静态初始化 项目介绍 使用springboot整合jsp,在后端写入公交路线名称和详细站点,前端页面可条件查询具体的内容,如公交路线,公交名称,车俩信息等. 运行效果 前台用户端: 路线选择 路线详情 数据准备: BusData.txt 准备工作: pom.xml加入jsp模板引擎支持: <dependency> <groupId&g

  • springboot整合websocket实现群聊思路代码详解

    实现思路 发送者向服务器发送大家早上好.其它客户端可以收到对应消息. 项目展示 通过springboot引入websocket,实现群聊,通过在线websocket测试进行展示. 核心代码 pom引入jar <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2

  • SpringBoot整合JWT框架,解决Token跨域验证问题

    一.传统Session认证 1.认证过程 1.用户向服务器发送用户名和密码. 2.服务器验证后在当前对话(session)保存相关数据. 3.服务器向返回sessionId,写入客户端 Cookie. 4.客户端每次请求,需要通过 Cookie,将 sessionId 回传服务器. 5.服务器收到 sessionId,验证客户端. 2.存在问题 1.session保存在服务端,客户端访问高并发时,服务端压力大. 2.扩展性差,服务器集群,就需要 session 数据共享. 二.JWT简介 JWT

  • springboot整合shardingjdbc实现分库分表最简单demo

    一.概览 1.1 简介 ShardingSphere-JDBC定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务. 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架. 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC. 支持任何第三方的数据库连接池,如:DBCP,

  • Springboot整合minio实现文件服务的教程详解

    首先pom文件引入相关依赖 <!--minio--> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>3.0.10</version> </dependency> springboot配置文件application.yml 里配置minio信息 #minio配置 minio: endpo

  • SpringBoot整合Druid实现数据库连接池和监控

    目录 1.Druid的简介 2.创建SpringBoot项目与数据表 2.1 创建项目 2.2 创建数据表 3.Druid实现数据库连接池 3.1 Druid的配置 3.2 创建实体类(Entity层) 3.3 数据库映射层(Mapper层) 3.4 业务逻辑层(Service层) 3.5 控制器方法(Controller层) 3.6 显示页面(View层) 4.Druid实现监控功能 1.Druid的简介 Druid是Java语言中使用的比较多的数据库连接池.Druid还提供了强大的监控和扩展

  • SpringBoot详解整合Spring Boot Admin实现监控功能

    目录 监控 监控的意义 可视化监控平台 监控原理 自定义监控指标 监控 ​ 在说监控之前,需要回顾一下软件业的发展史.最早的软件完成一些非常简单的功能,代码不多,错误也少.随着软件功能的逐步完善,软件的功能变得越来越复杂,功能不能得到有效的保障,这个阶段出现了针对软件功能的检测,也就是软件测试.伴随着计算机操作系统的逐步升级,软件的运行状态也变得开始让人捉摸不透,出现了不稳定的状况.伴随着计算机网络的发展,程序也从单机状态切换成基于计算机网络的程序,应用于网络的程序开始出现,由于网络的不稳定性,

随机推荐