一、项目介绍
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
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();
}
}
}
2.文本文件读取工具类
工具类封装 :
1 先写测试类,确认输入与输出技术问题
2 抽象出了输入与输出,形成方法的入参和出参
3 工具代码实现,测试
2.1 工具类
package 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;
}
}
2.2 测试工具类
import java.io.IOException;
import java.util.List;
import 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<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 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();
}
}
4.2 数据拆分,转换为对象
package com;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import pojo.IPAndLocationPojo;
import 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<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 manager;
import pojo.IPAndLocationPojo;
import util.FileOperatorUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 该类为项目中管理类
*
*/
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 测试
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import cmanager.DataProcessManager;
import pojo.IPAndLocationPojo;
import util.FileOperatorUtil;
/**
* 转换为结构化对象
*
*/
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.数据化集合转换为数组
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import manager.DataProcessManager;
import 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("