根据IP地址查出对应城市

package com.jd.train.service.util;

import com.jd.common.util.StringUtils;
import com.jd.train.manager.util.impl.HttpClientUtilManagerImpl;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

public class IPParser {
    private final Logger log = Logger.getLogger(IPParser.class);
    private String url; //ip查询请求地址
    private String dbPath; //本地IP数据库地址
    private String country, localStr;
    private long IPN;
    private int recordCount, countryFlag;
    private long rangE, rangB, offSet, startIP, endIP, firstStartIP,lastStartIP, endIPOff;
    private RandomAccessFile fis;
    private byte[] buff;

    private long B2L(byte[] b) {
        long ret = 0;
        for (int i = 0; i < b.length; i++) {
            long t = 1L;
            for (int j = 0; j < i; j++)
                t = t * 256L;
            ret += ((b[i] < 0) ? 256 + b[i] : b[i]) * t;
        }
        return ret;
    }

    private long ipToInt(String ip) {
        String[] arr = ip.split("\\.");
        long ret = 0;
        for (int i = 0; i < arr.length; i++) {
            long l = 1;
            for (int j = 0; j < i; j++)
                l *= 256;
            try {
                ret += Long.parseLong(arr[arr.length - i - 1]) * l;
            } catch (Exception e) {
                ret += 0;
            }
        }
        return ret;
    }

    private void seek(String ip) throws Exception {
        IPN = ipToInt(ip);
        fis = new RandomAccessFile(dbPath, "r");
        buff = new byte[4];
        fis.seek(0);
        fis.read(buff);
        firstStartIP = B2L(buff);
        fis.read(buff);
        lastStartIP = B2L(buff);
        recordCount = (int) ((lastStartIP - firstStartIP) / 7);
        if (recordCount <= 1) {
            localStr = country = "未知";
            throw new Exception();
        }

        rangB = 0;
        rangE = recordCount;
        long RecNo;

        do {
            RecNo = (rangB + rangE) / 2;
            getStartIP(RecNo);
            if (IPN == startIP) {
                rangB = RecNo;
                break;
            }
            if (IPN > startIP)
                rangB = RecNo;
            else
                rangE = RecNo;
        } while (rangB < rangE - 1);

        getStartIP(rangB);
        getEndIP();
        getCountry(IPN);

        fis.close();
    }

    private String getFlagStr(long OffSet) throws IOException {
        int flag = 0;
        do {
            fis.seek(OffSet);
            buff = new byte[1];
            fis.read(buff);
            flag = (buff[0] < 0) ? 256 + buff[0] : buff[0];
            if (flag == 1 || flag == 2) {
                buff = new byte[3];
                fis.read(buff);
                if (flag == 2) {
                    countryFlag = 2;
                    endIPOff = OffSet - 4;
                }
                OffSet = B2L(buff);
            } else
                break;
        } while (true);

        if (OffSet < 12) {
            return "";
        } else {
            fis.seek(OffSet);
            return getStr();
        }
    }

    private String getStr() throws IOException {
        long l = fis.length();
        ByteArrayOutputStream byteout = new ByteArrayOutputStream();
        byte c = fis.readByte();
        do {
            byteout.write(c);
            c = fis.readByte();
        } while (c != 0 && fis.getFilePointer() < l);
        return byteout.toString();
    }

    private void getCountry(long ip) throws IOException {
        if (countryFlag == 1 || countryFlag == 2) {
            country = getFlagStr(endIPOff + 4);
            if (countryFlag == 1) {
                localStr = getFlagStr(fis.getFilePointer());
                if (IPN >= ipToInt("255.255.255.0")
                        && IPN <= ipToInt("255.255.255.255")) {
                    localStr = getFlagStr(endIPOff + 21);
                    country = getFlagStr(endIPOff + 12);
                }
            } else {
                localStr = getFlagStr(endIPOff + 8);
            }
        } else {
            country = getFlagStr(endIPOff + 4);
            localStr = getFlagStr(fis.getFilePointer());
        }
    }

    private long getEndIP() throws IOException {
        fis.seek(endIPOff);
        buff = new byte[4];
        fis.read(buff);
        endIP = B2L(buff);
        buff = new byte[1];
        fis.read(buff);
        countryFlag = (buff[0] < 0) ? 256 + buff[0] : buff[0];
        return endIP;
    }

    private long getStartIP(long RecNo) throws IOException {
        offSet = firstStartIP + RecNo * 7;
        fis.seek(offSet);
        buff = new byte[4];
        fis.read(buff);
        startIP = B2L(buff);
        buff = new byte[3];
        fis.read(buff);
        endIPOff = B2L(buff);
        return startIP;
    }

    private String getUserIp(HttpServletRequest request) {
        String ip = CodesUtil.getIpAddr(request);
        if (ip != null && ip.indexOf(",") > 0) {
            log.info("取到客户多个ip1====================" + ip);
            String[] arr = ip.split(",");
            ip = arr[arr.length - 1].trim();//有多个ip时取最后一个ip
            log.info("取到客户多个ip2====================" + ip);
        }
        return ip;
    }

    private String findCity(HttpServletRequest request , String ipStr) {
        if(null == request && StringUtils.isEmpty(ipStr)){
            log.info("IPParser,findIpAddr(), request and ip is empty !");
            return null;
        }

        String ip = ipStr;
        if(request != null){
            ip = getUserIp(request);
        }
        if(StringUtils.isEmpty(ip)){
            log.info("IPParser,findIpAddr(), ip is empty !");
            return null;
        }

        String result;
        String location;
        try {
            seek(ip.trim());
        } catch (Exception e) {
            log.error("IPParser,findIpAddr() error ! " + e);
        }
        location = country;
        //查不到1
        if (StringUtils.isEmpty(location)) {
            log.info("IPParser,findIpAddr(), location is empty ! Trying remote interface ...");
            location = findIpAddrRemote(ip);
            if (StringUtils.isEmpty(location)) {
                log.info("IPParser,findIpAddr(), location is empty !");
                return null;
            }
        }
        //查不到2
        location = location.trim();
        if (location.length() == 0) {
            log.info("IPParser,findIpAddr(), location length is 0 ! Trying remote interface ...");
            location = findIpAddrRemote(ip);
            if (StringUtils.isEmpty(location)) {
                log.info("IPParser,findIpAddr(), location is empty !");
                return null;
            }
            if (location.length() == 0) {
                log.info("IPParser,findIpAddr(), location length is 0 !");
                return null;
            }
        }
        //查不到3
        if (location.contains("未知")) {
            log.info("IPParser,findIpAddr(), location is not found ! Trying remote interface ...");
            location = findIpAddrRemote(ip);
            if (StringUtils.isEmpty(location)) {
                log.info("IPParser,findIpAddr(), location is empty !");
                return null;
            }
            if (location.contains("未知")) {
                log.info("IPParser,findIpAddr(), location is not found !");
                return null;
            }
        }

        int cityIndex = location.indexOf("市");
        int cityIndex2 = location.indexOf("市", cityIndex + 1);
        int provinceIndex = location.indexOf("省");
        if (cityIndex > -1 && cityIndex2 == -1) {
            if (provinceIndex > -1) {
                location = location.substring(provinceIndex + 1, cityIndex);
            } else {
                location = location.substring(0, cityIndex);
            }
        }
        //处理有2个市的地址
        if (cityIndex > -1 && cityIndex2 > -1) {
            location = location.substring(cityIndex + 1, cityIndex2);
        }

        //自治区处理
        if (location.contains("宁夏")) {
            location = location.replaceAll("宁夏", "");
        }
        if (location.indexOf("内蒙古") > -1) {
            location = location.replaceAll("内蒙古", "");
            int districtIndex = location.indexOf("盟");
            if (districtIndex > -1) {
                location = location.substring(districtIndex + 1, location.length());
            }
        }
        if (location.indexOf("广西") > -1) {
            location = location.replaceAll("广西", "");
        }
        if (location.indexOf("西藏") > -1) {
            location = location.replaceAll("西藏", "");
        }
        if (location.indexOf("新疆") > -1) {
            location = location.replaceAll("新疆", "");
            int districtIndex = location.indexOf("州");
            if (districtIndex > -1) {
                location = location.substring(districtIndex + 1, location.length());
            }
        }

        //港澳台处理
        if (location.contains("省")) {
            location = location.replaceAll("省", "");
        }

        //其他
        if (location.startsWith("清华大学")) {
            location = "北京";
        }

        //去掉CZ88.NET字样,去掉空格
        location = location.replaceAll("CZ88.NET", "");
        result = location.replaceAll(" ", "");

        log.info(ip + " --> " + location);
        return result;
    }

    private String findIpAddrRemote(String ip) {
        String result;
        HttpClientUtilManagerImpl httpClientUtilManager = new HttpClientUtilManagerImpl();
        httpClientUtilManager.setTimeout(1000); //超时时间 1s
        String ipXML = httpClientUtilManager.executeHttpRequestString(url + ip, null);
        if (ipXML == null) {
            log.info("IPParser,findIpAddrRemote(),ipXML is null !");
            return null;
        }
        Document doc;
        try {
            doc = DocumentHelper.parseText(ipXML.trim());
        } catch (DocumentException e) {
            log.error("IPParser,findIpAddrRemote() error !" + e);
            return null;
        }
        if (doc == null) {
            log.info("IPParser,findIpAddrRemote(),doc is null !");
            return null;
        }
        Element rootElement = doc.getRootElement();
        Element productElement = rootElement.element("product");
        if (productElement == null) {
            log.info("IPParser,findIpAddrRemote(),productElement is null !");
            return null;
        }
        Element element = productElement.element("location");
        if (element == null) {
            log.info("IPParser,findIpAddrRemote(),element is null !");
            return null;
        }
        result = element.getTextTrim();
        return result;
    }

    /**
     * 根据ip获得城市名称
     * @param ip
     * @return
     */
    public String ipToCity(String ip){
        return findCity(null , ip);
    }

    /**
     * 根据请求获得城市名称
     * @param request
     * @return
     */
    public String ipToCity(HttpServletRequest request){
        return findCity(request, null);
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDbPath() {
        return dbPath;
    }

    public void setDbPath(String dbPath) {
        this.dbPath = dbPath;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getLocalStr() {
        return localStr;
    }

    public void setLocalStr(String localStr) {
        this.localStr = localStr;
    }

    public long getIPN() {
        return IPN;
    }

    public void setIPN(long IPN) {
        this.IPN = IPN;
    }

    public int getRecordCount() {
        return recordCount;
    }

    public void setRecordCount(int recordCount) {
        this.recordCount = recordCount;
    }

    public int getCountryFlag() {
        return countryFlag;
    }

    public void setCountryFlag(int countryFlag) {
        this.countryFlag = countryFlag;
    }

    public long getRangE() {
        return rangE;
    }

    public void setRangE(long rangE) {
        this.rangE = rangE;
    }

    public long getRangB() {
        return rangB;
    }

    public void setRangB(long rangB) {
        this.rangB = rangB;
    }

    public long getOffSet() {
        return offSet;
    }

    public void setOffSet(long offSet) {
        this.offSet = offSet;
    }

    public long getStartIP() {
        return startIP;
    }

    public void setStartIP(long startIP) {
        this.startIP = startIP;
    }

    public long getFirstStartIP() {
        return firstStartIP;
    }

    public void setFirstStartIP(long firstStartIP) {
        this.firstStartIP = firstStartIP;
    }

    public long getLastStartIP() {
        return lastStartIP;
    }

    public void setLastStartIP(long lastStartIP) {
        this.lastStartIP = lastStartIP;
    }

    public long getEndIPOff() {
        return endIPOff;
    }

    public void setEndIPOff(long endIPOff) {
        this.endIPOff = endIPOff;
    }

    public RandomAccessFile getFis() {
        return fis;
    }

    public void setFis(RandomAccessFile fis) {
        this.fis = fis;
    }

    public byte[] getBuff() {
        return buff;
    }

    public void setBuff(byte[] buff) {
        this.buff = buff;
    }

    public static void main(String[] args) throws Exception {
        long initUsedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        long start = System.currentTimeMillis();

        IPParser w = new IPParser();
        // w.setPath(new File("QQWry2.Dat").getAbsolutePath());
//		w.seek("125.10.100.17");
//        String ip = "211.161.190.171";
//        String ip = "14.192.60.1";
//        w.findRequestPhysAddr(ip);

        long end = System.currentTimeMillis();
        long endUsedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        System.out.println("time spent:" + (end - start) + " ms");
        System.out.println("memory consumes:" + (endUsedMemory - initUsedMemory));

    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值