SpringBoot整合ip2region實現(xiàn)使用ip監(jiān)控用戶訪問城市的詳細過程
舉個栗子??
最近,多平臺都上線了展示近期發(fā)帖所在地功能,比如抖音、微博、百度,像下面那樣:
那么這個功能都是如何實現(xiàn)的呢?
一般有兩個方法:GPS 定位的信息和用戶 IP 地址。
由于每個手機都不一定會打開 GPS,而且有時并不太需要太精確的位置(到城市這個級別即可),所以根據(jù) IP 地址入手來分析用戶位置是個不錯的選擇。
所以ip2region框架應運而生,GitHub上??已經(jīng)10.6K,值得一用。
GitHub地址:github.com/lionsoul201…
快速上手??
第一步,將整個項目down下來,找到data目錄,進入
這里有三份ip地址庫,我們將ip2region.xdb復制出來,等下我們的java項目中需要使用到。
第二步,創(chuàng)建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
目錄下創(chuàng)建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/"; /** * 根據(jù)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); } //創(chuàng)建查詢對象 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")); } }
輸出結果如下:
項目實現(xiàn)??
1、思路分析
通過上面簡單的例子我們已經(jīng)可以通過ip獲取地域了,那么接下來將實現(xiàn)如何監(jiān)控Controller接口的訪問地址。
首先,在一個項目中肯定有很多接口,所以我們不能直接在接口中寫代碼的方式去實現(xiàn),這樣代碼復雜度、耦合度太高。所以我打算在這里使用注解切面的方式實現(xiàn),只需要在接口方法上加上 @Ip 注解就可以實現(xiàn)
。不知道切面是什么的同學可以參考這篇文章:Springboot如何使用Aspectj實現(xiàn)AOP面向切面編程
其次,有些項目中會使用Nginx等反向代理軟件,則不能通過 request.getRemoteAddr()獲取 IP地址,如果使用了多級反向代理的話,X-Forwarded-For的值并不止一個,而是一串IP地址,X-Forwarded-For中第一個非 unknown的有效IP字符串,則為真實IP地址。
最后,讓我們來實現(xiàn)這個功能吧!
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/"; /** * 根據(jù)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); } //創(chuàng)建查詢對象 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,所以本地解析出來的是內(nèi)網(wǎng)
到此這篇關于SpringBoot整合ip2region實現(xiàn)使用ip監(jiān)控用戶訪問城市的文章就介紹到這了,更多相關SpringBoot整合ip2region內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java實現(xiàn)監(jiān)聽文件變化的三種方案詳解
這篇文章主要介紹了Java實現(xiàn)監(jiān)聽文件變化的三種方法,每種方案給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05SpringBoot集成Lettuce客戶端操作Redis的實現(xiàn)
本文主要介紹了SpringBoot集成Lettuce客戶端操作Redis的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-11-11jdk中動態(tài)代理異常處理分析:UndeclaredThrowableException
最近在工作中遇到了報UndeclaredThrowableException的錯誤,通過查找相關的資料,終于解決了,所以這篇文章主要給大家介紹了關于jdk中動態(tài)代理異常處理分析:UndeclaredThrowableException的相關資料,需要的朋友可以參考下2018-04-04

解決Java變異出現(xiàn)錯誤No enclosing instance of type XXX is accessible

MyEclipse+Tomcat+MAVEN+SVN項目完整環(huán)境搭建(圖文教程)

分享Java8中通過Stream對列表進行去重的實現(xiàn)