根据IP得到位置,加标签
进行大数据分析,比如淘宝推荐等提供优质数据
www.ip.cn 等 查询IP
IP 分析 归属地信息 , 查找在毫秒内完成
IP地址库,公网都是开放的
IANA : 国际组织,负责公网IP维护分发
Eclipse ,JavaSE中面向对象、IO流、二分法算法、Base64编码、工具类封装
通过开发IP地址归属地查询平台,我们需要对JavaSE综合技术有所提升,增强实战能力。学习完该项目我们应该具备如下能力:
1 面向对象程序设计
2 工具类封装与使用写法
3 文件IO流
4 字符串处理
5 二分法查找
6 IP地址的不同形式的使用
强化项目思维
不管好方法还是差方法,先尝试把功能实现
再考虑对代码进行优化,最优为止
1 解析提供的地址库字符串,为结构化数据格式
2 基于结构化数据构建成某个数据结构,加速给定IP地址的查找速度
3 封装成响应的工具类API,开放其响应的方法,即给定IP地址可以再ms内计算得到其位置信息
4 工具类只有一个入参一个出参
入参是IP
出参是地址
解决某些特定功能而开发的应用软件,比如QQ,微信,Eclipse等
以B/S架构为主,也就是网页形式访问的在线系统,如各类官网等
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 项目总结,项目复盘
在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 关闭流
*
*/
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();
}
}
}
工具类封装 :
1 先写测试类,确认输入与输出技术问题
2 抽象出了输入与输出,形成方法的入参和出参
3 工具代码实现,测试
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;
/**
* 读取文件
*
*/
public class FileOperatorUtil {
/**
* 读取文件,并返回List
*
* @param txtFilePath
* 字符串格式的文件路径
* @param encoding
* 字符编码
* @return
* @throws IOException
*/
public static List
throws IOException {
List
// 字节流
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;
}
}
package com;
import java.io.IOException;
import java.util.List;
import com.tledu.zrz.util.FileOperatorUtil;
/**
* 测试工具类
*
*/
public class TestFileIO_02 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List
encoding);
for (String string : lineList) {
System.out.println(string);
}
}
}
1 可以找无结构化数据的组织规则,进行抽象,转换为结构化
2 根据数据组织进行数据抽象
3 解析数据,保存到对应的对象中
Model,pojo,dto
package com.tledu.zrz.pojo;
/**
* 结构化实体类
*/
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();
}
}
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;
/**
* 转换为结构化对象
*
*/
public class TestNonStructToStruct_01 {
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
List
encoding);
List
// 遍历 获取每一行
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);
}
}
}
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;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 把读取到的List
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List
String encoding) throws IOException {
List
encoding);
List
// 遍历 获取每一行
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;
}
}
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
for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {
System.err.println(ipAndLocationPojo);
}
}
}
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
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
.getPojoList(ipLibrartPath, encoding);
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[ipAndLocationPojos
.size()];
ipAndLocationPojos.toArray(ipLocationPojoArr);
for (IPAndLocationPojo ipAndLocationPojo : ipLocationPojoArr) {
System.out.println(ipAndLocationPojo);
}
}
}
1 自定义实现
冒泡,选择
2 API
Collections,Arrays
1 被排序的元素必须具有可比性
实现Comparable接口
有比较器类Comparator
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{
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;
}
}
要么实现排序的类 实现Comparable接口
由于IP是字符串,而字符串比较ASCII码
比如 1.1.6.32 , 1.1.128.23 理论上应该是后面的大
但是按照ASCII码比较的话,前面的大
所以我们需要把IP转换为long类型进行比较即可
package com.tledu.zrz.util;
/**
* IP和long类型之间的转换
*
*/
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();
}
}
实体类中衍生两个字段,用来存储转换为long类型之后的值
package com.tledu.zrz.pojo;
import com.tledu.zrz.util.IPUtil;
/**
* 结构化实体类
*
*/
public class IPAndLocationPojo implements Comparable
@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;
}
}
}
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
.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]);
}
}
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;
/**
* 该类为项目中管理类
*
*/
public class DataProcessManager {
/**
* 将对象集合转换为对象数组并排序
*
* @param pojoList
* @return
*/
public static IPAndLocationPojo[] convertListToArrayAndSort(
List
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List
String encoding) throws IOException {
List
encoding);
List
// 遍历 获取每一行
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;
}
}
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
.getPojoList(ipLibrartPath, encoding);
// 转换为数组
IPAndLocationPojo[] ipLocationPojoArr = DataProcessManager.convertListToArrayAndSort(ipAndLocationPojos);
// 测试首位元素
System.out.println(ipLocationPojoArr[0]);
System.out.println(ipLocationPojoArr[ipLocationPojoArr.length-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("没找着");
}
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("没找着");
}
public static void main(String[] args) throws IOException {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List
.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("没找着");
}
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;
/**
* 该类为项目中管理类
*
*/
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[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List
String encoding) throws IOException {
List
encoding);
List
// 遍历 获取每一行
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;
}
}
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
.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]);
}
}
到目前为止,已经把二分法搞定了,已经可以实现功能了,测试代码就相当于客户端
但是目前客户端知道的信息还是比较多,客户只关心 入参和出参是什么就可以
至于我们用什么编码,用什么存储,客户根本不关心
此时我们需要提供一个对外访问的方法,该方法入参就是IP 出参就是归属地
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;
/**
* 该类为项目中管理类
*/
public class DataProcessManager {
/**
* 对外提供的接口,入参IP出参地址
*
* @param ip
* @return
*/
public static String getLocation(String ip) {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List
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[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
private static List
String encoding) throws IOException {
List
encoding);
List
// 遍历 获取每一行
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;
}
}
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);
}
}
功能实现了,像以下情况,同一个生命周期中,如果操作两次及两次以上
那么 会导致 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;
/**
* 该类为项目中管理类
*/
public class DataProcessManager {
private static IPAndLocationPojo[] ipLocationPojoArr = null;
static {
// 地址库文件
String ipLibrartPath = "ip_location_relation.txt";
// 字符编码
String encoding = "utf-8";
// 获取数据
List
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[] ipLocationPojoArr = new IPAndLocationPojo[pojoList
.size()];
pojoList.toArray(ipLocationPojoArr);
// 排序
Arrays.sort(ipLocationPojoArr);
return ipLocationPojoArr;
}
/**
* 把读取到的List
*
* @param ipLibrartPath
* @param encoding
* @return
* @throws IOException
*/
public static List
String encoding) throws IOException {
List
encoding);
List
// 遍历 获取每一行
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;
}
}
package com.tledu.zrz.controller;
import java.util.Scanner;
import com.tledu.zrz.manager.DataProcessManager;
/**
* 程序入口
*
*/
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));
}
}
}