号码归属地查询功能实现

后端

libphonenumber

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

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

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

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

使用

导入maven坐标

<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>

编写工具类

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 Map<String, Object> getPhoneAffiliationInfo(String phone) {
         String fixNumber = phone;
         // 号码长度不够自动补零
         if (phone.length() < 11){
             fixNumber = phone + "0".repeat(11 - phone.length());
         }
         Map<String, Object> affiliation = new HashMap<>();
         affiliation.put("phone", phone);
         affiliation.put("carrier", getPhoneCarrier(fixNumber));
         affiliation.put("region", getRegionInfoByPhone(fixNumber));
         return affiliation;
     }
}

这段代码借鉴于网络,不过我在getPhoneAffiliationInfo()方法中做了些许修改

public static Map<String, Object> getPhoneAffiliationInfo(String phone) {
    String fixNumber = phone;
    // 号码长度不够自动补零
    if (phone.length() < 11){
        fixNumber = phone + "0".repeat(11 - phone.length());
    }
    Map<String, Object> affiliation = new HashMap<>();
    affiliation.put("phone", phone);
    affiliation.put("carrier", getPhoneCarrier(fixNumber));
    affiliation.put("region", getRegionInfoByPhone(fixNumber));
    return affiliation;
}

我这里使用后补零的方式来确保电话号码的位数,以达到输入前三个数字即可查询到营业商的效果

对于超出长度的电话号码,getPhoneCarrier()getRegionInfoByPhone()都可以查询,不过返回的是空结果,不会报错,所以我就没做错误处理。

/**
     * 生成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;
}

由于这里规定了号码前缀为 +86 所以只能查询国内的电话号码归属地。

代码参考:SpringBoot通过手机号获取归属地,你应该知道的几种方式。_通过手机号码获取运营商归属地-CSDN博客

调用接口

@GetMapping("/getPhoneAffiliationInfo.do")
public Result getPhoneAffiliationInfo(@RequestParam("phone") String phone){
    return Result.success(PhoneToRegionUtil.getPhoneAffiliationInfo(phone));
}

响应格式

{
    "code": 1,
    "msg": "success",
    "data": {
        "carrier": "中国联通",
        "phone": "15566668888",
        "region": "辽宁省大连市"
    }
}

遇到的问题

在功能开发的时候遇到过下面这两个错误

  • 其一:找不到对应的构造器

java: 无法将类 com.example.pojo.Result中的构造器 Result应用到给定类型;
  需要: 没有参数
  找到:    int,java.lang.String,<nulltype>
  原因: 实际参数列表和形式参数列表长度不同

这里排查出来时Lombok的@AllArgsConstructor注解失效,我就取消了注解,手动定义了一个全参构造,问题解决。

  • 其二:无法返回客户端要求的数据格式

[org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]

一开始我以为这两个报错是不同的原因构成的,还花了好些时间去调整请求头,但都无济于事。后面在网上查资料发现是返回的对象没有getter和setter造成的,所以这里还是Lombok的问题。手动添加了getter和setter之后问题就解决了。至于为什么Lombok会失效我还在研究。

前端

主要设计

因为我的学习方向是Java后端,所以前端代码我是在网络上找的,手动做了一些功能上的调整。

<el-col :span="24" style="text-align: center;">
    <el-input 
              v-model="phoneNumber" 
              placeholder="请输入要查询的手机号" 
              style="width: 80%;" 
              @input="onInputChange"
              />
</el-col>

这个输入框下面本来还有一个button用来触发事件,我这里改成使用@input来监听输入框值得变化并以此触发事件,即每输入一个字就调用一次onInputChange,向后端发起一次请求,由于后端会自动将号码补齐,所以可以起到输入前2~3个数字即可查询到运营商等信息。

// 输入框变化时调用此方法
const onInputChange = async () => {
  if (phoneNumber.value.length > 0) {
    try {
      // 调用接口请求数据
      const response = await getPhoneAffiliationInfo(phoneNumber.value);
      
      // 判断接口返回是否成功
      if (response.code === 1) {
        // 如果请求成功,更新表格数据
        tableData.value = [{
          phone: response.data.phone,
          carrier: response.data.carrier,
          region: response.data.region,
        }];
      } else {
        // 如果请求失败,清空表格数据
        tableData.value = [];
      }
    } catch (error) {
      // 请求失败时处理错误并清空表格数据
      console.error("请求失败:", error);
      tableData.value = [];
    }
  }
};

最后通过对tableData的双向数据绑定,实现查询结果的动态显示。

<el-col :span="24" style="margin-top: 30px;">
    <el-table :data="tableData" style="width: 100%">
        <el-table-column label="手机号码" prop="phone"></el-table-column>
        <el-table-column label="运营商" prop="carrier"></el-table-column>
        <el-table-column label="地区" prop="region"></el-table-column>
    </el-table>
</el-col>

页面展示

  • 输入号码前三个数字

  • 输入完整电话号码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值