package controller;import java.util.Scanner;import manager.DataProcessManager;public class SystemController {@SuppressWarnings("resource")public static void main(String[] args) {// 接收用户输入Scanner scanner = new Scanner(System.in);while (true) {System.out.println("请输入IP地址 : ");String ip = scanner.nextLine();// 查询long startTime = System.currentTimeMillis();String location = DataProcessManager.getLocation(ip);long endTime = System.currentTimeMillis();System.out.println("总耗时 : " + (endTime - startTime) + "  "+ location);}}}
package manager;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import pojo.IPAndLocationPojo;
import utli.FileOperatorUtil;
import utli.IPUtil;
import utli.RegexUtil;
import utli.SerDeUtil;
import utli.StaticValue;
/*** 程序核心业务类**/
public class DataProcessManager {private static IPAndLocationPojo[] ipAndLocationPojoArray = null;static {// 保存数据对象List<IPAndLocationPojo> ipAndLocationPojos = null;// 判断是否有序列化的文件File file = new File(StaticValue.serdeObiFilePath);if (file.exists()) {// TODOlong startTime = System.currentTimeMillis();// 如果存在 就反序列化try {Object obj = SerDeUtil.getObj(StaticValue.serdeObiFilePath,StaticValue.cacheByteArrayLength);ipAndLocationPojoArray = (IPAndLocationPojo[]) obj;} catch (ClassNotFoundException | IOException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println("反序列化,耗时 : " + (endTime - startTime));} else {// 不存在 就读取数据 并且结构化 排序 然后 进行序列化try {// 获取数据ipAndLocationPojos = DataProcessManager.getPojoList(StaticValue.ipLibrayPath, StaticValue.encoding);// 转数组并排序// TODOlong startTime = System.currentTimeMillis();ipAndLocationPojoArray = DataProcessManager.convertListToArraySort(ipAndLocationPojos);// 序列化SerDeUtil.saveObj(ipAndLocationPojoArray,StaticValue.serdeObiFilePath,StaticValue.cacheByteArrayLength);long endTime = System.currentTimeMillis();System.out.println("转数组并排序序列化,耗时 : " + (endTime - startTime));} catch (IOException e) {e.printStackTrace();}}}/*** 对外提供的接口,入参是IP,出参是归属地* * @param ip* @return*/public static String getLocation(String ip) {// 校验IPif (!RegexUtil.isValidIP(ip)) {return "请输入正确的IP地址";}// 二分法查找int index = DataProcessManager.binaraySeach(ipAndLocationPojoArray, ip);// 判断是否找到if (index == -1) {return null;} else {return ipAndLocationPojoArray[index].getLocation();}}/*** 二分法查找,入参是IP和数组,出参是对应的索引,找不到返回-1* * @param ipAndLocationPojoArray* @param targetIP* @return* @throws IOException*/private static int binaraySeach(IPAndLocationPojo[] ipAndLocationPojoArray,String targetIP) {// 把IP转换为longlong targetIPLong = IPUtil.ipToLong(targetIP);int startIndex = 0;int endIndex = ipAndLocationPojoArray.length - 1;int m = (startIndex + endIndex) / 2;/*** 如果 小于 起始IP 找前面* * 如果 大于 结束IP 找后面* * 如果 大于等于起始IP且 小于等于 结束IP 则说明找到了*/while (startIndex <= endIndex) {if (targetIPLong >= ipAndLocationPojoArray[m].getStartIPLong()&& targetIPLong <= ipAndLocationPojoArray[m].getEndIPLong()) {return m;}if (targetIPLong < ipAndLocationPojoArray[m].getStartIPLong()) {endIndex = m - 1;} else {startIndex = m + 1;}m = (startIndex + endIndex) / 2;}return -1;}/*** 把集合转换为数组并排序* * @param ipAndLocationPojos* @return*/private static IPAndLocationPojo[] convertListToArraySort(List<IPAndLocationPojo> ipAndLocationPojos) {// 创建数组IPAndLocationPojo[] ipAndLocationPojoArray = new IPAndLocationPojo[ipAndLocationPojos.size()];// 转换为数组ipAndLocationPojos.toArray(ipAndLocationPojoArray);// 排序Arrays.sort(ipAndLocationPojoArray);return ipAndLocationPojoArray;}/*** 结构化数据集合* * @param filePath* @param encoding* @return* @throws IOException*/private static List<IPAndLocationPojo> getPojoList(String filePath,String encoding) throws IOException {// 保存数据对象List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();// TODOlong startTime = System.currentTimeMillis();List<String> lineList = FileOperatorUtil.getLineList(filePath, encoding);long endTime = System.currentTimeMillis();System.out.println("读取数据,耗时 : " + (endTime - startTime));startTime = System.currentTimeMillis();for (String string : lineList) {// 判断是否是空行if (string == null || string.trim().equals("")) {continue;}// 分割为数组String[] columnArray = string.split("    ");// 获取起始IPString startIP = columnArray[0];// 获取结束IPString endIP = columnArray[1];// 获取归属地String location = columnArray[2];// 封装到对象中IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(startIP, endIP, location);// 添加到集合中ipAndLocationPojos.add(ipAndLocationPojo);}endTime = System.currentTimeMillis();System.out.println("结构化数据,耗时 : " + (endTime - startTime));return ipAndLocationPojos;}}
package pojo;
import java.io.Serializable;
import utli.IPUtil;
public class IPAndLocationPojo {private static final long serialVersionUID = 1L;// 衍生字段,用于保存IP对应的long值private long startIPLong;private long endIPLong;/*** 起始IP*/private transient String startIP;/*** 结束IP*/private transient String endIP;/*** 归属地*/private String location;public int compareTo(IPAndLocationPojo o) {long status = this.startIPLong - o.startIPLong;// 不能强制转换 , 如果两个值相差 2147483647的话,转换为int之后 得到负数// return (int) (this.startIPLong - o.startIPLong);return status > 0 ? 1 : 0;}public String getStartIP() {return startIP;}public long getStartIPLong() {return startIPLong;}public void setStartIPLong(long startIPLong) {this.startIPLong = startIPLong;}public long getEndIPLong() {return endIPLong;}public void setEndIPLong(long endIPLong) {this.endIPLong = endIPLong;}public void setStartIP(String startIP) {this.startIP = startIP;}public String getEndIP() {return endIP;}public void setEndIP(String endIP) {this.endIP = endIP;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public IPAndLocationPojo(String startIP, String endIP, String location) {super();this.startIP = startIP;this.endIP = endIP;this.location = location;// 对长整型赋值this.startIPLong = IPUtil.ipToLong(startIP);this.endIPLong = IPUtil.ipToLong(endIP);}public IPAndLocationPojo() {super();}@Overridepublic String toString() {return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP+ ", location=" + location + "]";}}
package utli;import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;public class FileOperatorUtil {/*** 读取文件并返回list集合* * @param filePath*            文件路径* @param encoding*            字符编码* @return* @throws IOException*/public static List<String> getLineList(String filePath, String encoding)throws IOException {// 2 节点流对接文件FileInputStream fis = new FileInputStream(filePath);// 3 转换为字符流并指定字符编码Reader reader = new InputStreamReader(fis, encoding);// 4 缓冲流提高效率BufferedReader br = new BufferedReader(reader);// 5 读取String line = null;// 保存读取的数据List<String> lineList = new ArrayList<String>();while ((line = br.readLine()) != null) {// 添加到集合中lineList.add(line);}// 6 关闭br.close();return lineList;}}
package utli;public class IPUtil {public static void main(String[] args) {String ip = "126.56.78.59";long ipLong = ipToLong(ip);System.out.println(ipLong);System.out.println(longToIP(ipLong));}/*** 将127.0.0.1形式的IP地址转换成十进制整数,这里没有进行任何错误处理* 通过左移位操作(<<)给每一段的数字加权,第一段的权为2的24次方,第二段的权为2的16次方,第三段的权为2的8次方,最后一段的权为1*/public static long ipToLong(String ipaddress) {long[] ip = new long[4];// 先找到IP地址字符串中.的位置int position1 = ipaddress.indexOf(".");int position2 = ipaddress.indexOf(".", position1 + 1);int position3 = ipaddress.indexOf(".", position2 + 1);// 将每个.之间的字符串转换成整型ip[0] = Long.parseLong(ipaddress.substring(0, position1));ip[1] = Long.parseLong(ipaddress.substring(position1 + 1, position2));ip[2] = Long.parseLong(ipaddress.substring(position2 + 1, position3));ip[3] = Long.parseLong(ipaddress.substring(position3 + 1));return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];}/*** 将十进制整数形式转换成127.0.0.1形式的ip地址 将整数值进行右移位操作(>>>),右移24位,右移时高位补0,得到的数字即为第一段IP。* 通过与操作符(&)将整数值的高8位设为0,再右移16位,得到的数字即为第二段IP。* 通过与操作符吧整数值的高16位设为0,再右移8位,得到的数字即为第三段IP。 通过与操作符吧整数值的高24位设为0,得到的数字即为第四段IP。*/public static String longToIP(long ipaddress) {StringBuffer sb = new StringBuffer("");// 直接右移24位sb.append(String.valueOf((ipaddress >>> 24)));sb.append(".");// 将高8位置0,然后右移16位sb.append(String.valueOf((ipaddress & 0x00FFFFFF) >>> 16));sb.append(".");// 将高16位置0,然后右移8位sb.append(String.valueOf((ipaddress & 0x0000FFFF) >>> 8));sb.append(".");// 将高24位置0sb.append(String.valueOf((ipaddress & 0x000000FF)));return sb.toString();}}
package utli;import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 正则表达式工具类***/
public class RegexUtil {/*** 校验IP* */public static boolean isValidIP(String input){String regex="(?=(\\b|\\D))(((\\d{1,2})|(1\\d{1,2})|(2[0-4]\\d)|(25[0-5]))\\.){3}((\\d{1,2})|(1\\d{1,2})|(2[0-4]\\d)|(25[0-5]))(?=(\\b|\\D))";return isValid(regex,input);}/*** 格式校验 全词匹配* */public static boolean isValid(String regex,String input){//创建引擎对象Pattern pattern=Pattern.compile(regex);//创建匹配器Matcher matcher=pattern.matcher(input);return matcher.matches();}}
package utli;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;/*** 序列化相关工具类* **/
public class SerDeUtil {/*** 序列化*/public static void saveObj(Object obj,String filePath,int cacheByteArrayLength)throws IOException{//1 序列化FileOutputStream fos=new FileOutputStream(filePath);//字节数组流ByteArrayOutputStream baos=new ByteArrayOutputStream(cacheByteArrayLength);//数据写出到字节数组中oos.writeObject(obj);//转换为字节数组byte[]byteArray=baos.toByteArray();oos.flush();oos.close();fos.write(byteArray);fos.close();}/*** 反序列化*/public static Object getObj(String filePath,int cacheByteArrayLength)throws IOException,ClassNotFoundException{//2 反序列化FileInputStream fis=new FileInputStream(filePath);byte[]byteArray=new byte[cacheByteArrayLength];//数据读取到字节数组中fis.read(byteArray);fis.close();//字节数组缓冲流ByteArrayInputStream bais=new ByteArrayInputStream(byteArray);ObjectInputStream ois=new ObjectInputStream(bais);Object obj=ois.readObject();ois.close();return obj;}
}
package utli;
/*** 集中的静态变量***/
public class StaticValue {//序列化之后的文件名public static String serdeObiFilePath="ipLibObj.data";//地址库文件路径public static String ipLibrayPath="ip_location_relation.txt";//字符编码public static String encoding="UTF-8";//序列化文件大小public static int cacheByteArrayLength=25*1024*1024;}

IP地址归属地查询完整版相关推荐

  1. IP地址 归属地查询

    目标 通过开发IP地址归属地查询平台,我们需要对JavaSE综合技术有所提升,增强实战能力.学习完该项目我们应该具备如下能力: 1 面向对象程序设计 2 工具类封装与使用写法 3 文件IO流 4 字符 ...

  2. 分享2020 几个好用的ip地址归属地查询

    ip地址归属地查询接口 一.百度 大公司,不必说,肯定好用,我就一直用的他作为主要查询接口. url:http://opendata.baidu.com/api.php params:query=ip ...

  3. 实现调用阿里云API第二章——API调用实战(全球IP地址归属地查询)

    本篇将实现利用springboot实现阿里云API调用实战. 一.购买阿里云API https://market.aliyun.com/data?spm=5176.9502607.1387859.3. ...

  4. python查询ip归属地_基于Python的免费IP地址归属地查询

    一.开通接口 IP地址归属地查询服务使用聚合数据提供的免费接口,每天可以100次免费调用.可以通过 https://www.juhe.cn/docs/api/id/1 注册及开通. 二.请求接口 #! ...

  5. [转载]手机号码IP地址归属地查询

    详情点击:http://yoursunny.com/work/MobileIPquery/ 注:调用的数据相对比较准确,可将改功能加以改造并应用于本地论坛及门户站的用户注册控制上来,防止恶意注册,控制 ...

  6. Spark系列四:Spark的经典入门案列之ip地址归属地查询

    目录 概述 代码实现 单级模式 分布式模式 方案一: 方案二: 工具类 提示:所有需要的文件我全部放在资源里面了,可以自行下载 概述 需求:根据访问日志的ip地址计算出访问者的归属地,并且按照省份,计 ...

  7. IP地址归属地查询接口

     1.新浪IP API: 新浪这个应该说是最不错的.并且返回的数据类型为可以自定义格式(默认为纯文本格式,根据format的参数定义,还可以返回JS.Json格式.下面列举的是JS的格式). ht ...

  8. python对ip地址归属地查询笔记

    所有笔记内容均来源于 爱课程 的北京理工大学嵩天教授课程,版权归属于嵩天老师所有. import requests #导入网页爬取库 url = "http://m.ip138.com/ip ...

  9. IP地址归属地在线查询平台

    一.项目介绍 1.背景 根据IP得到位置,加标签 进行大数据分析,比如淘宝推荐等提供优质数据 www.ip.cn 等 查询IP 2.需求 IP 分析 归属地信息 , 查找在毫秒内完成 IP地址库,公网 ...

最新文章

  1. 面试 6:调整数组顺序使奇数位于偶数前面
  2. Python 文件读取与写入操作方法
  3. MCMC采样和M-H采样
  4. top命令---Linux学习笔记
  5. 用promise封装ajax_ES6-promise封装AJAX请求
  6. 前沿 | 阿里达摩院最牛科技~摄像头ISP处理器,提升夜间识别精准率
  7. can总线报文是固定的吗_CAN总线传输协议
  8. go 怎么等待所有的协程完成_怎么关闭golang协程
  9. java 单例 并发_完美的单例实现(The Perfect Singleton)
  10. 【架构师面试题库1】—etcd高可用集群搭建
  11. Eclipse中JAVA项目的打包
  12. mysql5.7.11解压安装_mysql 5.7.11解压安装教程
  13. 设计模式 (十七) 迭代器模式
  14. 网页访问计数器 html,网页计数器(访问量)
  15. 移动端获取手机网络信息
  16. fastreport 横向分栏_fastreport分栏分组显示问题(急贴盼解决)
  17. smbd cpu高 linux,Samba smbd vfs.c访问限制绕过漏洞(CVE-2015-5252)
  18. vim 的操作说明:
  19. 解决源码编译Python3后缺少ssl tkinter,bz2等库的问题
  20. 通过python smtplib库添加右抄送和密送人

热门文章

  1. 菜单栏点击显示二级菜单_显示完整菜单
  2. 用C语言实现一个cat命令
  3. HIVE基本查询操作(二)——第1关:Hive排序
  4. Echarts -盒须图的使用说明
  5. XXX高校信息安全服务解决方案
  6. 微信小程序文字两边添加横线
  7. 2022“杭电杯”中国大学生算法设计超级联赛(1)C.Backpack
  8. MxNet系列——Windows上安装MxNet
  9. 游戏模型外包-【精刚石数位】
  10. 同一文件夹下多个word文档合并