写在前面
最近有个项目,需要根据当前的地理位置获取天气信息.因为这个是一个web端的项目,没有办法根据移动端的定位去获取地理位置的信息,所以在此记录下如何根据请求的ip地址获取地理位置信息,在google搜索问题的时候发现一个不错的解决方案,用到的是Ip2region这个项目
引入依赖
根据官方文档的描述,我们需要先引入依赖
1 2 3 4 5
| <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.7.0</version> </dependency>
|
下载文件
下载xdb文件到本地 ip2region.xdb,我将这个文件放在了resource目录

根据IP查询地址信息
参考官方文档,有三种方式可以查询所属的地址信息分别为:完全基于文件的查询、缓存 VectorIndex
索引、缓存整个 xdb
数据,在此我选择的是第二种,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public static String getRegion(String ip) throws IOException { InputStream in = IPUtils.class.getClassLoader().getResourceAsStream("ip2region.xdb");
File file = new File("ip2region.xdb"); try (OutputStream outputStream = new FileOutputStream(file)) { int read; byte[] bytes = new byte[1024];
while ((read = in.read(bytes)) != -1) { outputStream.write(bytes, 0, read); } }
String dbPath = file.getAbsolutePath();
byte[] vIndex; try { vIndex = Searcher.loadVectorIndexFromFile(dbPath); } catch (Exception e) { return null; }
Searcher searcher; try { searcher = Searcher.newWithVectorIndex(dbPath, vIndex); } catch (Exception e) { return null; }
String region = null; try { region = searcher.search(ip); } catch (Exception e) { return null; }
searcher.close(); return region; }
|
开发过程中遇到的坑
使用HttpServletRequest
获取用户的IP地址
在使用HttpServletRequest
获取IP地址的过程中,如果是通过内网访问,或者用了Nginx、FRP等方式反向代理会导致request.getRemoteAddr()
方法拿到的是内网地址,并非真实的用户ip,所以我们需要根据header去判断是否经过了反向代理
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static String getRealIP(HttpServletRequest request){ String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) { clientIp = request.getRemoteAddr(); }
String[] clientIps = clientIp.split(","); if(clientIps.length <= 1) return clientIp.trim();
return clientIps[clientIps.length-1].trim(); }
|
部署项目最好还是部署在公网服务器上,内网服务器上部署是无法拿到用户的真实ip的