现如今,大家在很多网站上留言等,都会显示归属地。例如本站的问答模块,只要回答问题,他也会显示ip归属地,如下图:
这里我们提供一个公共免费的获取ip归属地的网址:
https://whois.pconline.com.cn/ipJson.jsp
这个地址,我们通过传递给他一个ip,他就会返回当前的ip归属地信息。下面我们使用java的方式编写一个根据ip获取归属地的工具类,在真实的环境中,直接开箱即用。
此工具类一共分为两部分:
第一部分是一个公共的ip获取类,可以通过request来获取到用户真实的ip,代码如下:
import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; /** * IP地址 工具类 * */ public class IpUtils { /** * 获取客户端IP地址 */ public static String getIpAddr(HttpServletRequest request) { if (request == null) { return "unknown"; } String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Forwarded-For"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); } /** * 检查是否为内部IP地址 * * @param ip IP地址 */ public static boolean internalIp(String ip) { byte[] addr = textToNumericFormatV4(ip); return internalIp(addr) || "127.0.0.1".equals(ip); } /** * 检查是否为内部IP地址 * * @param addr byte地址 */ private static boolean internalIp(byte[] addr) { if (addr == null || addr.length < 2) { return true; } final byte b0 = addr[0]; final byte b1 = addr[1]; // 10.x.x.x/8 final byte SECTION_1 = 0x0A; // 172.16.x.x/12 final byte SECTION_2 = (byte) 0xAC; final byte SECTION_3 = (byte) 0x10; final byte SECTION_4 = (byte) 0x1F; // 192.168.x.x/16 final byte SECTION_5 = (byte) 0xC0; final byte SECTION_6 = (byte) 0xA8; switch (b0) { case SECTION_1: return true; case SECTION_2: if (b1 >= SECTION_3 && b1 <= SECTION_4) { return true; } case SECTION_5: if (b1 == SECTION_6) { return true; } default: return false; } } /** * 将IPv4地址转换成字节 * * @param text IPv4地址 * @return byte 字节 */ public static byte[] textToNumericFormatV4(String text) { if (text.length() == 0) { return null; } byte[] bytes = new byte[4]; String[] elements = text.split("\\.", -1); try { long l; int i; switch (elements.length) { case 1: l = Long.parseLong(elements[0]); if ((l < 0L) || (l > 4294967295L)) { return null; } bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 2: l = Integer.parseInt(elements[0]); if ((l < 0L) || (l > 255L)) { return null; } bytes[0] = (byte) (int) (l & 0xFF); l = Integer.parseInt(elements[1]); if ((l < 0L) || (l > 16777215L)) { return null; } bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 3: for (i = 0; i < 2; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } l = Integer.parseInt(elements[2]); if ((l < 0L) || (l > 65535L)) { return null; } bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 4: for (i = 0; i < 4; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } break; default: return null; } } catch (NumberFormatException e) { return null; } return bytes; } /** * 获取本地IP地址 * * @return 本地IP地址 */ public static String getHostIp() { try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException ignored) { } return "127.0.0.1"; } /** * 获取主机名 * * @return 本地主机名 */ public static String getHostName() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ignored) { } return "未知"; } /** * 从反向代理中,获得第一个非 unknown IP地址 */ public static String getMultistageReverseProxyIp(String ip) { // 反向代理检测 if (ip.indexOf(",") > 0) { final String[] ips = ip.trim().split(","); for (String sub : ips) { if (!"unknown".equalsIgnoreCase(sub)) { ip = sub; break; } } } return ip; } }
第二部分是公共的根据把ip传递给服务器,服务器返回对应的ip归属地,完整代码如下:
import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONUtil; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.Map; /** * 获取真实地址 * */ @Slf4j public class AddressUtils { // 实时查询 public static final String ADDRESS_URL = "https://whois.pconline.com.cn/ipJson.jsp"; public static final String UNKNOWN = "未知"; public static String getAddressByIP(String ip) { // 内网 if (IpUtils.internalIp(ip)) { return "内网IP"; } try { Map<String, Object> paramMap = new HashMap<>(); paramMap.put("ip", ip); paramMap.put("json", true); String response = HttpUtil.get(ADDRESS_URL, paramMap); if (StringUtils.isBlank(response)) { log.error("根据IP获取地址异常 {}", ip); return UNKNOWN; } Address address = JSONUtil.toBean(response, Address.class); return String.format("%s %s", address.getPro(), address.getCity()); } catch (Exception e) { log.error("根据IP获取地址异常 {}", ip); } return UNKNOWN; } @Data static class Address { /** * 省 */ private String pro; /** * 市 */ private String city; } }
最后我们测试一下,看看效果,测试代码如下:
public static void main(String[] args) { String addressByIP = AddressUtils.getAddressByIP("36.192.183.255"); System.out.println(addressByIP); }
运行后,可以看到这个ip显示的是福建省厦门市
至此根据ip查询ip归属地的公共免费接口代码就实现了。真实环境直接开箱即可就可以了。
备注:
1、运行此代码,需要在maven中引入如下3个依赖:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency>
还没有评论,来说两句吧...