项目实战-day-34

2021.11.11 晴

一、介绍

背景和需求

根据IP得到位置

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

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

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

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

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

二、相关问题

强化项目思维

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

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

三、主要思路

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

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

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

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

入参是IP

出参是地址

四、研发项目分类

        应用开发类项目

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

        Web开发类 项目

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

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

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

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

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

可行性一定是可以做的

需求分析的梳理

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

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

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

        前置条件 :

IP地址库

JavaSE

面向对象

IO

常用类

二分法

正则表达式校验

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

读取IP地址库

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

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

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

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

DTO : 先不管

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

把对象加入List中

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

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

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

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

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

完成比较逻辑

对外提供访问接口

测试

细节开发与风险控制

BUG修复,调优,标准化

正式上线

项目总结,项目复盘·

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

	}
}
package com.manager;

import com.pojo.IPAndLocationPojo;
import com.util.FileOperatorUtil;
import com.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<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;
	}
}
package com.pojo;

import com.util.IPUtil;

/**
 * 结构化实体类
 * 
 */
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;
		}
	}

}
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
	 * 
	 * @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;
	}
}
package com.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);
	}

	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地址转换回点分十进制表示的字符串类型
	 * 
	 * @param ipLong
	 * @return java.lang.String
	 * @throws Exception
	 */
	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();
	}
}

进阶修改:(将数据存储进数据库,直接用sql语句从数据库中查找)

package practice03.controller;

import java.util.Scanner;

import practice03.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);
			System.out.println("运行时间: " + (endTime - startTime));
		}

	}
}
package practice03.manager;

import practice.util.DBUtil;
import practice03.pojo.IPAndLocationPojo;
import practice03.util.FileOperatorUtil;
import practice03.util.IPUtil;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
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<IPAndLocationPojo> ipAndLocationPojos = null;
		try {
			ipAndLocationPojos = DataProcessManager.getPojoList(ipLibrartPath,
					encoding);
		} catch (IOException e) {
			e.printStackTrace();
		}
		Connection conn = null;
		PreparedStatement stmt = null;
		String sql="insert into ip(startIp,endIp,location) values (?,?,?)";
		try {
			conn = DBUtil.getConnection();
			stmt=conn.prepareStatement(sql);
			for (IPAndLocationPojo ipAndLocationPojo : ipAndLocationPojos) {
				stmt.setLong(1, ipAndLocationPojo.getStartIPLong());
				stmt.setLong(2, ipAndLocationPojo.getEndIPLong());
				stmt.setString(3,  ipAndLocationPojo.getLocation());
				stmt.executeUpdate();
			}			
		} catch (Exception e) {
		e.printStackTrace();
		}finally{
			DBUtil.close(stmt);
			DBUtil.close(conn);
		}
	}

	/**
	 * 对外提供的接口,入参IP出参地址
	 * 
	 * @param ip
	 * @return
	 */
	public static String getLocation(String ip) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		String canshu=null;
		long  ip1=IPUtil.ipToLong(ip);
		String sql="select location from ip where startIp<"+ip1 +" and endIp >"+ip1+";";
		try {			
			conn = DBUtil.getConnection();
			stmt = conn.createStatement();
			rs=stmt.executeQuery(sql);
			while(rs.next()){
				canshu=rs.getString("location");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			DBUtil.close(rs);
			DBUtil.close(stmt);
			DBUtil.close(conn);
		}
		return  canshu ;
	}


	/**
	 * 把读取到的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;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值