1.项目介绍

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 地址的不同形式的使用

2.相关问题

强化项目四位

不管好方法还是差方法,先尝试把功能实现再考虑对代码进行优化,最优位置

3.主要思路

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

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

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

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

入参是IP 出参是地址

4.研发项目分类

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 项目总结,项目复盘

5.代码研发

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

}

}

}

  1.  文本文件读取工具类

工具类封装 :

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

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

3 工具代码实现,测试

  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;

}

}

  1.  测试工具类

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

}

}

}

  1.  数据结构化

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

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

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

Model,pojo,dto

  1.  抽象pojo类

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

}

}

  1.  数据拆分,转换为对象

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

}

}

}

  1.  封装DataProcessManager类

    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;

}

}

  1.  测试

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

}

}

}

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

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

}

}

}

  1.  对象数组排序

    1.  实现排序

1 自定义实现

冒泡,选择

2 API

Collections,Arrays

  1.  排序注意事项

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

实现Comparable接口

有比较器类Comparator

  1.  排序案例

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;

}

}

  1.  总结

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

  1.  业务问题

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

}

}

  1.  Pojo添加衍生字段

实体类中衍生两个字段,用来存储转换为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;

}

}

}

  1.  测试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]);

}

}

  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;

/**

* 该类为项目中管理类

*

* @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;

}

}

  1.  测试

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

}

}

  1.  二分法

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

  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("没找着");

}

  1.  引用/复杂类型

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("没找着");

}

  1.  业务类实现

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("没找着");

}

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

    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;

}

}

  1.  测试

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

}

}

  1.  工具类封装

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

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

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

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

  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;

}

}

  1.  测试

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

}

}

  1.  优化

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

那么 会导致 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;

}

}

  1.  测试

  1.  入口类

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

}

}

}

IP归属地在线查询平台 javaSE相关推荐

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

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

  2. 深圳市补贴政策在线查询平台,2021年最新深圳企业补贴项目

    在企业日常经营发展过程中,企业通过申请政府补贴项目可以获得一定程度上的资金支持,有利于缓解企业的资金压力与品牌塑造.而在这一过程中,我们需要找到一个合适的深圳市补贴政策在线查询平台,从而查询到2021 ...

  3. 2023基于微信小程序的公交信息在线查询平台(SSM+mysql)-JAVA.VUE(论文+开题报告+运行)

    摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟.本文介绍了微信小程序公交信息在线查询系统的开发全过程.通过分析微信小程序公交信息在线查询系统信息管理的不足,创建 ...

  4. IP归属地批量查询软件

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言: 前段时间有个需求是把几万个IP解析为国家,省份,城市,运营商等形式,本来想写个爬虫不断去向网站post,但想了想,这样慢不说, ...

  5. Excel也可以根据ip地址在线查询归属地详细信息

    今天要和大家分享的是:Excel也可以根据ip地址在线查询归属地详细信息,先看下面的动图演示 ​ 1.先装好该插件,然后打开表格 ​ 2.然后选择ip地址,将获得国家.大区.省.市.县.运营商等详细信 ...

  6. 案例—手机号码归属地专业在线查询

    使用Ajax异步请求向服务器发送GET请求,请求手机号码归属地查询,然后动态生成列表,显示手机号码段,卡号归属地,卡类型,区号,邮编等列表信息,最后写一个超链接把更多详情的邮区编号写进去. 本案例整体 ...

  7. 最新社工库在线查询网站

    社工查询网站 手机号注册网站查询 信用查询 国内企业信息 政府信息查询 身份信息查询 驾驶员及车辆信息查询 物品资产查询 物流查询 发票查询 金融查询 手机信息查询 个人信息查询 搜索引擎 手机号注册 ...

  8. Java IP归属地查询(离线方式+在线方式,内附查询IP方法)

    一.离线方式 1.1. 下载 ip2region.xdb GitHub项目地址:https://github.com/lionsoul2014/ip2region 我们首先需要下载一个 ip2regi ...

  9. IP归属地查询(基于本地IP库实现)

    这是一篇GitHub上的项目说明文档,项目地址: Zzz2333/IPLibrary 本项目功能是根据IP查询归属地.用到了纯真IP地址数据库,即qqwry.dat文件. 纯真IP地址数据库是一个网上 ...

最新文章

  1. 【小样本学习】什么是小样本学习?这篇综述文章用166篇参考文献告诉你答案...
  2. 如何检查字符串是否为空?
  3. 集训队脱单大法:这是一道只能由学姐我自己出数据的水题
  4. .net core mvc初级教程(六)
  5. 电脑怎么结束进程_小协漫谈 | 聊聊电脑卡顿那些事
  6. TensorFlow 教程 --新手入门--1.1简介
  7. 打印异常堆栈_通过异常堆栈丢失谈即时编译优化
  8. IOS7 position:fixed focus定位问题
  9. 开启html元素的编辑模式contenteditable=true
  10. Appium移动自动化测试-----(一)Appium介绍
  11. [傅里叶变换及其应用学习笔记] 七. 傅里叶正(反)变换复习
  12. C/C++中怎样获取日期和时间
  13. uniapp开发微信公众号(支付宝支付)
  14. 关于存储单元、寻址范围的问题
  15. 2015-华为招聘公开测试题目-单词迷宫
  16. 双硬盘笔记本电脑安装WIN10和Ubuntu双系统(二)
  17. Google镜像站点 资源收集
  18. Ubuntu 16.04 和18.04 命令行配置802.1x无线网络连接方法(针对北邮校园网BUPT-mobile)
  19. layui查档页面_首页--layui后台管理模板 2.0
  20. 几个opencv自带测试视频

热门文章

  1. 骑车与走路(YZOJ-1041)
  2. canvas绘图(下)
  3. 调侃:办公室“四大毒人”素描
  4. 《新概念英语3》大概相当于什么水平
  5. 8月9日逆水寒服务器维护时间,【图片】《逆水寒》2019年8月8日更新公告【逆水寒ol吧】_百度贴吧...
  6. audio标签控制音量_HTML5中audio标签的使用
  7. 景观设计主题命名_景观设计名字主题_园林景观好听的名字
  8. 香奈儿等奢侈品厂商要求欧盟修改网络销售法
  9. 一起了解Windows——把WPS设为.doc文件的默认打开应用
  10. python 人体建模_Google人体图像分割模型Bodypix再次更新,720p/30fps流畅运行