Day-30

IP归属地在线查询平台

一   项目介绍

  1. 背景

根据IP得到位置,加标签

进行大数据分析,比如淘宝推荐等提供优质数据

www.ip.cn 等 查询IP       

     2.需求

IP 分析 归属地信息 , 查找在毫秒内完成

IP地址库,公网都是开放的

IANA : 国际组织,负责公网IP维护分发

      3.技术栈

Eclipse ,JavaSE中面向对象、IO流、二分法算法、Base64编码、工具类封装

        4.目标

通过开发IP地址归属地查询平台,我们需要对JavaSE综合技术有所提升,增强实战能力。学习完该项目我们应该具备如下能力:

1 面向对象程序设计

2 工具类封装与使用写法

3 文件IO流

4 字符串处理

5 二分法查找

6 IP地址的不同形式的使用

二        相关问题

强化项目思维

不管好方法还是差方法,先尝试把功能实现

再考虑对代码进行优化,最优为止

三        主要思路

1 解析提供的地址库字符串,为结构化数据格式

2 基于结构化数据构建成某个数据结构,加速给定IP地址的查找速度

3 封装成响应的工具类API,开放其响应的方法,即给定IP地址可以再ms内计算得到其位置信息

4 工具类只有一个入参一个出参

入参是IP

出参是地址

四        研发项目分类

1 应用开发类项目

解决某些特定功能而开发的应用软件,比如QQ,微信,Eclipse等

2 Web开发类 项目

以B/S架构为主,也就是网页形式访问的在线系统,如各类官网等

3 中小型应用类开发项目的流程

1 需求概述 : 需求描述,说清楚你要干什么,为什么做这个

在互联网公司中,根据IP地址获取归属地信息是非常广泛的,开发的这个项目就能解决这个问题

2 需求分析 : 需要根据需求概述,用技术角度来看一下这个项目是否可行

可行性一定是可以做的

需求分析的梳理

三方面 : 输入,输出,已具备的物料(前置条件)

输入 : 给定任意一个IP地址

输出 : 返回IP对应的归属地

前置条件 :

IP地址库

JavaSE

面向对象

IO

常用类

二分法

正则表达式校验

3 开发步骤拆分,可以理解为解耦,把一个拆分为多个

1 读取IP地址库

2 解析IP地址每行数据,进行结构化

找到无结构化数据的规则,进行结构化处理

简单来说,就是根据需求,生成实体类

Entity/model : 实体类,一般该类和数据库表是一一对应的

DTO : 先不管

Pojo : 无特殊意义,纯粹的业务对象

3 把对象加入List中

4 转换为数组,方便二分法操作

为什么不直接转换为数组?

数组长度问题,不清楚有多少行,有多少空行等

ArrayList转数组,不会消耗很多时间,因为底层就是数组

5 解决二分法查找的技术问题

6 完成比较逻辑

7 对外提供访问接口

8 测试

4 细节开发与风险控制

5 BUG修复,调优,标准化

6 正式上线

7 项目总结,项目复盘

五丶 代码研发

1.无脑读取文件

在test文件夹下 创建 TestFileIO_01.java

package com;

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.io.Reader;

/**

 * 1 定义文件路径

 *

 * 2 通过节点流对接到文本上

 *

 * 3 将节点流转换为字符流

 *

 * 4 通过缓冲流对接到输入流

 *

 * 5 读取

 *

 * 6 关闭流

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:06:32

 */

public class TestFileIO_01 {

         public static void main(String[] args) {

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  try (

                  // 字节流

                  FileInputStream fis = new FileInputStream(ipLibrartPath);

                                   // 转换为字符流

                                   Reader reader = new InputStreamReader(fis, encoding);

                                   // 封装缓冲流

                                   BufferedReader br = new BufferedReader(reader);) {

                          String temp = null;

                          while ((temp = br.readLine()) != null) {

                                   System.out.println(temp);

                          }

                  } catch (Exception e) {

                          e.printStackTrace();

                  }

         }

}

2.文本文件读取工具类

工具类封装 :

1 先写测试类,确认输入与输出技术问题

2 抽象出了输入与输出,形成方法的入参和出参

3 工具代码实现,测试

2.1 工具类

package com.tledu.zrz.util;

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;

/**

 * 读取文件

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:17:26

 */

public class FileOperatorUtil {

         /**

          * 读取文件,并返回List

          *

          * @param txtFilePath

          *            字符串格式的文件路径

          * @param encoding

          *            字符编码

          * @return

          * @throws IOException

          */

         public static List<String> getLineList(String txtFilePath, String encoding)

                          throws IOException {

                 List<String> lineLine = new ArrayList<String>();

                 // 字节流

                 FileInputStream fis = new FileInputStream(txtFilePath);

                 // 转换为字符流

                 Reader reader = new InputStreamReader(fis, encoding);

                 // 封装缓冲流

                 BufferedReader br = new BufferedReader(reader);

                 String temp = null;

                 while ((temp = br.readLine()) != null) {

                          lineLine.add(temp);

                 }

                 // 关闭资源

                 br.close();

                 return lineLine;

         }

}

2.2        测试工具类

package com;

import java.io.IOException;

import java.util.List;

import com.tledu.zrz.util.FileOperatorUtil;

/**

 * 测试工具类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:06:32

 */

public class TestFileIO_02 {

         public static void main(String[] args) throws IOException {

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                  for (String string : lineList) {

                          System.out.println(string);

                  }

         }

}

3.        数据结构化

1 可以找无结构化数据的组织规则,进行抽象,转换为结构化

2 根据数据组织进行数据抽象

3 解析数据,保存到对应的对象中

Model,pojo,dto

4.抽象pojo类

4.1抽象封装

package com.tledu.zrz.pojo;

/**

 * 结构化实体类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:29:50

 */

public class IPAndLocationPojo {  

         @Override

         public String toString() {

                 return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP

                                   + ", location=" + location + "]";

         }

         /**

          * 起始IP

          */

         private String startIP;

         /**

          * 结束IP

          */

         private String endIP;

         /**

          * 归属地

          */

         private String location;

         public String getStartIP() {

                 return startIP;

         }

         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;

         }

         public IPAndLocationPojo() {

                 super();

         }

}

4.2           数据拆分,转换为对象

package com;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

/**

 * 转换为结构化对象

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:32:39

 */

public class TestNonStructToStruct_01 {

         public static void main(String[] args) throws IOException {

                 // 地址库文件

                 String ipLibrartPath = "ip_location_relation.txt";

                 // 字符编码

                 String encoding = "utf-8";

                 List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                 List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                 // 遍历 获取每一行

                 for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                           columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                 }

                 // 遍历集合

                 for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {

                          System.out.println(ipAndLocationPojo);

                 }

         }

}

5.封装DataProcessManager类

5.1把数据封装到对象中并保存list里面

package com.tledu.zrz.manager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

/**

 * 该类为项目中管理类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:45:19

 */

public class DataProcessManager {

         /**

          * 把读取到的List<String> 转换为 List<IPAndLocationPojo>

          *

          * @param ipLibrartPath

          * @param encoding

          * @return

          * @throws IOException

          */

         public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,

                          String encoding) throws IOException {

                  List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                  List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                  // 遍历 获取每一行

                  for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                            columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                  }

                  return ipAndLocationPojos;

         }

}

5.2        测试

package com;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import com.tledu.zrz.manager.DataProcessManager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

/**

 * 转换为结构化对象

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:32:39

 */

public class TestNonStructToStruct_02 {

         public static void main(String[] args) throws IOException {

                 // 地址库文件

                 String ipLibrartPath = "ip_location_relation.txt";

                 // 字符编码

                 String encoding = "utf-8";

                 List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath, encoding);

                 for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {

                          System.err.println(ipAndLocationPojo);

                 }

         }

}

6.结构化集合转换为数组

package com;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import com.tledu.zrz.manager.DataProcessManager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

public class TestListToArray_01 {

         public static void main(String[] args) throws IOException {

                  List<String> list = new ArrayList<String>();

                  list.add("a");

                  list.add("b");

                  list.add("c");

                  list.add("d");

                  String[] arr = new String[list.size()];

                  list.toArray(arr);

                  for (String string : arr) {

                          System.out.println(string);

                  }

                  // 业务数据

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

                                   .getPojoList(ipLibrartPath, encoding);

                  IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[ipAndLocationPojos

                                   .size()];

                  ipAndLocationPojos.toArray(ipLocationPojoArr);

                  for (IPAndLocationPojo ipAndLocationPojo : ipLocationPojoArr) {

                          System.out.println(ipAndLocationPojo);

                  }

         }

}

7.对象数组排序

7.1实现排序

1 自定义实现

冒泡,选择

2 API

Collections,Arrays

7.2排序注意事项

1 被排序的元素必须具有可比性

实现Comparable接口

有比较器类Comparator

7.3排序案例

package com;

import java.util.Arrays;

public class TestArrySort_01 {

         public static void main(String[] args) {

                  // 数字 : 从小到大

                  // 字符串 : ASCII码

                  // 日期 : 自然日期

                  // 因为 Integer,String,Date 都实现了Comparable接口

                  int[] intArray = { 1, 13, 24, 7, 4 };

                  Arrays.sort(intArray);

                  for (int i : intArray) {

                          System.out.println(i);

                  }

                  A a1 = new A(18, "张三1");

                  A a2 = new A(19, "张三2");

                  A a3 = new A(15, "张三3");

                  A a4 = new A(12, "张三4");

                  A[] a = { a1, a2, a3, a4 };

                  Arrays.sort(a);

                  for (A a5 : a) {

                          System.out.println(a5);

                  }

         }

}

class A implements Comparable<A>{

         private int age;

         private String name;

         public int getAge() {

                  return age;

         }

         public void setAge(int age) {

                  this.age = age;

         }

         public String getName() {

                  return name;

         }

         public void setName(String name) {

                  this.name = name;

         }

         public A(int age, String name) {

                  super();

                  this.age = age;

                  this.name = name;

         }

         @Override

         public String toString() {

                  return "A [age=" + age + ", name=" + name + "]";

         }

         @Override

         public int compareTo(A o) {

                  return age-o.age;

         }

}

7.4总结

要么实现排序的类 实现Comparable接口

7.5业务问题

由于IP是字符串,而字符串比较ASCII码

比如 1.1.6.32  , 1.1.128.23 理论上应该是后面的大

但是按照ASCII码比较的话,前面的大

所以我们需要把IP转换为long类型进行比较即可

package com.tledu.zrz.util;

/**

 * IP和long类型之间的转换

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 下午2:51:10

 */

public class IPUtil {

         public static void main(String[] args) {

                  long x = ipToLong("120.211.144.131");

                  System.out.println(x);

                  String s = longToIp(x);

                  System.out.println(s);

         }

         private static Long ipToLong(String ipStr) {

                  long ipLong = 0;

                  if (ipStr != null && ipStr.length() > 0) {

                          // 将ip(点分十进制的形式 a.b.c.d) 地址按.分割

                          String[] ipSplit = ipStr.split("\\.");

                          try {

                                   if (ipSplit.length != 4) {

                                            throw new Exception("IP Format Error");

                                   }

                                   for (int i = 0; i < ipSplit.length; i++) {

                                            int temp = Integer.parseInt(ipSplit[i]);

                                            ipLong += temp * (1L << (ipSplit.length - i - 1) * 8);

                                   }

                          } catch (Exception e) {

                                   e.printStackTrace();

                          }

                  } else {

                  }

                  return ipLong;

         }

         /**

          * 将long型IP地址转换回点分十进制表示的字符串类型

          *

          * @param ipLong

          * @return java.lang.String

          * @throws Exception

          */

         private static String longToIp(long ipLong) {

                  StringBuffer ipStr = new StringBuffer();

                  try {

                          if (ipLong < 0) {

                                   throw new Exception("Can not to IP...");

                          }

                          // 最高8位,直接右移24位

                          ipStr.append((ipLong >>> 24));

                          ipStr.append(".");

                          // 将高8位设置0,然后右移16位

                          ipStr.append(((ipLong & 0x00FFFFFF) >>> 16));// 获得高8位,6个f对应的是24个1,最高8位设置空为0,之后右移16位将前面多余的16位去掉,以下类推即可

                          ipStr.append(".");

                          // 将高16位设置0,然后右移8位

                          ipStr.append((ipLong & 0x0000FFFF) >>> 8); // 前16位

                                                                                                                          // 设置0,移除低8位,16个1,高16位设置为0

                          ipStr.append(".");

                          // 将高24位设置0

                          ipStr.append(ipLong & 0x000000FF); // 前24位 设置0,留低8位,8个1,高24位设置为0

                  } catch (Exception e) {

                          e.printStackTrace();

                  }

                  return ipStr.toString();

         }

}

7.6Pojo添加衍生字段

实体类中衍生两个字段,用来存储转换为long类型之后的值

package com.tledu.zrz.pojo;

import com.tledu.zrz.util.IPUtil;

/**

 * 结构化实体类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:29:50

 */

public class IPAndLocationPojo implements Comparable<IPAndLocationPojo> {

         @Override

         public String toString() {

                  return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP

                                   + ", location=" + location + "]";

         }

         /**

          * 起始IP

          */

         private String startIP;

         // 衍生字段

         private long startIPLong;

         private long endIPLong;

         /**

          * 结束IP

          */

         private String endIP;

         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;

         }

         /**

          * 归属地

          */

         private String location;

         public String getStartIP() {

                  return startIP;

         }

         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();

         }

         @Override

         public int compareTo(IPAndLocationPojo o) {

                  // 因为IP段没有交集,所以使用起始和结束 比较 都是可以的

                  long result = startIPLong - o.startIPLong;

                  if (result > 0) {

                          return 1;

                  } else if (result < 0) {

                          return -1;

                  } else {

                          return 0;

                  }

         }

}

7.7测试Pojo排序

package com;

import java.io.IOException;

import java.util.Arrays;

import java.util.List;

import com.tledu.zrz.manager.DataProcessManager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

public class TestArrySort_02 {

         public static void main(String[] args) throws IOException {

                 // 地址库文件

                 String ipLibrartPath = "ip_location_relation.txt";

                 // 字符编码

                 String encoding = "utf-8";

                 // 获取数据

                 List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

                                   .getPojoList(ipLibrartPath, encoding);

                 // 转换为数组

                 IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[ipAndLocationPojos

                                   .size()];

                 ipAndLocationPojos.toArray(ipLocationPojoArr);

                 // 排序

                 Arrays.sort(ipLocationPojoArr);

                 // 测试首位元素

                 System.out.println(ipLocationPojoArr[0]);

                 System.out.println(ipLocationPojoArr[ipLocationPojoArr.length-1]);

         }

}

7.8封装排序

package com.tledu.zrz.manager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

/**

 * 该类为项目中管理类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:45:19

 */

public class DataProcessManager {

         /**

          * 将对象集合转换为对象数组并排序

          *

          * @param pojoList

          * @return

          */

         public static IPAndLocationPojo[] convertListToArrayAndSort(

                          List<IPAndLocationPojo> pojoList) {

                 // 转换为数组

                 IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList

                                   .size()];

                 pojoList.toArray(ipLocationPojoArr);

                 // 排序

                 Arrays.sort(ipLocationPojoArr);

                 return ipLocationPojoArr;

         }

         /**

          * 把读取到的List<String> 转换为 List<IPAndLocationPojo>

          *

          * @param ipLibrartPath

          * @param encoding

          * @return

          * @throws IOException

          */

         public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,

                          String encoding) throws IOException {

                 List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                 List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                 // 遍历 获取每一行

                 for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                           columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                 }

                 return ipAndLocationPojos;

         }

}

7.9测试

package com;

import java.io.IOException;

import java.util.Arrays;

import java.util.List;

import com.tledu.zrz.manager.DataProcessManager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

public class TestArrySort_03 {

         public static void main(String[] args) throws IOException {

                 // 地址库文件

                 String ipLibrartPath = "ip_location_relation.txt";

                 // 字符编码

                 String encoding = "utf-8";

                 // 获取数据

                 List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

                                   .getPojoList(ipLibrartPath, encoding);

                 // 转换为数组

                 IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager.convertListToArrayAndSort(ipAndLocationPojos);

                 // 测试首位元素

                 System.out.println(ipLocationPojoArr[0]);

                 System.out.println(ipLocationPojoArr[ipLocationPojoArr.length-1]);

         }

}

8        二分法

二分法查询,必须建立在已排序的基础上

8.1基本类型

          public static void main(String[] args) {

          // 基础类型

          int[] intArray = {1,3,5,7,9,11,100,900};

          int aid = 9200;

          int startIndex = 0;

          int endIndex = intArray.length-1;

          int m = (endIndex+startIndex)/2;

          while (startIndex <= endIndex) {

          if (aid == intArray[m]) {

          System.out.println(m);

          return;

          }else if (aid > intArray[m]) {

          startIndex = m+1;

          }else{

          endIndex = m -1;

          }

          m=(startIndex+endIndex)/2;

          }

          System.out.println("没找着");

          }

8.2引用/复杂类型

public static void main(String[] args) {

          User u1 = new User(18);

          User u2 = new User(19);

          User u3 = new User(20);

          User u4 = new User(21);

          User u5 = new User(22);

          // 复杂类型

          User[] intArray = { u1, u2, u3, u4, u5 };

          int aid = 23;

          int startIndex = 0;

          int endIndex = intArray.length - 1;

          int m = (endIndex + startIndex) / 2;

          while (startIndex <= endIndex) {

          if (aid == intArray[m].getAge()) {

          System.out.println(m);

          return;

          } else if (aid > intArray[m].getAge()) {

          startIndex = m + 1;

          } else {

          endIndex = m - 1;

          }

          m = (startIndex + endIndex) / 2;

          }

          System.out.println("没找着");

        

          }

8.3业务类实现

public static void main(String[] args) throws IOException {

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  // 获取数据

                  List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

                                   .getPojoList(ipLibrartPath, encoding);

                  // 转换为数组

                  IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager

                                   .convertListToArrayAndSort(ipAndLocationPojos);

                  // 用户输入的IP

                  // String aid = "125.152.1.22";

                  String aid = "120.211.144.131";

                  // 转换为long类型

                  long ipLong = IPUtil.ipToLong(aid);

                  int startIndex = 0;

                  int endIndex = ipLocationPojoArr.length - 1;

                  int m = (endIndex + startIndex) / 2;

                  while (startIndex <= endIndex) {

                          // 大于等于起始 小于等于结束 说明找到了

                          // 小于起始 在前半截

                          // 大于结束 在后半截

                          if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {

                                   startIndex = m + 1;

                          } else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {

                                   endIndex = m - 1;

                          } else {

                                   System.out.println(ipLocationPojoArr[m]);

                                   return;

                          }

                          m = (startIndex + endIndex) / 2;

                  }

                  System.out.println("没找着");

         }

9        IP地址对象的范围形式数据的二分法实现

9.1业务类功能实现

package com.tledu.zrz.manager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

import com.tledu.zrz.util.IPUtil;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

/**

 * 该类为项目中管理类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:45:19

 */

public class DataProcessManager {

         /**

          * 业务类对应的二分法

          *

          * @param ipLocationPojoArr

          *            数组

          * @param ip

          *            ip

          * @return 索引

          */

         public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,

                          String ip) {

                  // 转换为long类型

                  long ipLong = IPUtil.ipToLong(ip);

                  int startIndex = 0;

                  int endIndex = ipLocationPojoArr.length - 1;

                  int m = (endIndex + startIndex) / 2;

                  while (startIndex <= endIndex) {

                          // 大于等于起始 小于等于结束 说明找到了

                          // 小于起始 在前半截

                          // 大于结束 在后半截

                          if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {

                                   startIndex = m + 1;

                          } else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {

                                   endIndex = m - 1;

                          } else {

                                   return m;

                          }

                          m = (startIndex + endIndex) / 2;

                  }

                  return -1;

         }

         /**

          * 将对象集合转换为对象数组并排序

          *

          * @param pojoList

          * @return

          */

         public static IPAndLocationPojo[] convertListToArrayAndSort(

                          List<IPAndLocationPojo> pojoList) {

                  // 转换为数组

                  IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList

                                   .size()];

                  pojoList.toArray(ipLocationPojoArr);

                  // 排序

                  Arrays.sort(ipLocationPojoArr);

                  return ipLocationPojoArr;

         }

         /**

          * 把读取到的List<String> 转换为 List<IPAndLocationPojo>

          *

          * @param ipLibrartPath

          * @param encoding

          * @return

          * @throws IOException

          */

         public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,

                          String encoding) throws IOException {

                  List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                  List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                  // 遍历 获取每一行

                  for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                            columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                  }

                  return ipAndLocationPojos;

         }

}

9.2测试

package com;

import java.io.IOException;

import java.util.List;

import com.tledu.zrz.manager.DataProcessManager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.IPUtil;

public class TestBinaraySearch_02 {

         public static void main(String[] args) throws IOException {

                 // 地址库文件

                 String ipLibrartPath = "ip_location_relation.txt";

                 // 字符编码

                 String encoding = "utf-8";

                 // 获取数据

                 List<IPAndLocationPojo> ipAndLocationPojos = DataProcessManager

                                   .getPojoList(ipLibrartPath, encoding);

                 // 转换为数组

                 IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager

                                   .convertListToArrayAndSort(ipAndLocationPojos);

                 // 用户输入的IP

                 String ip = "125.152.1.22";

                 // String ip = "120.211.144.131";

                 int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);

                 System.out.println(ipLocationPojoArr[index]);

         }

}

10.工具类封装

到目前为止,已经把二分法搞定了,已经可以实现功能了,测试代码就相当于客户端

但是目前客户端知道的信息还是比较多,客户只关心 入参和出参是什么就可以

至于我们用什么编码,用什么存储,客户根本不关心

此时我们需要提供一个对外访问的方法,该方法入参就是IP 出参就是归属地

10.1编码

package com.tledu.zrz.manager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

import com.tledu.zrz.util.IPUtil;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

/**

 * 该类为项目中管理类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:45:19

 */

public class DataProcessManager {

         /**

          * 对外提供的接口,入参IP出参地址

          *

          * @param ip

          * @return

          */

         public static String getLocation(String ip) {

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  // 获取数据

                  List<IPAndLocationPojo> ipAndLocationPojos = null;

                  try {

                          ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,

                                            encoding);

                  } catch (IOException e) {

                          e.printStackTrace();

                  }

                  // 转换为数组

                  IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager

                                   .convertListToArrayAndSort(ipAndLocationPojos);

                  int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);

                  return ipLocationPojoArr[index].getLocation();

         }

         /**

          * 业务类对应的二分法

          *

          * @param ipLocationPojoArr

          *            数组

          * @param ip

          *            ip

          * @return 索引

          */

         private static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,

                          String ip) {

                  // 转换为long类型

                  long ipLong = IPUtil.ipToLong(ip);

                  int startIndex = 0;

                  int endIndex = ipLocationPojoArr.length - 1;

                  int m = (endIndex + startIndex) / 2;

                  while (startIndex <= endIndex) {

                          // 大于等于起始 小于等于结束 说明找到了

                          // 小于起始 在前半截

                          // 大于结束 在后半截

                          if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {

                                   startIndex = m + 1;

                          } else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {

                                   endIndex = m - 1;

                          } else {

                                   return m;

                          }

                          m = (startIndex + endIndex) / 2;

                  }

                  return -1;

         }

         /**

          * 将对象集合转换为对象数组并排序

          *

          * @param pojoList

          * @return

          */

         private static IPAndLocationPojo[] convertListToArrayAndSort(

                          List<IPAndLocationPojo> pojoList) {

                  // 转换为数组

                  IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList

                                   .size()];

                  pojoList.toArray(ipLocationPojoArr);

                  // 排序

                  Arrays.sort(ipLocationPojoArr);

                  return ipLocationPojoArr;

         }

         /**

          * 把读取到的List<String> 转换为 List<IPAndLocationPojo>

          *

          * @param ipLibrartPath

          * @param encoding

          * @return

          * @throws IOException

          */

         private static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,

                          String encoding) throws IOException {

                  List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                  List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                  // 遍历 获取每一行

                  for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                            columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                  }

                  return ipAndLocationPojos;

         }

}

10.2测试

package com;

import java.io.IOException;

import com.tledu.zrz.manager.DataProcessManager;

public class TestBinaraySearch_03 {

         public static void main(String[] args) throws IOException {

                  // String ip = "125.152.1.22";

                  String ip = "120.211.144.131";

                  String location = DataProcessManager.getLocation(ip);

                  System.out.println(location);

         }

}

10.3优化

功能实现了,像以下情况,同一个生命周期中,如果操作两次及两次以上

那么 会导致 ip_location_relation地址库被解析多次,并且结构化多次,并且排序多次

带来的性能变弱

因为在一个生命周期当前,只解析一次,结构化一次,排序一次即可,每次获取归属地的时候,只需要进行二分法操作即可

可以使用静态代码块解决

package com.tledu.zrz.manager;

import com.tledu.zrz.pojo.IPAndLocationPojo;

import com.tledu.zrz.util.FileOperatorUtil;

import com.tledu.zrz.util.IPUtil;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

/**

 * 该类为项目中管理类

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 上午11:45:19

 */

public class DataProcessManager {

         private static IPAndLocationPojo[] ipLocationPojoArr = null;

         static {

                  // 地址库文件

                  String ipLibrartPath = "ip_location_relation.txt";

                  // 字符编码

                  String encoding = "utf-8";

                  // 获取数据

                  List<IPAndLocationPojo> ipAndLocationPojos = null;

                  try {

                          ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,

                                            encoding);

                  } catch (IOException e) {

                          e.printStackTrace();

                  }

                  // 转换为数组

                  ipLocationPojoArr = DataProcessManager

                                   .convertListToArrayAndSort(ipAndLocationPojos);

         }

         /**

          * 对外提供的接口,入参IP出参地址

          *

          * @param ip

          * @return

          */

         public static String getLocation(String ip) {

                  int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);

                  return ipLocationPojoArr[index].getLocation();

         }

         /**

          * 业务类对应的二分法

          *

          * @param ipLocationPojoArr

          *            数组

          * @param ip

          *            ip

          * @return 索引

          */

         public static int binaraySearch(IPAndLocationPojo[] ipLocationPojoArr,

                          String ip) {

                  // 转换为long类型

                  long ipLong = IPUtil.ipToLong(ip);

                  int startIndex = 0;

                  int endIndex = ipLocationPojoArr.length - 1;

                  int m = (endIndex + startIndex) / 2;

                  while (startIndex <= endIndex) {

                          // 大于等于起始 小于等于结束 说明找到了

                          // 小于起始 在前半截

                          // 大于结束 在后半截

                          if (ipLong > ipLocationPojoArr[m].getEndIPLong()) {

                                   startIndex = m + 1;

                          } else if (ipLong < ipLocationPojoArr[m].getStartIPLong()) {

                                   endIndex = m - 1;

                          } else {

                                   return m;

                          }

                          m = (startIndex + endIndex) / 2;

                  }

                  return -1;

         }

         /**

          * 将对象集合转换为对象数组并排序

          *

          * @param pojoList

          * @return

          */

         public static IPAndLocationPojo[] convertListToArrayAndSort(

                          List<IPAndLocationPojo> pojoList) {

                  // 转换为数组

                  IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList

                                   .size()];

                  pojoList.toArray(ipLocationPojoArr);

                  // 排序

                  Arrays.sort(ipLocationPojoArr);

                  return ipLocationPojoArr;

         }

         /**

          * 把读取到的List<String> 转换为 List<IPAndLocationPojo>

          *

          * @param ipLibrartPath

          * @param encoding

          * @return

          * @throws IOException

          */

         public static List<IPAndLocationPojo> getPojoList(String ipLibrartPath,

                          String encoding) throws IOException {

                  List<String> lineList = FileOperatorUtil.getLineList(ipLibrartPath,

                                   encoding);

                  List<IPAndLocationPojo> ipAndLocationPojos = new ArrayList<IPAndLocationPojo>();

                  // 遍历 获取每一行

                  for (String string : lineList) {

                          if (string == null || string.trim().equals("")) {

                                   continue;

                          }

                          // 以\t分割,得到三个列

                          String[] columnArray = string.split("\t");

                          // 创建结构化对象

                          IPAndLocationPojo ipAndLocationPojo = new IPAndLocationPojo(

                                            columnArray[0], columnArray[1], columnArray[2]);

                          // 保存到集合中

                          ipAndLocationPojos.add(ipAndLocationPojo);

                  }

                  return ipAndLocationPojos;

         }

}

10.4测试

11.入口类

package com.tledu.zrz.controller;

import java.util.Scanner;

import com.tledu.zrz.manager.DataProcessManager;

/**

 * 程序入口

 *

 * @author 天亮教育-帅气多汁你泽哥

 * @Date 2021年11月11日 下午4:41:42

 */

public class SystemController {

         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(location + " : " + (endTime - startTime));

                  }

         }

}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值