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

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

There is a newer version: 2.0.3
Show newest version
package org.javaweb.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * IP 地址转地理位置工具类,使用的是IPIP.NET的城市库(收费版.ipdb格式)
 *
 * @author yz
 */
public class IPLocationUtils {

	private static final Logger LOG = LoggerFactory.getLogger(IPToLocationUtils.class);

	private static int nodeCount;

	private static byte[] data;

	private static JSONObject metaJson;

	private static JSONArray fieldArray;

	private static int v4offset;

	private static int fileSize;

	private static String ipFileName = "mydata4vipday2.ipdb";

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

	static {
		try {
			byte[]      bytes = null;
			InputStream in    = IPToLocationUtils.class.getClass().getResourceAsStream("/" + ipFileName);

			if (in != null) {
				bytes = IOUtils.toByteArray(in);
			}

			if (bytes == null && ipFile.exists()) {
				bytes = FileUtils.readFileToByteArray(ipFile);
			}

			fileSize = bytes.length;

			int    metaLength = bytesToLong(bytes[0], bytes[1], bytes[2], bytes[3]).intValue();
			String metaStr    = new String(Arrays.copyOfRange(bytes, 4, metaLength + 4));
			metaJson = JSON.parseObject(metaStr);

			nodeCount = metaJson.getInteger("node_count");
			fieldArray = metaJson.getJSONArray("fields");

			// 获取IP数据
			data = Arrays.copyOfRange(bytes, metaLength + 4, fileSize);

			if (metaJson.getInteger("ip_version") == 1) {
				int node = 0;

				for (int i = 0; i < 96 && node < nodeCount; i++) {
					if (i >= 80) {
						node = readNode(node, 1);
					} else {
						node = readNode(node, 0);
					}
				}

				v4offset = node;
			}
		} catch (Exception e) {
			LOG.info("IP地址解析异常:" + e, e);
		}
	}

	/**
	 * 查找IP地址对应的数据范围
	 *
	 * @param binary
	 * @return
	 */
	private static int findNode(byte[] binary) {
		int node = 0;

		final int bit = binary.length * 8;

		if (bit == 32) {
			node = v4offset;
		}

		for (int i = 0; i < bit; i++) {
			if (node > nodeCount) {
				break;
			}

			node = readNode(node, 1 & ((0xFF & binary[i / 8]) >> 7 - (i % 8)));
		}

		if (node > nodeCount) {
			return node;
		}

		throw new RuntimeException("IP Address Not Found!");
	}

	/**
	 * 查找IP地址对应的真实地理位置信息
	 *
	 * @param ip
	 * @return
	 */
	public static IPLocation find(String ip) {
		return find(ip, "CN");
	}

	/**
	 * 查找IP地址对应的真实地理位置信息
	 *
	 * @param ip
	 * @param language
	 * @return
	 */
	public static IPLocation find(String ip, String language) {
		try {
			if (StringUtils.isNotEmpty(ip) && StringUtils.isNotEmpty(language) && metaJson != null) {
				JSONObject langObject = metaJson.getJSONObject("languages");

				if (langObject != null && langObject.containsKey(language.toUpperCase())) {
					int    langOffset  = langObject.getInteger(language);
					byte[] ipArray     = textToNumericFormatV4(ip);
					int    node        = findNode(ipArray);
					String locationStr = resolve(node);

					if (locationStr != null) {
						int fieldLength = fieldArray.size();

						String[] locationArr = Arrays.copyOfRange(
								locationStr.split("\t", fieldLength * langObject.size()),
								langOffset, langOffset + fieldLength
						);

						return new IPLocation(
								locationArr[11], locationArr[0], locationArr[0],
								locationArr[1], locationArr[2], null,
								locationArr[4], locationArr[5], locationArr[6]
						);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	private static String resolve(int node) {
		final int index = node - nodeCount + nodeCount * 8;

		if (index < fileSize) {
			byte b    = 0;
			int  size = Long.valueOf(bytesToLong(b, b, data[index], data[index + 1])).intValue();

			if (data.length > index + 2 + size) {
				return new String(data, index + 2, size, Charset.forName("UTF-8"));
			}
		}

		return null;
	}

	private static int readNode(int node, int index) {
		int off = node * 8 + index * 4;
		return bytesToLong(data[off], data[off + 1], data[off + 2], data[off + 3]).intValue();
	}

	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 Long int2long(int i) {
		Long l = i & 0x7fffffffL;

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

		return l;
	}

	public static byte[] textToNumericFormatV4(String var0) {
		byte[]  var1 = new byte[4];
		long    var2 = 0L;
		int     var4 = 0;
		boolean var5 = true;
		int     var6 = var0.length();

		if (var6 != 0 && var6 <= 15) {
			for (int var7 = 0; var7 < var6; ++var7) {
				char var8 = var0.charAt(var7);

				if (var8 == '.') {
					if (var5 || var2 < 0L || var2 > 255L || var4 == 3) {
						return null;
					}

					var1[var4++] = (byte) ((int) (var2 & 255L));
					var2 = 0L;
					var5 = true;
				} else {
					int var9 = Character.digit(var8, 10);
					if (var9 < 0) {
						return null;
					}

					var2 *= 10L;
					var2 += (long) var9;
					var5 = false;
				}
			}

			if (!var5 && var2 >= 0L && var2 < 1L << (4 - var4) * 8) {
				switch (var4) {
					case 0:
						var1[0] = (byte) ((int) (var2 >> 24 & 255L));
					case 1:
						var1[1] = (byte) ((int) (var2 >> 16 & 255L));
					case 2:
						var1[2] = (byte) ((int) (var2 >> 8 & 255L));
					case 3:
						var1[3] = (byte) ((int) (var2 >> 0 & 255L));
					default:
						return var1;
				}
			} else {
				return null;
			}
		} else {
			return null;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy