根据IP解析所属地区--离线与在线双方案

免责声明:因使用该工具类导致的任何线上事故,本人概不负责。

直接代码

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HelloMrGen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值