All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.javaweb.utils.IPToLocationUtils Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
/*
 * Copyright yz 2016-01-14  Email:[email protected].
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.javaweb.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * IP地址转换成地理位置工具类,使用得IPIP.NET免费版IP数据库。使用前如果IP数据文件未初始化的
 * 情况下就必须要先调用一次load方法加载数据文件
 *
 * @author yz
 */
public class IPToLocationUtils {

	public static final Map COUNTRY_CODE_MAP = new HashMap();

	private static final String[] countries = new String[]{"RW=卢旺达", "SO=索马里", "YE=也门", "IQ=伊拉克", "SA=沙特阿拉伯", "IR=伊朗伊斯兰共和国", "CY=塞浦路斯", "TZ=坦桑尼亚", "SY=叙利亚", "AM=亚美尼亚", "KE=肯尼亚", "CD=扎伊尔", "DJ=吉布提", "UG=乌干达", "CF=中非共和国", "SC=塞舌尔群岛", "JO=约旦", "LB=黎巴嫩", "KW=科威特", "OM=阿曼", "QA=卡塔尔", "BH=巴林", "AE=阿拉伯联合酋长国", "IL=以色列", "TR=土耳其", "ET=埃塞俄比亚", "ER=厄立特里亚", "EG=埃及", "SD=苏丹", "GR=希腊", "BI=布隆迪", "EE=爱沙尼亚", "LV=拉脱维亚", "AZ=阿塞拜疆", "LT=立陶宛", "SJ=斯瓦尔巴特和扬马延", "GE=格鲁吉亚", "MD=摩尔多瓦共和国", "BY=白俄罗斯", "FI=芬兰", "AX=奥兰群岛", "UA=乌克兰", "MK=前南斯拉夫马其顿共和国", "HU=匈牙利", "BG=保加利亚", "AL=阿尔巴尼亚", "PL=波兰", "RO=罗马尼亚", "XK=科索沃", "ZW=津巴布韦", "ZM=赞比亚", "KM=科摩罗", "MW=马拉维", "LS=莱索托", "BW=博茨瓦纳", "MU=毛里求斯", "SZ=斯威士兰", "RE=留尼汪", "ZA=南非", "YT=马约特", "MZ=莫桑比克", "MG=马达加斯加", "AF=阿富汗", "PK=巴基斯坦", "BD=孟加拉", "TM=土库曼斯坦", "TJ=塔吉克斯坦", "LK=斯里兰卡", "BT=不丹", "IN=印度", "MV=马尔代夫", "IO=英属印度洋领地", "NP=尼泊尔", "MM=缅甸", "UZ=乌兹别克斯坦", "KZ=哈萨克斯坦", "KG=吉尔吉克斯坦", "TF=法属南部领土", "CC=科科斯群岛", "PW=帕劳", "VN=越南", "TH=泰国", "ID=印度尼西亚", "LA=老挝人民民主共和国", "TW=台湾", "PH=菲律宾", "MY=马来西亚", "CN=中国", "HK=香港", "BN=文莱", "MO=澳门", "KH=柬埔寨", "KR=韩国", "JP=日本", "KP=朝鲜民主共和国", "SG=新加坡", "CK=库克群岛", "TL=东帝汶", "RU=俄罗斯", "MN=蒙古", "AU=澳大利亚", "CX=圣诞岛", "MH=马绍尔群岛", "FM=密克罗尼西亚", "PG=巴布亚新几内亚", "SB=所罗门群岛", "TV=图瓦卢", "NR=瑙鲁", "VU=瓦努阿图", "NC=新喀里多尼亚", "NF=诺福克岛", "NZ=新西兰", "FJ=斐济", "LY=阿拉伯利比亚民众国", "CM=喀麦隆", "SN=塞内加尔", "CG=刚果", "PT=葡萄牙", "LR=利比里亚", "CI=象牙海岸", "GH=加纳", "GQ=赤道几内亚", "NG=尼日利亚", "BF=布基纳法索", "TG=多哥", "GW=几内亚比绍", "MR=毛里塔尼亚", "BJ=贝宁", "GA=加蓬", "SL=塞拉利昂", "ST=圣多美和普林西比", "GI=直布罗陀", "GM=冈比亚", "GN=几内亚", "TD=乍得", "NE=尼日尔", "ML=马里", "TN=突尼斯", "ES=西班牙", "MA=摩洛哥", "MT=马耳他", "DZ=阿尔及利亚", "FO=法罗群岛", "DK=丹麦", "IS=冰岛", "GB=英国", "CH=瑞士", "SE=瑞典", "NL=荷兰", "AT=奥地利", "BE=比利时", "DE=德国", "LU=卢森堡", "IE=爱尔兰", "MC=摩纳哥", "FR=法国", "AD=安道尔", "LI=列支敦士登", "JE=泽西岛", "IM=曼岛", "GG=格恩西岛", "SK=斯洛伐克共和国", "CZ=捷克共和国", "NO=挪威", "VA=圣座(梵蒂冈)", "SM=圣马力诺", "IT=意大利", "SI=斯洛文尼亚", "ME=黑山共和国", "HR=克罗地亚", "BA=波斯尼亚和黑山共和国", "AO=安哥拉", "NA=纳米比亚", "SH=圣赫勒拿", "BB=巴巴多斯", "CV=佛得角", "GY=圭亚那", "GF=法属圭亚那", "SR=苏里南", "PM=圣皮埃尔和密克隆", "GL=格陵兰", "PY=巴拉圭", "UY=乌拉圭", "BR=巴西", "FK=福克兰群岛", "GS=南乔治亚岛和南桑威齐群岛", "JM=牙买加", "DO=多米尼加共和国", "CU=古巴", "MQ=马提尼克群岛", "BS=巴哈马", "BM=百慕大", "AI=安圭拉", "TT=特立尼达和多巴哥", "KN=圣基茨和尼维斯", "DM=多米尼加", "AG=安提瓜和巴布达", "LC=圣卢西亚", "TC=特克斯和凯科斯群岛", "AW=阿鲁巴", "VG=英属维京群岛", "VC=圣文森特和格林纳丁斯", "MS=蒙塞拉特群岛", "MF=圣马丁", "BL=圣巴泰勒米", "GP=瓜德罗普岛", "GD=格林纳达", "KY=开曼群岛", "BZ=伯利兹", "SV=萨尔瓦多", "GT=危地马拉", "HN=洪都拉斯", "NI=尼加拉瓜", "CR=哥斯达黎加", "VE=委内瑞拉", "EC=厄瓜多尔", "CO=哥伦比亚", "PA=巴拿马", "HT=海地", "AR=阿根廷", "CL=智利", "BO=玻利维亚", "PE=秘鲁", "MX=墨西哥", "PF=法属波利尼西亚", "PN=皮特凯恩群岛", "KI=基里巴斯", "TK=托克劳", "TO=汤加", "WF=瓦利斯和富图纳", "WS=萨摩亚", "NU=纽埃", "MP=北马里亚纳群岛", "GU=关岛", "PR=波多黎各", "VI=美属维京群岛", "UM=美国边远小岛", "AS=美属萨摩亚", "CA=加拿大", "US=美国", "PS=巴勒斯坦领土", "RS=塞尔维亚", "AQ=南极洲", "SX=圣马丁岛", "CW=库拉索", "BQ=博奈尔岛、圣尤斯达蒂斯和萨巴", "SS=南苏丹"};

	public static boolean enableFileWatch = false;

	private static int offset;

	private static int[] index = new int[256];

	private static ByteBuffer dataBuffer;

	private static ByteBuffer indexBuffer;

	private static Long lastModifyTime = 0L;

	private static String ipFileName = "17monipdb.dat";

	private static File ipFile = new File(FileUtils.getCurrentDirectory(), ipFileName);

	private static ReentrantLock lock = new ReentrantLock();

	static {
		for (String country : countries) {
			String[] array = country.split("=");
			COUNTRY_CODE_MAP.put(array[1], array[0]);
		}

		load();
	}

	/**
	 * 需要加载一次文件路径
	 *
	 * @param filePath
	 */
	public static void load(String filePath) {
		ipFile = new File(filePath);
		load();

		if (enableFileWatch) {
			watch();
		}
	}

	public static String[] find(String ip) {
		int  ip_prefix_value = new Integer(ip.substring(0, ip.indexOf(".")));
		long ip2long_value   = ip2long(ip);
		int  start           = index[ip_prefix_value];
		int  max_comp_len    = offset - 1028;
		long index_offset    = -1;
		int  index_length    = -1;
		byte b               = 0;

		for (start = start * 8 + 1024; start < max_comp_len; start += 8) {
			if (int2long(indexBuffer.getInt(start)) >= ip2long_value) {
				index_offset = bytesToLong(b, indexBuffer.get(start + 6), indexBuffer.get(start + 5), indexBuffer.get(start + 4));
				index_length = 0xFF & indexBuffer.get(start + 7);
				break;
			}
		}

		byte[] areaBytes;
		lock.lock();

		try {
			dataBuffer.position(offset + (int) index_offset - 1024);
			areaBytes = new byte[index_length];
			dataBuffer.get(areaBytes, 0, index_length);
		} finally {
			lock.unlock();
		}

		return new String(areaBytes, Charset.forName("UTF-8")).split("\t", -1);
	}

	private static void watch() {
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				long time = ipFile.lastModified();

				if (time > lastModifyTime) {
					lastModifyTime = time;
					load();
				}
			}
		}, 1000L, 5000L, TimeUnit.MILLISECONDS);
	}

	private static void load() {
		lastModifyTime = ipFile.lastModified();
		FileInputStream fin = null;
		lock.lock();

		try {
			dataBuffer = ByteBuffer.allocate(Long.valueOf(ipFile.length()).intValue());
			fin = new FileInputStream(ipFile);
			int    readBytesLength;
			byte[] chunk = new byte[4096];

			while (fin.available() > 0) {
				readBytesLength = fin.read(chunk);
				dataBuffer.put(chunk, 0, readBytesLength);
			}

			dataBuffer.position(0);
			int    indexLength = dataBuffer.getInt();
			byte[] indexBytes  = new byte[indexLength];
			dataBuffer.get(indexBytes, 0, indexLength - 4);
			indexBuffer = ByteBuffer.wrap(indexBytes);
			indexBuffer.order(ByteOrder.LITTLE_ENDIAN);
			offset = indexLength;

			int loop = 0;

			while (loop++ < 256) {
				index[loop - 1] = indexBuffer.getInt();
			}

			indexBuffer.order(ByteOrder.BIG_ENDIAN);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				if (fin != null) {
					fin.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			lock.unlock();
		}
	}

	private static long bytesToLong(byte a, byte b, byte c, byte d) {
		return int2long((((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)));
	}

	private static int str2Ip(String ip) {
		String[] ss = ip.split("\\.");
		int      a, b, c, d;
		a = Integer.parseInt(ss[0]);
		b = Integer.parseInt(ss[1]);
		c = Integer.parseInt(ss[2]);
		d = Integer.parseInt(ss[3]);

		return (a << 24) | (b << 16) | (c << 8) | d;
	}

	private static long ip2long(String ip) {
		return int2long(str2Ip(ip));
	}

	private static long int2long(int i) {
		long l = i & 0x7fffffffL;

		if (i < 0) {
			l |= 0x080000000L;
		}

		return l;
	}

	public static void main(String[] args) {
		Long     st   = System.nanoTime();
		String[] strs = IPToLocationUtils.find("114.253.34.147");
		System.out.println(Arrays.toString(strs));
		System.out.println(COUNTRY_CODE_MAP.get(strs[0]));

		Long et = System.nanoTime();
		System.out.println((et - st) / 1000 / 1000);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy