0 概述
-
不知道各位有没有好奇过,下图这个效果是怎么做到的呢?
-
想要知道一个位置信息,要么就是使用 GPS,要么就是使用 IP 地址查询。但是 GPS 定位获取地址的前提是要打开它,IP 地址查询有在线查询,也有离线查询,我现在要介绍的这款工具,就是一个离线的 IP 地址库,名为:ip2region
-
它是一款很好用的离线 IP 地址定位库和 IP 定位数据管理框架,支持国内和国外的 IP 查询,Gitee 上已有 7.4K stars
-
Gitee 地址:仓库地址
1 快速上手
- 我们已经了解了 ip2region 了,现在我们开始写一个 demo 测试一下
- 测试开始前,首先需要到上述仓库地址中,拉取代码到本地,进入 data 文件夹,把
ip2region.xdb
文件复制到 SpringBoot 项目中的resources
资源目录下
补充:直接获取
ip2region.xbd
文件,可以关注微信公众号:EzCoding
,回复ip
即可获取 - 引入依赖
<dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.6.5</version> </dependency> <!-- 以下依赖在后续测试时会使用,与 ip2region 本身无关 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.7</version> </dependency>
- 测试 IP 、测试代码
import lombok.extern.slf4j.Slf4j; import org.lionsoul.ip2region.xdb.Searcher; import java.io.File; import java.util.Objects; /** * 测试demo * * @Author Jasper * @Time 2024/02/20 * @公众号:EzCoding */ @Slf4j public class Ip2RegionUtil { public static String getCityInfo(String ip) { String dbPath = Objects.requireNonNull(Ip2RegionUtil.class.getResource("/ip2region.xdb")).getPath(); File file = new File(dbPath); if (file.exists()) { try { // 创建查询对象 Searcher searcher = Searcher.newWithFileOnly(dbPath); return searcher.search(ip); } catch (Exception e) { log.error("异常:{}", e.getMessage(), e); } } return ""; } public static void main(String[] args) { System.out.println(getCityInfo("127.0.0.1")); System.out.println(getCityInfo("186.63.44.21")); } }
- 输出结果如下:
0|0|0|内网IP|内网IP 阿根廷|0|0|0|西班牙电信
2 整合到项目中
- 通过上述 demo 演示,已初步掌握了 ip2region 的使用,那么如何整合到项目里呢?如何知道用户一访问就知道用户的 IP 地址呢?
- 如果直接在每个接口或需要记录 IP 的接口都引入这个方法的话,耦合太高,并且增加了代码的复杂度和冗余度,因此推荐使用通过
自定义注解
+AOP
的方式来实现整合。 - step1、定义一个自定义注解
import java.lang.annotation.*; /** * 自定义注解 * * @Author Jasper * @Time 2024/02/20 * @公众号:EzCoding */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Ip { }
- step2、定义切面
import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; 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.util.HashMap; import java.util.Map; /** * 切面 * * @Author Jasper * @Time 2024/02/20 * @公众号:EzCoding */ @Aspect @Component @Slf4j public class IpAspect { @Pointcut("@annotation(com.example.demo.ip2regin.Ip)") public void pointcut(){ } @Around("pointcut()") public Object doAround(ProceedingJoinPoint joinPoint){ HttpServletRequest request = HttpContextUtil.getHttpServletRequest(); Map<String, Object> map = new HashMap<>(); String ip = IpUtil.getIpAddr(request); try { String cityInfo = Ip2RegionUtil.getCityInfo(ip); joinPoint.proceed(); map.put("ip", ip); map.put("cityInfo", cityInfo); } catch (Throwable e) { log.error("切面获取ip异常:{}", e.getMessage(), e); } return JSONUtil.toJsonStr(map); } }
- step3、使用到的工具类
import javax.servlet.http.HttpServletRequest; public class IpUtil { private static final String UNKNOWN = "unknown"; protected IpUtil() { } 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; } }
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; 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(); } }
- step4、Controller 层
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Controller 层 * * @Author Jasper * @Time 2024/02/20 * @公众号:EzCoding */ @RestController @RequestMapping("/ip2region") public class Ip2RegionController { @GetMapping("/test") @Ip public String test(){ return "hello ip2region"; } }
- step5、访问测试
- 以上就是有关 ip2region 的全部内容了,赶快收藏起来以备不时之需。
- 创作不易,感谢阅读,若您喜欢这篇文章,不妨传承这份知识的力量,点个赞或关注我吧~
- 微信公众号:EzCoding