今天来认识一个IP地址解析库(ip2region)


一、问题提出

不知道各位有没有遇到过这样一个业务场景,当你的账号在其他城市登陆时会收到异地登陆的短信提示,最近个人就在做类似这样的业务,这点就有点像QQ与微信的异地登陆提示。话不多说了,开始之前我们认识一下一个地址解析库(ip2region),此库能够将IP地址解析成一个准确的地址信息,我们要做的就是进行分割得到我们想要的区域地址就可以了。

二、使用步骤

1.引入库,码云地址:gitee: https://gitee.com/lionsoul/ip2region

依赖如下(示例):

<dependency>
      <groupId>org.lionsoul</groupId>
      <artifactId>ip2region</artifactId>
      <version>1.7.2</version>
      <scope>compile</scope>
</dependency>

2.构建返回实体类对象

将ip2region.db文件放入resources文件夹中,接着就可以写测试代码了,个人写了一个解析准确地址的工具类,这里可以演示一下具体的使用过程。

代码如下(示例):

package cn.com.hjh.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;

/**
 * @author hjh
 */
public class GeoAddressVO {

    private String province;
    /**
     * 城市 二级行政区 例如:深圳、成都、凉山州
     */
    private String city;
    /**
     * 区/县 三级行政
     */
    private String county;
    /**
     * 街道
     */
    private String street;
    /**
     * 镇
     */
    private String town;
    /**
     * 村
     */
    private String village;
    /**
     * 其他
     */
    private String other;

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        if (StringUtils.isNotBlank(province)) {
            province = province.trim();
        }
        this.province = province;
    }

    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        if (StringUtils.isNotBlank(city)) {
            city = city.trim();
        }
        this.city = city;
    }
    public String getCounty() {
        return county;
    }
    public void setCounty(String county) {
        if (StringUtils.isNotBlank(county)) {
            county = county.trim();
        }
        this.county = county;
    }
    public String getStreet() {
        return street;
    }
    public void setStreet(String street) {
        if (StringUtils.isNotBlank(street)) {
            street = street.trim();
        }
        this.street = street;
    }
    public String getTown() {
        return town;
    }
    public void setTown(String town) {
        if (StringUtils.isNotBlank(town)) {
            town = town.trim();
        }
        this.town = town;
    }
    public String getVillage() {
        return village;
    }

    public void setVillage(String village) {
        if (StringUtils.isNotBlank(village)) {
            village = village.trim();
        }
        this.village = village;
    }
    public String getOther() {
        return other;
    }
    public void setOther(String other) {
        if (StringUtils.isNotBlank(other)) {
            other = other.trim();
        }
        this.other = other;
    }

    @Override
    public String toString() {
        try {
            ObjectMapper objectMapper =  new JsonMapper();
            //空值处理为空字符串 ""
            objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
                @Override
                public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    jsonGenerator.writeString("");
                }
            });
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return objectMapper.writeValueAsString(this);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return JSONObject.toJSONString(this, SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty);
    }

    /**
     *
     * @return com.alibaba.fastjson.JSONObject
     */
    public JSONObject toJson() {
        return JSONObject.parseObject(this.toString());
    }
}

3.获取IP以及详细地址的工具类

代码如下(示例):

package cn.com.hjh.util;

import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;

/**
 * @author hjh
 */
public final class IpUtils {

  public  static final String REGION = "内网IP|内网IP";
  private static final String UNKNOWN = "unknown";

    /**
     * 获取ip地址
     */
    public static String getIp(HttpServletRequest request) {
        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("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        String comma = ",";
        String localhost = "127.0.0.1";
        if (ip.contains(comma)) {
            ip = ip.split(",")[0];
        }
        if  (localhost.equals(ip))  {
            // 获取本机真正的ip地址
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
        return ip;
    }

    /**
     * 根据ip获取详细地址
     */
    public static String getGeoInfo(String ip) {
        DbSearcher searcher = null;
        try {
            String name = "ip2region.db";
            DbConfig config = new DbConfig();
            ClassLoader classLoader = IpUtils.class.getClassLoader();
            URL resource = classLoader.getResource(name);
            searcher = new DbSearcher(config, resource.getFile());
            Method method;
            method = searcher.getClass().getMethod("btreeSearch", String.class);
            DataBlock dataBlock;
            dataBlock = (DataBlock) method.invoke(searcher, ip);
            String address = dataBlock.getRegion().replace("0|","");
            char symbol = '|';
            if(address.charAt(address.length()-1) == symbol){
                address = address.substring(0,address.length() - 1);
            }
            return address.equals(REGION)?"内网IP":address;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(searcher!=null){
                try {
                    searcher.close();
                } catch (IOException ignored) {
                }
            }

        }
        return "";
    }
}

3.代码测试

代码如下(示例):

package cn.com.hjh.util;

import java.util.List;

public class test {
    public static void main(String[] args) {
        List<GeoAddressVO> address = GeoAddressUtils.addressResolution(IpUtils.getGeoInfo("223.213.59.207"));
        System.out.println(address);
        if (address.size()> 0 && null != address.get(0).getCity()) {
            System.out.println(address.get(0).getCity().replace("|",""));
        }
    }
}

总结

这里我们大致了解了此库的使用方法。接下来我们来谈谈如何设计一个异地登录检测机制,当发生异地登录时发送短信给用户,这里要考虑到一个问题是当发送异地登录时,当天同样地址重复登录时应该避免重复短信发送。首先我们设计一个表来记录用户所有的异地登录信息,表字段应包括用户ID,异地地址,创建时间,更新时间,异地地址登录记录数。此后我们可以根据登录记录数做一个热点地址,只要当前地址不属于热点地址,且当天该地址更新时间与当前时间不在同一天,我们就需要发送异地登录短信给用户。发送短信的情况:1、解析地址为新地址表明用户发生了异地登录;2、用户地址在热点地址外且存在数据库中,表明用户之前一段时间未产生位置偏移。

欢迎大家添加个人公众号,一起进步努力。
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值