告别国际号码验证难题:Spring Boot集成libphonenumber完全指南

告别国际号码验证难题:Spring Boot集成libphonenumber完全指南

【免费下载链接】libphonenumber Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers. 【免费下载链接】libphonenumber 项目地址: https://gitcode.com/gh_mirrors/libp/libphonenumber

在全球化应用开发中,电话号码验证始终是令人头疼的问题。不同国家的号码格式千差万别,手动编写验证规则不仅繁琐,还容易遗漏边缘情况。本文将介绍如何在Spring Boot项目中集成libphonenumber库,通过自动配置和服务封装,轻松实现国际电话号码的解析、格式化和验证功能。

为什么选择libphonenumber

libphonenumber是Google开发的国际电话号码处理库,支持Java、C++和JavaScript等多种语言。该库能够解析、格式化和验证全球几乎所有国家和地区的电话号码,解决了国际化应用中的号码处理难题。

项目核心功能由PhoneNumberUtil.java类提供,包含了号码验证、格式化、解析等基础操作。同时,AsYouTypeFormatter.java类提供了实时输入格式化功能,提升用户体验。

集成准备:添加依赖

首先,在Spring Boot项目的pom.xml中添加libphonenumber依赖:

<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>libphonenumber</artifactId>
    <version>8.13.25</version>
</dependency>
<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>geocoder</artifactId>
    <version>2.184</version>
</dependency>
<dependency>
    <groupId>com.googlecode.libphonenumber</groupId>
    <artifactId>carrier</artifactId>
    <version>1.164</version>
</dependency>

自动配置实现

创建PhoneNumberAutoConfiguration类,实现libphonenumber的自动配置:

@Configuration
public class PhoneNumberAutoConfiguration {
    
    @Bean
    public PhoneNumberUtil phoneNumberUtil() {
        return PhoneNumberUtil.getInstance();
    }
    
    @Bean
    public PhoneNumberToCarrierMapper carrierMapper() {
        return PhoneNumberToCarrierMapper.getInstance();
    }
    
    @Bean
    public PhoneNumberOfflineGeocoder geocoder() {
        return PhoneNumberOfflineGeocoder.getInstance();
    }
    
    @Bean
    public PhoneNumberService phoneNumberService(PhoneNumberUtil phoneNumberUtil,
                                                PhoneNumberToCarrierMapper carrierMapper,
                                                PhoneNumberOfflineGeocoder geocoder) {
        return new PhoneNumberServiceImpl(phoneNumberUtil, carrierMapper, geocoder);
    }
}

服务层封装

创建PhoneNumberService接口及其实现类,封装电话号码处理功能:

public interface PhoneNumberService {
    // 解析号码
    Phonenumber.PhoneNumber parse(String phoneNumber, String regionCode) throws NumberParseException;
    
    // 验证号码
    boolean isValid(String phoneNumber, String regionCode);
    
    // 格式化号码
    String format(Phonenumber.PhoneNumber number, PhoneNumberUtil.PhoneNumberFormat format);
    
    // 实时输入格式化
    String formatAsYouType(char nextChar, String regionCode);
    
    // 获取号码归属地
    String getGeolocation(Phonenumber.PhoneNumber number, Locale locale);
    
    // 获取运营商信息
    String getCarrier(Phonenumber.PhoneNumber number, Locale locale);
}

实现类中,使用PhoneNumberUtil.java的核心方法:

@Service
public class PhoneNumberServiceImpl implements PhoneNumberService {
    
    private final PhoneNumberUtil phoneNumberUtil;
    private final PhoneNumberToCarrierMapper carrierMapper;
    private final PhoneNumberOfflineGeocoder geocoder;
    private final ThreadLocal<Map<String, AsYouTypeFormatter>> formatterCache = 
        ThreadLocal.withInitial(HashMap::new);
    
    public PhoneNumberServiceImpl(PhoneNumberUtil phoneNumberUtil,
                                 PhoneNumberToCarrierMapper carrierMapper,
                                 PhoneNumberOfflineGeocoder geocoder) {
        this.phoneNumberUtil = phoneNumberUtil;
        this.carrierMapper = carrierMapper;
        this.geocoder = geocoder;
    }
    
    @Override
    public Phonenumber.PhoneNumber parse(String phoneNumber, String regionCode) throws NumberParseException {
        return phoneNumberUtil.parse(phoneNumber, regionCode);
    }
    
    @Override
    public boolean isValid(String phoneNumber, String regionCode) {
        try {
            Phonenumber.PhoneNumber number = parse(phoneNumber, regionCode);
            return phoneNumberUtil.isValidNumber(number);
        } catch (NumberParseException e) {
            return false;
        }
    }
    
    // 其他方法实现...
}

实时输入格式化实现

利用AsYouTypeFormatter.java实现实时格式化:

@Override
public String formatAsYouType(char nextChar, String regionCode) {
    AsYouTypeFormatter formatter = formatterCache.get().computeIfAbsent(regionCode, 
        k -> phoneNumberUtil.getAsYouTypeFormatter(regionCode));
    
    if (nextChar == '\b') { // 处理退格键
        // 实现退格逻辑
        return "";
    }
    
    return formatter.inputDigit(nextChar);
}

控制器层使用

创建PhoneNumberController,提供REST接口:

@RestController
@RequestMapping("/api/phone")
public class PhoneNumberController {
    
    private final PhoneNumberService phoneNumberService;
    
    public PhoneNumberController(PhoneNumberService phoneNumberService) {
        this.phoneNumberService = phoneNumberService;
    }
    
    @PostMapping("/validate")
    public ResponseEntity<Map<String, Object>> validate(
            @RequestParam String number, 
            @RequestParam(defaultValue = "CN") String region) {
        
        Map<String, Object> result = new HashMap<>();
        boolean valid = phoneNumberService.isValid(number, region);
        result.put("valid", valid);
        
        if (valid) {
            try {
                Phonenumber.PhoneNumber phoneNumber = phoneNumberService.parse(number, region);
                result.put("e164Format", phoneNumberService.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164));
                result.put("nationalFormat", phoneNumberService.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.NATIONAL));
                result.put("internationalFormat", phoneNumberService.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL));
                result.put("location", phoneNumberService.getGeolocation(phoneNumber, Locale.CHINA));
                result.put("carrier", phoneNumberService.getCarrier(phoneNumber, Locale.CHINA));
            } catch (NumberParseException e) {
                // 已验证过,理论上不会抛出异常
            }
        }
        
        return ResponseEntity.ok(result);
    }
    
    @PostMapping("/format-as-you-type")
    public ResponseEntity<String> formatAsYouType(
            @RequestParam char digit, 
            @RequestParam(defaultValue = "CN") String region,
            @RequestParam(defaultValue = "false") boolean reset) {
        
        if (reset) {
            phoneNumberService.resetAsYouTypeFormatter(region);
        }
        
        String formatted = phoneNumberService.formatAsYouType(digit, region);
        return ResponseEntity.ok(formatted);
    }
}

测试与验证

使用Postman或其他工具测试API:

  1. 验证号码:POST /api/phone/validate?number=13800138000&region=CN
  2. 实时格式化:POST /api/phone/format-as-you-type?digit=1&region=CN

总结

通过本文的方法,我们成功将libphonenumber集成到Spring Boot项目中,实现了电话号码的解析、验证、格式化等功能。该方案具有以下优势:

  1. 自动配置,使用简单
  2. 服务层封装,便于维护
  3. 支持全球号码格式,适用性广
  4. 实时格式化,提升用户体验

项目完整代码可参考java/demo/目录下的示例应用。如需更多高级功能,可以进一步扩展PhoneNumberService接口。

扩展阅读

【免费下载链接】libphonenumber Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers. 【免费下载链接】libphonenumber 项目地址: https://gitcode.com/gh_mirrors/libp/libphonenumber

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值