SpringBoot实现根据手机号获取归属地

 更新时间:2023年12月11日 17:03:53   作者:抢老婆酸奶的小肥仔  
这篇文章主要为大家详细介绍了SpringBoot如何实现根据手机号获取归属地,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

最近在做公司需求时,甲方一会提出根据IP获取所在地,一会有提出根据手机号获取手机号所在地。真的是:需求时时变,累死程序猿。甲方才是爸爸。

之前已经实现过根据IP获取所在地的几种方式,大家可以参考我之前写的文章下:《SpringBoot通过ip获取归属地的几种方式》。

那么今天我们来看看根据手机号有哪些方式可以获取归属地呢?

废话不多说,开撸!

1、基于libphonenumber

libphonenumber:是谷歌提供的一款用于解析、格式化和校验国际手机号码的软件库。它提供了三个包,分别对应不同的功能。

libphonenumber:用于校验手机号的正确性,提供了:getNumberType,isNumberMatch ,getExampleNumber 等方法。

carrier:用于获取手机号的供应商。通过初始化PhoneNumberToCarrierMapper ,调用getNameForNumber可获取运营商信息。

geocoder:用于获取手机号的归属地。通过初始化PhoneNumberOfflineGeocoder ,调用getDescriptionForNumber方法可获取手机归属地。

下面我们来说说具体实现。

引入包:

 <dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>libphonenumber</artifactId>
    <version>8.13.26</version>
</dependency>
<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>carrier</artifactId>
    <version>1.210</version>
</dependency>
<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>geocoder</artifactId>
    <version>2.220</version>
</dependency>

1.1 编写工具

引入libphonenumber所有包后,我们编写一个工具类,实现手机校验,获取供应商,归属地等信息。

/**
 * @author: jiangjs
 * @description: 基于google的libphonenumber将手机号转成地区及供应商信息
 * @date: 2023/11/30 14:33
 **/
public class PhoneToRegionUtil {

    /**
     * 手机号基本工具类
     */
    private final static PhoneNumberUtil PHONE_NUMBER_UTIL = PhoneNumberUtil.getInstance();

    /**
     * 运营商
     */
    private final static PhoneNumberToCarrierMapper CARRIER_MAPPER = PhoneNumberToCarrierMapper.getInstance();

    /**
     *
     */
    private final static PhoneNumberOfflineGeocoder GEO_CODER = PhoneNumberOfflineGeocoder.getInstance();

    /**
     * 验证当前手机号是否有效
     * @param phone 手机号
     * @return 校验结果
     */
    public static boolean isValidNumber(String phone){
        return PHONE_NUMBER_UTIL.isValidNumber(getPhoneNumber(phone));
    }

    /**
     * 获取手机号运营商
     * @param phone 手机号
     * @return 运营商
     */
    public static String getPhoneCarrier(String phone){
        return isValidNumber(phone) ?  CARRIER_MAPPER.getNameForNumber(getPhoneNumber(phone), Locale.CHINA) : "";
    }

    /**
     * 获取手机号归属地
     * @param phone 手机号
     * @return 归属地
     */
    public static String getRegionInfoByPhone(String phone){
        return isValidNumber(phone) ? GEO_CODER.getDescriptionForNumber(getPhoneNumber(phone),Locale.CHINESE) : "";
    }

    /**
     * 生成PhoneNumber
     * @param phone 手机号
     * @return PhoneNumber
     */
    private static Phonenumber.PhoneNumber getPhoneNumber(String phone){
        Phonenumber.PhoneNumber phoneNumber = new Phonenumber.PhoneNumber();
        phoneNumber.setCountryCode(86);
        phoneNumber.setNationalNumber(Long.parseLong(phone));
        return phoneNumber;
    }

     /**
     * 获取手机号的归属信息:运营商,归属地
     * @param phone 手机号
     * @return 归属信息
     */
    public static JSONObject getPhoneAffiliationInfo(String phone){
        JSONObject affiliation = new JSONObject();
        affiliation.put("phone",phone);
        affiliation.put("carrier",getPhoneCarrier(phone));
        affiliation.put("region",getRegionInfoByPhone(phone));
        return affiliation;
    }
}

其中,getPhoneNumber创建每个手机号的Phonenumber.PhoneNumber,供其他接口调用。同时在调用运营商等接口时先进行手机号的校验。

在上面的接口中,我们会发现创建Phonenumber.PhoneNumber时,会使用setCountryCode方法去设置所在国家的电话区号,我们有时候复制手机号会发现前面是86,而86就是代表我们国家。每个国家有每个国家电话代号,其他国家代号,小伙伴们可以参考国际电信联盟根据 E.164 标准 分配给各国或特殊行政区的代码。

1.2 获取归属地

已经封装了工具类,那么接下来我们就测试一下,用手机号试试能不能获取归属信息。

我们直接在Controller层中编写接口:

@GetMapping("/getPhoneAffiliationInfo.do/{phone}")
public JsonResult<?> getPhoneAffiliationInfo(@PathVariable("phone") String phone){
    return JsonResult.success(PhoneToRegionUtil.getPhoneAffiliationInfo(phone));
}

在浏览器中输入地址,添加号码:

通过测试,引用谷歌提供的包,可以解决我们的需求。

哈哈,可以不用加班.......

2、基于CSV文件

虽然引入谷歌的可以搞定需求了,但是作为程序员总要想想还有没有其他方式实现?这不又找一种方式。哈哈

其实我们的手机号是有规律可循的:

1、前3位:前三位的数字,其实代表的是运营商。不同的运营商会提供不同的号段。比如:我的手机号是135开头就是移动提供的。移动除了提供135号段外,还有其他各种号段,如134,137等;联通则提供了:130,131等号段;电信呢,提供了133,153等号段。

2、前7位:前7位则是可以确定手机号的归属地,例如:我的手机号前7位是1350154,则可以确定是广东省广州市。

既然我们知道了手机号的一些规律,那么如果有一份这样的文档,我们是不是就可以基于这份文档进行归属地的查询呢?

还真有这样的一份文档,我在网上找到一份4年前的CSV文档。如图:

既然有这份文档那我们就好实现了该功能。

2.1 读取CSV文件

只所以写读取CSV文件,是因为读取到这些信息后,想怎么查询就由我们自己说了算了。可以将数据存储到数据库查询,也可以放在redis中查询。下面我们基于redis的查询来实现归属功能。

将CSV文件读取到redis中。

/**
 * @author: jiangjs
 * @description: 服务启动后,加载数据到缓存
 * @date: 2023/12/9 15:32
 **/
@ConditionalOnProperty(havingValue = "true",value = "phoneToRegion.enabled")
@Component
public class ReadRegionToRedisStart implements CommandLineRunner {
    private final static String REGION_CSV_PATH = "classpath:/static/region/phonetmp.csv";

    private final static String PHONE_REGION_KEY = "country_phone_region_info";

    @Resource
    private ResourceLoader resourceLoader;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    @Override
    public void run(String... args) {
        long size = redisTemplate.opsForHash().size(PHONE_REGION_KEY);
        if (size <= 0){
            try (InputStream ism = resourceLoader.getResource(REGION_CSV_PATH).getInputStream()){
                Assert.notNull(ism,"读取手机号信息文件为空");
                BufferedReader reader = new BufferedReader(new InputStreamReader(ism));
                String line = reader.readLine();
                while (StringUtils.isNoneBlank(line)){
                    String[] lineVal = line.split(",");
                    RegionVo regionVo = new RegionVo();
                    regionVo.setPhonePrefix(lineVal[0]).setProvince(lineVal[1]).setCity(lineVal[2]).setCarrier(lineVal[3]);
                    redisTemplate.opsForHash().put(PHONE_REGION_KEY,lineVal[0],regionVo);
                    line = reader.readLine();
                }
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("获取手机号信息报错");
            }
        }

    }
}

我们在系统启动后,自动将CSV数据加载到redis中,当然通过@ConditionalOnProperty可以来自行决定要不要加载到内存中。不知道@ConditionalOnProperty注解使用的小伙伴去我的主页可以找到这篇文章来了解。

2.2 创建工具

数据被加载到内存后,那么我们就可以编写工具类来进行获取手机归属地。

/**
 * @author: jiangjs
 * @description: 读取CSV文件,根据手机号前7位进行匹配
 * @date: 2023/11/30 14:54
 **/
@Component
public class PhoneToRegionCsvUtil {

    private final static String PHONE_REGION_KEY = "country_phone_region_info";

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 根据手机号获取手机归属地
     * @param phone 手机号
     * @return 归属地信息
     */
    public RegionVo getPhoneToRegion(String phone){
        String prefix = StringUtils.substring(phone, 0, 7);
        Object region = redisTemplate.opsForHash().get(PHONE_REGION_KEY, prefix);
        return Objects.isNull(region) ? new RegionVo() : (RegionVo) region;
    }
}

2.3 获取归属地

有了工具类,那我们来测试一下。

直接在Controller层中编写接口:

@Resource
private PhoneToRegionCsvUtil phoneToRegionCsvUtil;

@GetMapping("/getPhoneGeoInfoByCsv.do/{phone}")
public JsonResult<?> getPhoneGeoInfoByCsv(@PathVariable("phone") String phone){
    return JsonResult.success(phoneToRegionCsvUtil.getPhoneToRegion(phone));
}

浏览器中访问:

至此我们也可以正常的获取到手机号的归属地。

3、页面抓取

页面抓取这种方式,跟我之前的《SpringBoot通过ip获取归属地的几种方式》中的页面抓取方式是一样的,在这就不跟大家详细介绍了。

总结

文中介绍了三种方式进行手机号查询归属地的方式。

第一种:基于谷歌提供的国际解析包,引入后不用额外引入其他的东西,只需要写工具类即可,查询速度也比较快。

第二种:基于CSV文件的,不用额外引入具体的包,但是要引入CSV文件,大小在12M多,当然也可以将文件放在磁盘里,这样不用担心部署包过大。如果是基于内存查询的话,则需要依赖redis,增加了难度。

第三种:这个就不推荐了,毕竟依赖于第三方,如果服务挂了的话就没法使用了。如果用户量大的话,很可能会被第三方......,大家都懂的。

我在应用就是使用了第一种方式。

以上就是SpringBoot实现根据手机号获取归属地的详细内容,更多关于SpringBoot手机号获取归属地的资料请关注脚本之家其它相关文章!

相关文章

  • 在Java与Kotlin之间如何进行互操作详解

    在Java与Kotlin之间如何进行互操作详解

    这篇文章主要给大家介绍了关于在Java和Kotlin之间如何进行互操作的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-12-12
  • idea首次使用需要配置哪些东西

    idea首次使用需要配置哪些东西

    这篇文章主要介绍了idea首次使用需要配置哪些东西,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Spring boot webService使用方法解析

    Spring boot webService使用方法解析

    这篇文章主要介绍了Spring boot webService使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Java分布式ID中Snowflake雪花算法应用实现

    Java分布式ID中Snowflake雪花算法应用实现

    Snowflake算法作为一种高效且易于实现的分布式ID生成方案,能够很好地满足分布式系统中对全局唯一ID的需求,本文就来介绍一下Java分布式ID中Snowflake雪花算法应用实现,感兴趣的可以了解一下
    2024-07-07
  • IDEA搭建Maven模块化项目的实现

    IDEA搭建Maven模块化项目的实现

    本文主要介绍了IDEA搭建Maven模块化项目的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • Mybatis返回插入主键id的方法

    Mybatis返回插入主键id的方法

    这篇文章主要介绍了 Mybatis返回插入主键id的方法,在文章底部给大家补充了Mybatis中insert中返回主键ID的方法,非常不错,需要的朋友可以参考下
    2017-04-04
  • Java 8中的18个常用日期处理(收藏)

    Java 8中的18个常用日期处理(收藏)

    伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API,这篇文章主要介绍了Java 8的18个常用日期处理,需要的朋友可以参考下
    2022-04-04
  • Springboot AOP对指定敏感字段数据加密存储的实现

    Springboot AOP对指定敏感字段数据加密存储的实现

    本篇文章主要介绍了利用Springboot+AOP对指定的敏感数据进行加密存储以及对数据中加密的数据的解密的方法,代码详细,具有一定的价值,感兴趣的小伙伴可以了解一下
    2021-11-11
  • Java编程实现中英混合字符串数组按首字母排序的方法

    Java编程实现中英混合字符串数组按首字母排序的方法

    这篇文章主要介绍了Java编程实现中英混合字符串数组按首字母排序的方法,涉及Java字符串操作及拼音转换的相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • Java的Dialog和FileDialog你知道啊

    Java的Dialog和FileDialog你知道啊

    这篇文章主要为大家详细介绍了Java的Dialog和FileDialog,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03

最新评论