免责声明:因使用该工具类导致的任何线上事故,本人概不负责。
直接代码
1、从请求中获取IP
2、解析IP所属地区
IP解析离线方案需要导入的依赖
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
IP解析离线方案需要导入的资源,放下 resource 路径下
链接: https://pan.baidu.com/s/1G1diUl8Ei3wg1A5EsPtUKw?pwd=4dqj 提取码: 4dqj 复制这段内容后打开百度网盘手机App,操作更方便哦
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.beust.jcommander.internal.Lists;
import jodd.util.StringPool;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhanghl
* @version IpAddressUtil.java, v 0.1 2022-05-16 10:29 上午
*/
@Slf4j
public class IpAddressUtil {
public static final String PCONLINE_WHOIS = "http://whois.pconline.com.cn/ipJson.jsp?";
public static final String PROVINCE = "PROVINCE_NAME";
public static final String CITY = "CITY_NAME";
public static final String UNKNOWN = "unknown";
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
* 参考文章: http://developer.51cto.com/art/201111/305181.htm
* <p>
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
* 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
* <p>
* 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
* <p>
* 用户真实IP为: 192.168.1.110
*
* @param request
* @return
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
String[] ipArr = StringUtils.split(ip, StringPool.COMMA);
if (ipArr != null && ipArr.length > 1) {
ip = StringUtils.trim(ipArr[0]);
}
return ip;
}
/**
* 获得省、市完整信息(优先离线获取)可以避免存在同名的市
*
* @param ip
* @return
*/
public static String getRegionName(String ip) {
String regionNameOffline = getRegionNameOffline(ip);
if (StringUtils.isNotBlank(regionNameOffline)) {
return regionNameOffline;
}
String regionNameOnline = getRegionNameOnline(ip);
if (StringUtils.isNotBlank(regionNameOnline)) {
return regionNameOnline;
}
return StringPool.EMPTY;
}
/**
* 获得省份名称信息(优先离线获取)
*
* @param ip
* @return
*/
public static String getProvinceName(String ip) {
String provinceNameOffline = getProvinceNameOffline(ip);
if (StringUtils.isNotBlank(provinceNameOffline)) {
return provinceNameOffline;
}
String provinceNameOnline = getProvinceNameOnline(ip);
if (StringUtils.isNotBlank(provinceNameOnline)) {
return provinceNameOnline;
}
return StringPool.EMPTY;
}
/**
* 获得城市名信息(优先离线获取)
*
* @param ip
* @return
*/
public static String getCityName(String ip) {
String cityNameOffline = getCityNameOffline(ip);
if (StringUtils.isNotBlank(cityNameOffline)) {
return cityNameOffline;
}
String cityNameOnline = getCityNameOnline(ip);
if (StringUtils.isNotBlank(cityNameOnline)) {
return cityNameOnline;
}
return StringPool.EMPTY;
}
/**
* 在线获取省、市完整名
*
* @param ip
* @return
*/
public static String getRegionNameOnline(String ip) {
Map<String, String> cityInfoOnline = getCityInfoOnline(ip);
if (CollectionUtil.isEmpty(cityInfoOnline)) {
return StringPool.EMPTY;
}
String provinceName = cityInfoOnline.getOrDefault(PROVINCE, StringPool.EMPTY);
String cityName = cityInfoOnline.getOrDefault(CITY, StringPool.EMPTY);
return provinceName + cityName;
}
/**
* 在线获取省份名
*
* @param ip
* @return
*/
public static String getProvinceNameOnline(String ip) {
Map<String, String> cityInfoOnline = getCityInfoOnline(ip);
if (CollectionUtil.isEmpty(cityInfoOnline)) {
return StringPool.EMPTY;
}
return cityInfoOnline.getOrDefault(PROVINCE, StringPool.EMPTY);
}
/**
* 在线获取城市名
*
* @param ip
* @return
*/
public static String getCityNameOnline(String ip) {
Map<String, String> cityInfoOnline = getCityInfoOnline(ip);
if (CollectionUtil.isEmpty(cityInfoOnline)) {
return StringPool.EMPTY;
}
return cityInfoOnline.getOrDefault(CITY, StringPool.EMPTY);
}
/**
* 离线获取省、市完整名
*
* @param ip
* @return
*/
public static String getRegionNameOffline(String ip) {
Map<String, String> cityInfoOffline = getCityInfoOffline(ip);
if (CollectionUtil.isEmpty(cityInfoOffline)) {
return StringPool.EMPTY;
}
String provinceName = cityInfoOffline.getOrDefault(PROVINCE, StringPool.EMPTY);
String cityName = cityInfoOffline.getOrDefault(CITY, StringPool.EMPTY);
return provinceName + cityName;
}
/**
* 离线获取省份名
*
* @param ip
* @return
*/
public static String getProvinceNameOffline(String ip) {
Map<String, String> cityInfoOffline = getCityInfoOffline(ip);
if (CollectionUtil.isEmpty(cityInfoOffline)) {
return StringPool.EMPTY;
}
return cityInfoOffline.getOrDefault(PROVINCE, StringPool.EMPTY);
}
/**
* 离线获取城市名
*
* @param ip
* @return
*/
public static String getCityNameOffline(String ip) {
Map<String, String> cityInfoOffline = getCityInfoOffline(ip);
if (CollectionUtil.isEmpty(cityInfoOffline)) {
return StringPool.EMPTY;
}
return cityInfoOffline.getOrDefault(CITY, StringPool.EMPTY);
}
/**
* 根据IP地址获取完整城市信息
* 示例数据:"中国|0|浙江省|杭州市|电信"
*
* @param ip
* @return
*/
public static Map<String, String> getCityInfoOffline(String ip) {
if (!Util.isIpAddress(ip)) {
return null;
}
try {
DbConfig config = new DbConfig();
File file = ResourceUtils.getFile("classpath:ip2region.db");
DbSearcher searcher = new DbSearcher(config, file.getPath());
// 查询算法:B-tree
Method method = searcher.getClass().getMethod("btreeSearch", String.class);
DataBlock dataBlock = (DataBlock) method.invoke(searcher, ip);
// region = "中国|0|浙江省|杭州市|电信"
String region = dataBlock.getRegion();
if (StringUtils.isBlank(region)) {
return null;
}
List<String> regionSplitList = Lists.newArrayList(StringUtils.split(region, StringPool.PIPE));
if (CollectionUtil.isEmpty(regionSplitList) && regionSplitList.size() < 5) {
return null;
}
String provinceName = regionSplitList.get(2);
String cityName = regionSplitList.get(3);
HashMap<String, String> regionMap = new HashMap<>(2);
regionMap.put(PROVINCE, provinceName);
regionMap.put(CITY, cityName);
return regionMap;
} catch (Exception ignored) {
return null;
}
}
/**
* 在线获取Ip所属城市信息
* 示例数据:{regionCode=0, regionNames=, proCode=330000, err=, city=杭州市, cityCode=330100, ip=122.224.152.210, pro=浙江省, region=, addr=浙江省杭州市 电信}
*
* @param ip
* @return
*/
public static Map<String, String> getCityInfoOnline(String ip) {
if (!Util.isIpAddress(ip)) {
return null;
}
HashMap<String, Object> parameters = Maps.newHashMap();
parameters.put("ip", ip);
parameters.put("json", "true");
String region = HttpUtil.createGet(PCONLINE_WHOIS).form(parameters).charset("UTF-8").execute().body();
// region = {regionCode=0, regionNames=, proCode=330000, err=, city=杭州市, cityCode=330100, ip=122.224.152.210, pro=浙江省, region=, addr=浙江省杭州市 电信}
if (StringUtils.isBlank(region)) {
return null;
}
JSONObject jsonObject = JSON.parseObject(region);
String cityName = jsonObject.get("city").toString();
String provinceName = jsonObject.get("pro").toString();
if (StringUtils.isBlank(cityName) && StringUtils.isBlank(provinceName)) {
return null;
}
HashMap<String, String> regionMap = new HashMap<>(2);
regionMap.put(PROVINCE, provinceName);
regionMap.put(CITY, cityName);
return regionMap;
}
}