java的TreeMap在ip转区域的使用

2 篇文章 0 订阅
1 篇文章 0 订阅

前段时间 有个统计的需求,有用户的登陆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例子.

后来考虑了下,第一个方案,数据都是现成的,比较有安全感,就选择自己去解析。

具体处理

整个文件有40W行数据,用循环查找是太慢了,考虑到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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值