前言
日常開發中,獲取ip是常用的功能,本文記錄如何在Java中獲取本機外網ip、地理位置,訪問用戶的外網ip、地理位置,以及指定外網ip的地理位置;
代碼編寫
1、獲取訪問用戶外網ip,我們從訪問者的HttpServletRequest中獲取(注:要外網訪問才能獲取到外網地址,如果你在局域網甚至本機上訪問,獲得的是內網或者本機的ip)
2、獲取本機外網ip、地理位置以及指定外網ip的地理位置,我們調用太平洋網絡IP地址查詢Web接口(http://whois.pconline.com.cn/),返回ip、地理位置
太平洋網絡IP地址查詢接口豐富,參數設置多樣齊全,總有一款適合我們的需求
我們使用的就是第二個返回json(http://whois.pconline.com.cn/ipJson.jsp?json=true),如果要查詢指定ip,就拼上&ip=
Vo類
根據接口返回的數據,封裝IpVo類,以方便接參轉換實體
//太平洋接口返回數據格式 /* { ip: "58.63.47.115", pro: "廣東省", proCode: "440000", city: "廣州市", cityCode: "440100", region: "天河區", regionCode: "440106", addr: "廣東省廣州市天河區 電信", regionNames: "", err: "" } */
IpVo.java
import lombok.Data; /** * ip */ @Data public class IpVo { private String ip;//IP地址 private String pro;//省 private String proCode;//省編碼 private String city;//城市 private String cityCode;//城市編碼 private String region;//區 private String regionCode;//區編碼 private String addr;//詳細地址 + 運營商 //主要用於接參,無實際意義 private String regionNames; private String err; }
工具類
封裝工具類
import cn.huanzi.qch.baseadmin.common.pojo.IpVo; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.text.SimpleDateFormat; /** * IP工具類 */ @Slf4j public class IpUtil { /** * 獲取訪問者的ip地址 * 注:要外網訪問才能獲取到外網地址,如果你在局域網甚至本機上訪問,獲得的是內網或者本機的ip */ public static String getIpAddr(HttpServletRequest request) { String ipAddress = null; try { //X-Forwarded-For:Squid 服務代理 String ipAddresses = request.getHeader("X-Forwarded-For"); if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //Proxy-Client-IP:apache 服務代理 ipAddresses = request.getHeader("Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //WL-Proxy-Client-IP:weblogic 服務代理 ipAddresses = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //HTTP_CLIENT_IP:有些代理服務器 ipAddresses = request.getHeader("HTTP_CLIENT_IP"); } if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { //X-Real-IP:nginx服務代理 ipAddresses = request.getHeader("X-Real-IP"); } //有些網絡通過多層代理,那么獲取到的ip就會有多個,一般都是通過逗號(,)分割開來,並且第一個ip為客戶端的真實IP if (ipAddresses != null && ipAddresses.length() != 0) { ipAddress = ipAddresses.split(",")[0]; } //還是不能獲取到,最后再通過request.getRemoteAddr();獲取 if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { ipAddress = request.getRemoteAddr(); } } catch (Exception e) { ipAddress = ""; } return ipAddress; } /** * 調用太平洋網絡IP地址查詢Web接口(http://whois.pconline.com.cn/),返回ip、地理位置 */ public static IpVo getIpVo(String ip){ //查本機 String url = "http://whois.pconline.com.cn/ipJson.jsp?json=true"; //查指定ip if(!StringUtils.isEmpty(ip)){ url = "http://whois.pconline.com.cn/ipJson.jsp?json=true&ip=" + ip; } StringBuilder inputLine = new StringBuilder(); String read; try { HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection.setRequestProperty("Charset", "GBK"); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "GBK")); while ((read = in.readLine()) != null) { inputLine.append(read); } in.close(); } catch (Exception e) { e.printStackTrace(); } //返回格式 /* { ip: "58.63.47.115", pro: "廣東省", proCode: "440000", city: "廣州市", cityCode: "440100", region: "天河區", regionCode: "440106", addr: "廣東省廣州市天河區 電信", regionNames: "", err: "" } */ IpVo ipVo = null; try { ObjectMapper mapper = new ObjectMapper(); //當屬性的值為空(null或者"")時,不進行序列化,可以減少數據傳輸 mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); //設置日期格式 mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); //轉換成IpVo ipVo = mapper.readValue(new String(inputLine.toString().getBytes("GBK"), "GBK"), IpVo.class); } catch (IOException e) { e.printStackTrace(); } return ipVo; } /** * 直接根據訪問者的Request,返回ip、地理位置 */ public static IpVo getIpVoByRequest(HttpServletRequest request){ return IpUtil.getIpVo(IpUtil.getIpAddr(request)); } /* 終極大法:java獲取不了,就用js來獲取 <!-- js獲取客戶ip --> <script src="http://whois.pconline.com.cn/ipJson.jsp"></script> */ /*//測試 public static void main(String[] args) { //獲取本機ip System.out.println(getIpVo(null)); //獲取指定ip System.out.println(getIpVo("115.48.58.106")); }*/ }
效果演示
放開注釋,運行main方法
//測試 public static void main(String[] args) { //獲取本機ip System.out.println(getIpVo(null)); //獲取指定ip System.out.println(getIpVo("115.48.58.106")); }
后記
ip獲取暫時記錄到這,后續再進行補充
代碼開源
注:數據庫文件在resources/static/sql目錄下面
代碼已經開源、托管到我的GitHub、碼雲: