Java实现通过IP获取IP归属地的方法(离线+在线)
作者:拄杖盲学轻声码
【写在前面】
编撰这篇文章还得从之前做安全业务需求说起,我们都知道安全攻击都是在某台客户机上执行某些恶意操作(sql注入,DoS/DDoS攻击),致使服务端响应异常崩溃亦或响应数据被篡改,那么怎么去阻止这些东西呢?
首先我想到的是对访问的web端做一个IP的校验(好比阿里云服务器的安全组设置),建立一些白名单,这样能在很大程度上做到一个限制,其实在服务端也应该要开启防火墙、设置权限等。那么我们首先得知道客户端的IP是多少。接下来此文重点介绍如何获取。
1、如何获取客户端访问IP
其实获取IP是最简单的,因为只要有请求的话,都会存放在session里面的,只要通过下面这句话就可以拿到你所需要的IP,但是如何知道别人访问你的服务器呢,这个时候就需要您自己去写一个监听事件listen;
获取IP方式如下代码即可:
HttpSession session = request.getSession(false); if (session == null) { session = request.getSession(); System.out.println("session:" + session + "创建成功"); session.setAttribute("ip", request.getRemoteAddr()); System.out.println("----访问的IP是:"+request.getRemoteAddr()+"----"); }
控制台输出:
2、如何通过IP获取归属地(离线+在线)
通过上面的方式拿到了IP地址,那么我想知道是哪些地方的人访问了我们的系统的话这就需要后台去进行查询了,这才是这篇文章的核心:
2.1 离线模式
主要是通过自己本地的离线库来实现查找的,有个弊端就是需要不断的更新。
第一步:下载离线包ip2region.xdb
首先下载一个离线的IP归属映射包ip2region.xdb,没有的可以去我的百度云盘上下载
下载地址如下:
链接:https://pan.baidu.com/s/1l_Gfhl0TVPYXvpK9QSiXyw
提取码:hdd6
第二步:引入离线包
将我们的离线包放在resources目录下,如下图所示:
Maven引入
打开项目中的pom.xml文件,将下面的代码复制到里面去(如果有则忽略):
<!-- ip2region --> <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.6.5</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> </dependency>
开始引入时候可能会报红,需要你自己去更新一下maven库
没有报红表示本地引入成功。
Pom.xml引入静态打包(特别关键,不然会报错)
[Xxx/ip2region.xdb] cannot be opened because it does not exist
<resource> <directory>src/main/resources</directory> <includes> <include>jdbc.properties</include> <include>*.xml</include> <include>ipdb/*.xdb</include> </includes> </resource>
主要是在构建的时候我们java会变成class文件进行编译,一些静态资源需要自己手动去加才能打到jar包里面去。
第三步:代码实现
控制台效果如下所示(国内国外的都有):
核心实现代码(记得要引入一些依赖包哟):
String dbPath = "/ipdb/ip2region.xdb"; try { InputStream inputStream = new ClassPathResource(dbPath).getInputStream(); byte[] dbBinStr = FileCopyUtils.copyToByteArray(inputStream); // 创建一个完全基于内存的查询对象 searcher = Searcher.newWithBuffer(dbBinStr); } catch (Exception e) { System.out.printf("failed to create content cached searcher: %s\n", e); } //把ip2r String address = ""; try { address = searcher.search("66.249.79.193"); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("=== 访问者的地址为:"+address+" === ");
到这里我们就只要维护好那个离线包文件就可以,定时更新一下。
2.2 在线模式
主要通过别人或者官网提供的API接口去实现查询的功能,有个弊端就是特别依赖别人的服务器,万一别人服务器挂了就访问不了了。
具体实现效果和2.1离线模式介绍的一样
主要实现我封装到一个java类里面,写了一些特定的方法;
如下所示:
public static String getAddress(String ip) { try { URL realUrl = new URL("http://whois.pconline.com.cn/ipJson.jsp?ip=" + ip + "&json=true"); HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); conn.setRequestMethod("GET"); conn.setUseCaches(false); conn.setReadTimeout(6000); conn.setConnectTimeout(6000); conn.setInstanceFollowRedirects(false); int code = conn.getResponseCode(); StringBuilder sb = new StringBuilder(); String ipaddr = ""; if (code == 200) { InputStream in = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; while ((line = reader.readLine()) != null) { sb.append(line); } ipaddr = ip + "=" + sb.substring(sb.indexOf("addr") + 7, sb.indexOf("regionNames") - 3); } return ipaddr; } catch (Exception e) { e.printStackTrace(); return null; } }
调用地方如下所示:
String address = IpAddressUtils.getAddress("66.249.79.193"); System.out.println("=== (在线)访问者的地址为:"+address+" === ");
3、推荐方式,先离线后在线
【重要】其实我们可以结合两个使用一起,先采用离线,如果发现为null的话则调用在线查询的方式。这样在一定的程度上能够保证数据的完整性,都有不足的话就互补一下;如下所示逻辑:
System.out.println("--- (在线+离线)访问者的IP为:66.249.79.193 --- "); //================离线模式获取=start====================// String dbPath = "/ipdb/ip2region.xdb"; try { InputStream inputStream = new ClassPathResource(dbPath).getInputStream(); byte[] dbBinStr = FileCopyUtils.copyToByteArray(inputStream); // 创建一个完全基于内存的查询对象 searcher = Searcher.newWithBuffer(dbBinStr); } catch (Exception e) { System.out.printf("failed to create content cached searcher: %s\n", e); } //把ip2r String address = ""; try { address = searcher.search("221.231.220.212"); } catch (Exception e) { throw new RuntimeException(e); } // String address = IpAddressUtils.getCityInfo("66.249.79.193"); System.out.println("=== (离线)访问者的地址为:"+address+" === "); //================离线模式获取=end====================// //======================在线模式获取 start========================// if("".equals(address)){ address = IpAddressUtils.getAddress("66.249.79.193"); System.out.println("=== (在线)访问者的地址为:"+address+" === "); } //======================在线模式获取 end========================//
4、最后
以上就是Java实现通过IP获取IP归属地的方法(离线+在线)的详细内容,更多关于Java获取IP归属地的资料请关注脚本之家其它相关文章!