Day_34_IP查询

1.使用序列化

        在程序第一次运行的时候,将保存ip分段的文件进行序列化存储,从而使得程序在多个生命周期中的查询时间大幅度降低,除去第一次进行序列化的时间较长外,其他生命周期中程序会进行判断,若存在指定的序列化文件,程序会直接反序列化该文件,从而使程序运行效率大幅提升。

1.1 程序的入口(客户端)

package com.controller;

import java.util.Scanner;
import com.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));
		}
	}
}

1.2 管理类

package com.manager;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.pojo.IPAndLocationPojo;
import com.util.FileOperatorUtil;
import com.util.IPUtil;
import com.util.RegexUtil;
import com.util.SerDeUtil;
import com.util.StaticValue;

//该类为项目中管理类

public class DataProcessManager {
	private static IPAndLocationPojo[] ipLocationPojoArr = null;
	static {
		// 判断序列化文件是否存在
		File file = new File(StaticValue.serde_obj_filepath);
		boolean isInit = file.exists();
		// 存在就反序列化获取
		if (isInit) {
			try {
				Object object = SerDeUtil.getObj(StaticValue.serde_obj_filepath, StaticValue.cacheByteArrayLength);
				ipLocationPojoArr = (IPAndLocationPojo[]) object;
			} catch (ClassNotFoundException | IOException e) {
				e.printStackTrace();
			}
		} else {
			// 不存在就序列化写出
			// 获取数据
			List<IPAndLocationPojo> ipAndLocationPojos = null;
			try {
				ipAndLocationPojos = DataProcessManager.getPojoList(StaticValue.ipLibrartPath, StaticValue.encoding);
			} catch (IOException e) {
				e.printStackTrace();
			}
			// 转换为数组
			ipLocationPojoArr = DataProcessManager.convertListToArrayAndSort(ipAndLocationPojos);
			try {
				SerDeUtil.saveObject(ipLocationPojoArr, StaticValue.serde_obj_filepath,
						StaticValue.cacheByteArrayLength);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	// 对外提供的接口,入参IP出参地址
	public static String getLocation(String ip) {
		if (RegexUtil.isValidIP(ip)) {
			int index = DataProcessManager.binaraySearch(ipLocationPojoArr, ip);
			return index == -1 ? "未找到" : ipLocationPojoArr[index].getLocation();
		} else {
			return "IP地址格式不正确,请重新输入";
		}

	}

	// 业务类对应的二分法
	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;
	}

	// 将对象集合转换为对象数组并排序
	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>
	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.3 结构化实体类

package com.pojo;

import java.io.Serializable;
import com.util.IPUtil;

//结构化实体类

public class IPAndLocationPojo implements Serializable, Comparable<IPAndLocationPojo> {

	private static final long serialVersionUID = 1L;

	@Override
	public String toString() {
		return "IPAndLocationPojo [startIP=" + startIP + ", endIP=" + endIP + ", location=" + location + "]";
	}

	// 起始IP
	private transient String startIP;

	// 衍生字段
	private long startIPLong;
	private long endIPLong;

	// 结束IP
	private transient String endIP;

	// 归属地
	private String location;

	public long getStartIPLong() {
		return startIPLong;
	}

	public void setStartIPLong(long startIPLong) {
		this.startIPLong = startIPLong;
	}

	public long getEndIPLong() {
		return endIPLong;
	}

	public void setEndIPLong(long endIPLong) {
		this.endIPLong = endIPLong;
	}

	public 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) {
		long result = startIPLong - o.startIPLong;
		if (result > 0) {
			return 1;
		} else if (result < 0) {
			return -1;
		} else {
			return 0;
		}
	}
}

1.4 工具类

1. 4.1

package com.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

	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.4.2

package com.util;

import java.util.Scanner;

//IP和long类型之间的转换

public class IPUtil {
public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String ip = scanner.nextLine();
}
	public 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地址转换回点分十进制表示的字符串类型

	public 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.4.3

package com.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexUtil {
	private static String regexIP = "((25[0-5]|2[0-4]\\d|[1]{1}\\d{1}\\d{1}|[1-9]{1}\\d{1}|\\d{1})($|(?!\\.$)\\.)){4}";

	// 校验IP
	public static boolean isValidIP(String ip) {
		return isValid(regexIP, ip);
	}

	// 格式验证
	public static boolean isValid(String regex, String input) {
		Pattern pattern = Pattern.compile(regex);

		// 创建匹配器
		Matcher matcher = pattern.matcher(input);
		return matcher.matches();
	}

	// 数据提取
	public static String getMatchContent(String regex, String input, int groupIndex) {
		Pattern pattern = Pattern.compile(regex);

		// 创建匹配器
		Matcher matcher = pattern.matcher(input);
		if (matcher.find()) {
			return matcher.group(groupIndex);
		}
		return null;
	}

	public static String getMatchContent(String regex, String input) {
		return getMatchContent(regex, input, 0);
	}
}

1.4.4

package com.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerDeUtil {

	// 对象写出,引入缓冲流
	public static void saveObject(Object obj, String objFilePath, int cacheByyeArrayLength) throws IOException {
		FileOutputStream fos = new FileOutputStream(objFilePath);
		// 字节数组缓冲流
		ByteArrayOutputStream baos = new ByteArrayOutputStream(cacheByyeArrayLength);
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(obj);
		byte[] bytes = baos.toByteArray();
		fos.write(bytes);
		oos.close();
		fos.close();
	}

	// 获取,引入缓冲流

	public static Object getObj(String objFilePath, int cacheByyeArrayLength)
			throws ClassNotFoundException, IOException {
		FileInputStream fis = new FileInputStream(objFilePath);
		byte[] bytes = new byte[cacheByyeArrayLength];
		fis.read(bytes);
		fis.close();
		ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(bais);
		Object o = ois.readObject();
		ois.close();
		return o;
	}

	// 写入
	public static void saveObject(Object obj, String objFilePath) throws IOException {
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(objFilePath));
		oos.writeObject(obj);
		oos.close();
	}

	// 读取
	public static Object getObj(String objFilePath) throws ClassNotFoundException, IOException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(objFilePath));
		Object o = ois.readObject();
		ois.close();
		return o;
	}
}

1.4.5

package com.util;

public class StaticValue {

	// 地址库文件
	public static String ipLibrartPath = "ip_location_relation.txt";
	// 字符编码
	public static String encoding = "utf-8";
	// 文件地址
//	public static String serde_obj_filepath = "ipLibObj.data";
	public static String serde_obj_filepath = "D:/1";
	// 根据文件大小,计算长度
	public static int cacheByteArrayLength = 25 * 1024 * 1024;

}

2. 使用数据库

        将保存ip分段的文件导入到MySQL数据库中,之后的查询直接使用SQL语句进行查询

2.1 添加

public class InsertIP {
	
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			conn = DBUtil.getConnection();
			String sql=("insert into ip (startIP,endIP,location) values(?,?,?)");
			stmt=conn.prepareStatement(sql);
			int i=0;
			for (IPAndLocationPojo ipAndLocationPojo : ipLocationPojoArr) {
				stmt.setLong(1, ipAndLocationPojo.getStartIPLong());
				stmt.setLong(2, ipAndLocationPojo.getEndIPLong());
				stmt.setString(3, ipAndLocationPojo.getLocation());
				stmt.executeUpdate();
			}
			
			System.out.println("执行成功");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil.close(stmt);
			DBUtil.close(conn);
		}

}

2.2 查询

package com.IPSearch;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
import com.util.DBUtil;
import com.util.IPUtil;

public class Search_IP {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		String ip = scanner.nextLine();
		long ip1 = IPUtil.ipToLong(ip);

		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			conn = DBUtil.getConnection();

			// 3 创建语句传输对象
			String sql = "select location from ip where ? >= startIP and ? <= endIP";
			stmt = conn.prepareStatement(sql);
			stmt.setLong(1, ip1);
			stmt.setLong(2, ip1);
			// 4 执行并获取结果
			rs = stmt.executeQuery();

			// 遍历获取数据
			while (rs.next()) {
				System.out.print(rs.getString("location") + " ");
				System.out.println();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil.close(rs);
			DBUtil.close(stmt);
			DBUtil.close(conn);
		}
	}
}

2.3 工具类DBUtil

package com.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {
	public static Connection getConnection() throws SQLException, ClassNotFoundException {
		// 1 加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		// 2 链接对象
		// 导的所有包都是 java.sql的
		// jdbc:mysql://IP:端口/数据库 用户名 密码
		return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/work_11_11", "root", "root");
	}

	// AutoCloseable 是 Connection,Statement,ResultSet的父类
	//利用多态性,来什么都可以接收
	public static void close(AutoCloseable obj) {
		if (obj != null) {
			try {
				obj.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值