小工具      在线工具  汉语词典  css  js  c++  java

java的TreeMap在IP传输领域的使用

java,spring,TreeMap,java,数据,ip区域,批量ip 额外说明

收录于:40天前

前段时间,有一个统计的需求。我想将用户的登录IP转换为城市,然后用于统计。网上查百万数据还是有点慢,所以就寻找一些批量或者本地处理的方法。

有两种选择:

一、
这边的一个同事提供了一个文件(不清楚哪里搞来的),里面有ipbegin-ipEnd 地市,省 这些字段,用了10来个ip 测试,还是靠谱,格式如下

1551@@1.189.24.0@@1.189.24.255@@黑龙江省哈尔滨市通河县@@联通@@黑龙江省@@哈尔滨市@@HL
1561@@1.189.247.0@@1.189.248.255@@黑龙江省哈尔滨市延寿县@@联通@@黑龙江省@@哈尔滨市@@HL
1571@@1.189.249.0@@1.189.250.255@@黑龙江省哈尔滨市双城区@@联通@@黑龙江省@@哈尔滨市@@HL
1581@@1.189.25.0@@1.189.30.255@@黑龙江省哈尔滨市@@联通@@黑龙江省@@哈尔滨市@@HL
1591@@1.189.251.0@@1.189.254.255@@黑龙江省哈尔滨市@@联通@@黑龙江省@@哈尔滨市@@HL

二、
http://www.ipip.net这个地址,有ip库下载,也提供了各语言的api例子.

想了想,我决定第一个方案,因为数据已经有了,我觉得更有安全感,所以选择了自己分析。

具体加工

整个文件有40万行数据,循环查找太慢。考虑到IP地址大小不同,我们决定使用树。

设计理念

一份数据,一个节点,利用大小比较构建平衡树。搜索时,如果某个IP小于ip_begin,则向一个方向走,如果大于ip_end,则向另一个方向走。如果它在begin和end之间,那么这个节点就是目标。节点。

编程

java里面有treeMap,把节点扔进去,其自己会构建成一棵树,当然,此节点要实现 compareTo
的方法,把节点和ip的大小比较出来.
除了ip_begin,和ip_end , 此entity 上也加上 targetip用于通过ip取节点时的比较

具体代码

一个节点包括ip_begin和ip_end。当ip进来时,按照区间的左、中、右返回-1、0、1。具体方法是TipRange类写入这个节点并重写compareTo方法。使用时,ip区域列表形成一个treeMap。获取区域时,ip 获取 TipRange。具体请看下面两个核心类。

  • TipRange
    compareTo方法是关键
public class TipRange implements Comparable<TipRange> {
    
    private Integer id;
    // ipBegin
    private String ipBegin;
    // ipEnd
    private String ipEnd;
    private String regiondesc;
    private String typedesc;
    private String province;
    private String city;
    private String provinceCode;
    private Date updatetime;
    private String targetip;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getIpBegin() {
        return ipBegin;
    }

    public void setIpBegin(String ipBegin) {
        this.ipBegin = ipBegin;
    }

    public String getIpEnd() {
        return ipEnd;
    }

    public void setIpEnd(String ipEnd) {
        this.ipEnd = ipEnd;
    }

    public String getRegiondesc() {
        return regiondesc;
    }

    public void setRegiondesc(String regiondesc) {
        this.regiondesc = regiondesc;
    }

    public String getTypedesc() {
        return typedesc;
    }

    public void setTypedesc(String typedesc) {
        this.typedesc = typedesc;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getProvinceCode() {
        return provinceCode;
    }

    public void setProvinceCode(String provinceCode) {
        this.provinceCode = provinceCode;
    }

    public Date getUpdatetime() {
        return updatetime;
    }

    public void setUpdatetime(Date updatetime) {
        this.updatetime = updatetime;
    }

    public String getTargetip() {
        return targetip;
    }

    public void setTargetip(String targetip) {
        this.targetip = targetip;
    }

    @Override
    public int compareTo(TipRange targetRange) {
        String paramIp = targetRange.getTargetip();

        if(StringUtils.isEmpty(paramIp)&&StringUtils.isEmpty(this.getTargetip())){
            //两个都没ip为空,说明range和range对比
            long currtntipbeginLong = IpRangeUtil.ipStrToLong(ipBegin);
            long currentipendLong = IpRangeUtil.ipStrToLong(ipEnd);
            long rangeBegin = IpRangeUtil.ipStrToLong(targetRange.getIpBegin());
            if(rangeBegin<currtntipbeginLong){
                return 1;
            }else if (rangeBegin==currtntipbeginLong){
                return 0;
            }else{
                return -1;
            }
        }


        if(StringUtils.isNotEmpty(paramIp)&&StringUtils.isEmpty(this.getTargetip())){
            两个都没ip为空,说明range和range对比
            long targetIpLong = IpRangeUtil.ipStrToLong(paramIp);

            long currtntipbeginLong = IpRangeUtil.ipStrToLong(ipBegin);
            long currentipendLong = IpRangeUtil.ipStrToLong(ipEnd);
            //判断目标要往哪走
            if(targetIpLong<currtntipbeginLong){
                return 1;
            }else if (targetIpLong>currentipendLong){
                return -1;
            }else{
                return 0;
            }
        }

        if(StringUtils.isEmpty(paramIp)&&StringUtils.isNotEmpty(this.getTargetip())){
            //两个都没ip为空,说明range和range对比
            long currentIpLong = IpRangeUtil.ipStrToLong(this.getTargetip());

            long targetBeginLong = IpRangeUtil.ipStrToLong(targetRange.getIpBegin());
            long targetEndLong = IpRangeUtil.ipStrToLong(targetRange.getIpEnd());

            //判断目标要往哪走
            if(currentIpLong<targetBeginLong){
                return -1;
            }else if (currentIpLong>targetEndLong){
                return 1;
            }else{
                return 0;
            }
        }
        return -2;
    }

}
  • TgipRangeServiceImpl
    取数据,扔到treemap,其 ipToAddress 方法即为 暴露的api
import com.yp.springboot.util.FileReadUtils;
import com.yp.springboot.util.IFileOperByLine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


@Service
public class TgipRangeServiceImpl {
    
private static Map<TipRange, TipRange> cacheIpRangeMap;

@Autowired
 public JdbcTemplate jdbcTemplate;

private static Logger logger = LoggerFactory.getLogger("rlog");

public List<TipRange> queryAllByFile() throws Exception{
File file = new File("E:\\codeplace\\n_learn\\java\\springboot\\myexample\\springbootweb\\src\\main\\resources\\regionip.txt");//
 final List<TipRange> iprangeList1 = new ArrayList();

FileReadUtils.readFileAndUnionObj(file, new IFileOperByLine() {
@Override
 public void toOperLineNoList(String fileName, String linestr) {
String[] arrayText = linestr.split("@@");

Integer id = Integer.valueOf(arrayText[0]);
String ipBegin = arrayText[1];
String ipEnd = arrayText[2];
String regiondesc = arrayText[3];
String typedesc = arrayText[4];
String province = arrayText[5];
String city = arrayText[6];
String provinceCode = arrayText[7];

TipRange tmp = new TipRange();
tmp.setId(id);
tmp.setIpBegin(ipBegin);
tmp.setIpEnd(ipEnd);
tmp.setRegiondesc(regiondesc);
tmp.setTypedesc(typedesc);
tmp.setProvince(province);
tmp.setCity(city);
tmp.setProvinceCode(provinceCode);
//处理
 iprangeList1.add(tmp);
}
});
return iprangeList1;
}



/** * * @return */
 @Transactional(propagation = Propagation.NOT_SUPPORTED)
protected Map<TipRange, TipRange> genIpRangeToLogAllMap() throws Exception {
Map<TipRange, TipRange> allMap = new TreeMap<TipRange, TipRange>();
List<TipRange> allList = queryAllByFile();

for (TipRange entityRange : allList) {
allMap.put(entityRange, entityRange);
}
return allMap;
}

private String toTrim(String sstr){
if(sstr==null)return "";
return sstr.trim();
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
private synchronized void initMap() throws Exception {
cacheIpRangeMap = genIpRangeToLogAllMap();

}

/* */
 @Transactional(propagation = Propagation.NOT_SUPPORTED)
public TipRange ipToAddress(String ip) throws Exception {
synchronized (this) {
if (cacheIpRangeMap == null) {
initMap();
}
}
TipRange tmp = new TipRange();
tmp.setTargetip(ip);
return cacheIpRangeMap.get(tmp);
}
}

阐明:

代码 :https://github.com/huawumingguo/springbootsample/tree/master/springbootweb

. . .

相关推荐

额外说明

在做ibatis项目过程中遇到动态查询缓存的解决方案

动态查询可以对不同表进行查询,返回结果映射到HashMap中,但是使用中发现当第一次使用这个语句时是可以的,但是当使用这个语句再查询别的表时报错了,错误原因是从结果集到HashMap的映射时还按照上个表的字段进行装载,说明ibatis对上个表的结构进行了

额外说明

SQL CREATE DATABASE 语句和 SQL CREATE TABLE语句

SQL CREATE DATABASE 语句 CREATE DATABASE 语句用于创建数据库 SQL CREATE DATABASE 语法 CREATE DATABASE dbname SQL CREATE DATABASE实例 下面的SQL语句创

额外说明

VUE03_基于组件的思维,全局|本地注册,组件之间的值传递(从父亲到儿子,儿子到父亲,兄弟到兄弟),匿名 |命名|范围槽

文章目录 ①. 组件化思想 ②. 全局注册 ③. 局部注册 ④. 父组件向子组件传值 ⑤. 子组件向父组件传值 ⑥. 兄弟之间的传递 ⑦. 匿名插槽 ⑧. 具名插槽 ⑨. 作用域插槽 ①. 组件化思想 ①. 所谓组件化,就是把页面拆分成多个组件,每个组件

额外说明

[MySQL]常用基本SQL语句汇总

文章目录 1.前言 2.SQL的通用语法 2.1 注释 2.2 补充内容 3.数据库操作语言(DDL) 3.1 创建数据库 3.2 查看所有数据库 3.3 选中指定数据库 3.4 删除数据库 3.5 数据类型 3.6 创建数据库表 3.7 显示选中数据库

额外说明

比大龄单身更可怕的是大龄测试,失业or转行?

人说“三十而立”,可对于测试来说是“三十而秃”,除了日常秃头,而立之年的测试们的开始焦虑自己的职业未来。 自2017年华为传出“清理35岁以上员工”以来,各企业关于“劝退 35 岁以上员工”、“招聘限 35 岁以下”的传闻此起彼伏,在无数传言和事实下,人

额外说明

中文多模态医学大模型智能分析X光片,实现影像诊断,完成医生问诊多轮对话

项目设计集合(人工智能方向):助力新人快速实战掌握技能、自主完成项目设计升级,提升自身的硬实力(不仅限NLP、知识图谱、计算机视觉等领域):汇总有意义的项目设计集合,助力新人快速实战掌握技能,助力用户更好利用 CSDN 平台,自主完成项目设计升级,提升自

额外说明

【代码题】五道链表面试题

目录 1.移除链表元素 2.反转链表  3.链表的中间结点  4.链表中倒数第k个结点  5.合并两个有序链表 1.移除链表元素 点击进入该题https://leetcode.cn/problems/remove-linked-list-elements

额外说明

Direct3D 12——灯光——光照模型的概述

将之前所述的所有光照内容都结合起来,即表面反射的光量相当于环境反射光、漫反射光以及 镜面反射光的光量总和。 1.环境光Ca:模拟经表面反射的间接光量。 2.漫反射光Cd:对进入介质内部,又经过表面下吸收而最终散射岀表面的光进行模拟。由于对表 面下的散射光

额外说明

仅需5道题轻松掌握Python命令行相关标准库 | Python技能树征题

仅需5道题轻松掌握Python命令行相关标准库 | Python技能树征题 0. 前言 1. 第 1 题:命令行日志记录 2. 第 2 题:将日志存储在磁盘上 3. 第 3 题:命令行参数解析 4. 第 4 题:运行系统命令 5. 第 5 题:命令行中进

额外说明

计算机丢失d3dcompiler_35.dll如何解决?

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或者损坏了,这时你只需下载这个d3dcompiler_35.dll文件进行安装(前提是找到适

ads via 小工具