2026-02-01
Spring Boot
0

目录

优雅实现Java手机号脱敏:基于Jackson自定义注解方案
一、需求背景
二、技术选型
三、实现步骤
3.1 引入依赖
3.2 自定义手机号脱敏注解
3.3 实现手机号脱敏序列化器
四、使用示例
4.1 实体类中使用注解
4.2 接口返回效果
4.3 边界场景测试
五、扩展与优化
5.1 支持更多脱敏规则
5.2 批量脱敏场景
5.3 脱敏注解复用
六、核心优势
总结

优雅实现Java手机号脱敏:基于Jackson自定义注解方案

在日常的后端开发中,用户手机号等敏感信息的脱敏处理是数据安全合规的基本要求。直接在业务代码中硬编码脱敏逻辑会导致代码冗余、维护成本高,本文将分享一种基于Jackson自定义注解的优雅实现方案,只需一个注解即可完成手机号字段的自动脱敏。

一、需求背景

在接口返回用户数据时,手机号这类敏感信息不能明文展示,通常需要按照138****5678的格式进行脱敏。我们希望:

  1. 脱敏逻辑与业务代码解耦,不侵入业务层
  2. 使用简单,只需在字段上添加注解即可生效
  3. 具备容错性,非手机号格式的字符串原样返回
  4. 空值不做处理,避免空指针异常

二、技术选型

  • Jackson:Java生态中主流的JSON序列化/反序列化框架,支持自定义序列化逻辑
  • Hutool:国产优秀的Java工具类库,提供了完善的手机号校验和脱敏工具,避免重复造轮子
  • 自定义注解:通过注解标记需要脱敏的字段,实现配置化使用

三、实现步骤

3.1 引入依赖

首先确保项目中引入了必要的依赖(以Maven为例):

xml
<!-- Jackson核心依赖 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Hutool工具类库 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.20</version> </dependency>

3.2 自定义手机号脱敏注解

创建自定义注解PhoneDesensitization,用于标记需要脱敏的手机号字段:

java
package com.nsw.server.common.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.nsw.server.common.config.PhoneDesensitizationSerializer; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 手机号脱敏注解 * 标注在需要脱敏的phone字段上 * * @author weizhenwang */ // 注解作用目标:字段 @Target({ElementType.FIELD}) // 注解保留策略:运行时生效(反射可获取) @Retention(RetentionPolicy.RUNTIME) // 生成文档时包含该注解 @Documented // 嵌套Jackson注解的标记,避免注解冲突 @JacksonAnnotationsInside // 指定序列化器:使用自定义的PhoneDesensitizationSerializer处理字段 @JsonSerialize(using = PhoneDesensitizationSerializer.class) public @interface PhoneDesensitization { }

注解关键属性说明

  • @Target(ElementType.FIELD):限定注解只能用在类的字段上
  • @Retention(RetentionPolicy.RUNTIME):注解在运行时保留,Jackson序列化时能通过反射识别
  • @JacksonAnnotationsInside:Jackson的注解,用于嵌套自定义注解,防止注解失效
  • @JsonSerialize:指定该字段序列化时使用的自定义序列化器

3.3 实现手机号脱敏序列化器

创建PhoneDesensitizationSerializer类,继承Jackson的JsonSerializer,实现具体的脱敏逻辑:

java
package com.nsw.server.common.config; import cn.hutool.core.lang.Validator; import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.StrUtil; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; /** * 手机号脱敏序列化器 */ public class PhoneDesensitizationSerializer extends JsonSerializer<String> { @Override public void serialize(String phone, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 1. 空值处理:空字符串/Null直接返回,避免空指针 if (StrUtil.isBlank(phone)) { gen.writeString(phone); return; } // 2. 手机号格式校验:使用Hutool的Validator工具类 if (Validator.isMobile(phone)) { // 3. 格式正确则脱敏:Hutool的DesensitizedUtil实现138****5678格式 String desensitizedPhone = DesensitizedUtil.mobilePhone(phone); gen.writeString(desensitizedPhone); } else { // 4. 格式错误则原样返回,保证数据兼容性 gen.writeString(phone); } } }

核心逻辑说明

  1. 空值防护:通过StrUtil.isBlank()判断空值,避免后续逻辑出现NPE
  2. 格式校验Validator.isMobile()支持中国大陆11位手机号格式校验
  3. 脱敏处理DesensitizedUtil.mobilePhone()内置了成熟的手机号脱敏逻辑(保留前3位和后4位,中间4位替换为*)
  4. 容错处理:非手机号格式的字符串原样返回,避免数据异常

四、使用示例

4.1 实体类中使用注解

在需要脱敏的手机号字段上添加@PhoneDesensitization注解:

java
package com.nsw.server.entity; import com.nsw.server.common.annotation.PhoneDesensitization; import lombok.Data; @Data public class User { /** * 用户ID */ private Long id; /** * 用户名 */ private String username; /** * 手机号(脱敏展示) */ @PhoneDesensitization private String phone; /** * 邮箱 */ private String email; }

4.2 接口返回效果

编写测试接口:

java
package com.nsw.server.controller; import com.nsw.server.entity.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { @GetMapping("/info") public User getUserInfo() { User user = new User(); user.setId(1L); user.setUsername("张三"); user.setPhone("13812345678"); // 真实手机号 user.setEmail("zhangsan@example.com"); return user; } }

访问接口后,返回的JSON数据如下:

json
{ "id": 1, "username": "张三", "phone": "138****5678", // 已脱敏 "email": "zhangsan@example.com" }

4.3 边界场景测试

输入手机号输出结果说明
nullnull空值原样返回
""""空字符串原样返回
"13812345678""138****5678"合法手机号脱敏
"123456""123456"非手机号格式原样返回
"138123456789""138123456789"长度不符原样返回

五、扩展与优化

5.1 支持更多脱敏规则

如果需要自定义脱敏规则(比如保留前2位、后3位),可以修改序列化器:

java
// 自定义脱敏逻辑示例:保留前2位,后3位,中间用*填充 String prefix = phone.substring(0, 2); String suffix = phone.substring(phone.length() - 3); String desensitizedPhone = prefix + "*****" + suffix;

5.2 批量脱敏场景

如果需要对整个项目的手机号字段统一脱敏,可结合Spring Boot的配置,实现全局序列化规则,无需逐个字段加注解。

5.3 脱敏注解复用

可基于该思路扩展更多脱敏注解,如@IdCardDesensitization(身份证脱敏)、@BankCardDesensitization(银行卡脱敏)等,只需替换对应的序列化器即可。

六、核心优势

  1. 侵入性低:只需添加注解,无需修改业务代码,符合开闭原则
  2. 通用性强:基于Jackson实现,适配所有使用Jackson序列化的场景(Spring Boot默认JSON处理器)
  3. 容错性好:空值、非法格式均做了兼容处理,避免线上异常
  4. 易于维护:脱敏逻辑集中管理,修改时只需调整序列化器,无需逐个修改业务代码

总结

本文通过自定义Jackson注解+序列化器的方式,结合Hutool工具类,实现了优雅、通用的手机号脱敏方案。核心要点如下:

  1. 利用@JsonSerialize注解指定自定义序列化器,实现字段级别的序列化控制
  2. 通过Hutool工具类简化手机号校验和脱敏逻辑,提升开发效率
  3. 做好空值和异常格式的容错处理,保证代码健壮性
  4. 注解化使用方式降低代码侵入性,便于维护和扩展

该方案不仅适用于手机号脱敏,也可扩展到身份证、银行卡等其他敏感信息的脱敏场景,是后端开发中处理敏感数据的最佳实践之一。

本文作者:JACK WEI

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!