结论先行
FastJSON 的 SerializeFilter
接口通过 动态拦截和修改序列化过程 ,可实现字段名重命名、敏感数据脱敏、字段过滤等高级功能。其核心子接口包括 PropertyPreFilter
、ValueFilter
、NameFilter
和 ContextValueFilter
,分别解决不同场景需求。
接口选择指南
过滤器类型 | 适用场景 | 示例 |
---|---|---|
PropertyPreFilter |
按字段名黑名单/白名单过滤 | 过滤临时字段 _temp |
ValueFilter |
动态修改字段值 | 手机号脱敏 |
NameFilter |
统一字段命名风格 | 驼峰转下划线 |
ContextValueFilter |
根据类或字段类型差异化处理 | 仅对特定类脱敏 |
完整流程图
graph TD
A[开始序列化] --> B[遍历对象字段]
B --> C{是否通过 PropertyPreFilter?}
C -->|否| D[丢弃字段]
C -->|是| E[应用 NameFilter 修改字段名]
E --> F[应用 ValueFilter/ContextValueFilter 修改值]
F --> G[生成最终键值对]
G --> H[继续下一个字段]
H --> B
H --> I[生成完整 JSON]
一、PropertyPreFilter
:按字段名过滤
场景
过滤对象中不符合命名规范的字段(如临时字段 _temp
)。
示例代码
java
public class PropertyPreFilterDemo {
public static void main(String[] args) {
User user = new User("admin", "_tempData123", "13800138000");
// 创建过滤器:过滤以 "_" 开头的字段
PropertyPreFilter filter = (serializer, source, name) ->
!name.startsWith("_"); // 返回 true 表示保留该字段
String json = JSON.toJSONString(user, filter);
System.out.println(json);
// 输出:{"name":"admin","phone":"13800138000"}
}
static class User {
private String name;
private String _tempData; // 需要过滤的字段
private String phone;
public User(String name, String _tempData, String phone) {
this.name = name;
this._tempData = _tempData;
this.phone = phone;
}
// 省略 getter/setter
}
}
源码解析
-
PropertyPreFilter
接口定义javapublic interface PropertyPreFilter extends SerializeFilter { boolean apply(JSONSerializer serializer, Object object, String name); }
name
:当前字段名。- 返回
true
表示保留字段,false
表示过滤。
-
Lambda 实现
java(serializer, source, name) -> !name.startsWith("_")
- 直接通过字段名判断是否保留,简洁高效。
二、ValueFilter
:动态修改字段值
场景
对敏感数据(如手机号、身份证号)进行脱敏处理。
示例代码(含健壮性校验)
java
public class ValueFilterDemo {
public static void main(String[] args) {
User user = new User("李四", "510123199001011234", "13812345678");
// 创建 ValueFilter:脱敏身份证和手机号
ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if (value == null) return null; // 处理空值
switch (name) {
case "idCard":
if (value instanceof String && ((String) value).length() >= 15) {
String idCard = (String) value;
return idCard.substring(0, 6) + "********" + idCard.substring(14);
}
break;
case "phone":
if (value instanceof String && ((String) value).length() == 11) {
String phone = (String) value;
return phone.substring(0, 3) + "****" + phone.substring(7);
}
break;
}
return value;
}
};
String json = JSON.toJSONString(user, filter);
System.out.println(json);
// 输出:{"idCard":"510123********1234","name":"李四","phone":"138****5678"}
}
static class User {
private String name;
private String idCard;
private String phone;
// 省略构造方法和 getter/setter
}
}
源码解析
-
ValueFilter
接口定义javapublic interface ValueFilter extends SerializeFilter { Object process(Object object, String name, Object value); }
object
:当前序列化的对象实例(可获取其他字段值)。value
:当前字段的原始值,需返回修改后的值。
-
健壮性设计
- 校验
value
是否为null
,避免空指针异常。 - 校验数据类型和长度,防止无效脱敏。
- 校验
三、NameFilter
:字段名重命名
场景
统一 JSON 字段命名风格(如 Java 驼峰命名 → JSON 下划线命名)。
示例代码
java
public class NameFilterDemo {
public static void main(String[] args) {
Product product = new Product(1001, "MacBook Pro", 14999.99);
// 创建 NameFilter:驼峰转下划线
NameFilter filter = (object, name, value) -> {
String regex = "([a-z])([A-Z]+)";
String replacement = "$1_$2";
return name.replaceAll(regex, replacement).toLowerCase();
};
String json = JSON.toJSONString(product, filter);
System.out.println(json);
// 输出:{"product_id":1001,"product_name":"MacBook Pro","product_price":14999.99}
}
static class Product {
private Integer productId;
private String productName;
private Double productPrice;
// 省略构造方法和 getter/setter
}
}
源码解析
- 正则表达式处理
([a-z])([A-Z]+)
:匹配驼峰命名中的大写字母位置。$1_$2
:在大写字母前插入下划线。toLowerCase()
:统一转为小写,符合下划线风格。
四、ContextValueFilter
:上下文感知的字段处理
场景
根据不同对象类型动态脱敏(如 User
类手机号脱敏,Order
类不脱敏)。
示例代码
java
public class ContextValueFilterDemo {
public static void main(String[] args) {
User user = new User("王五", "13800001234");
Order order = new Order(2001, "13800001234");
// 创建 ContextValueFilter:仅对 User 类手机号脱敏
ContextValueFilter filter = new ContextValueFilter() {
@Override
public Object process(
BeanContext context, Object object, String name, Object value) {
// 获取字段所属的类
Class<?> clazz = context.getBeanClass();
if (clazz == User.class && "phone".equals(name)) {
return handlePhone((String) value);
}
return value;
}
private String handlePhone(String phone) {
if (phone != null && phone.length() == 11) {
return phone.substring(0, 3) + "****" + phone.substring(7);
}
return phone;
}
};
System.out.println("User JSON: " + JSON.toJSONString(user, filter));
// 输出:{"name":"王五","phone":"138****1234"}
System.out.println("Order JSON: " + JSON.toJSONString(order, filter));
// 输出:{"orderId":2001,"contactPhone":"13800001234"}
}
static class User {
private String name;
private String phone;
// 省略构造方法和 getter/setter
}
static class Order {
private Integer orderId;
private String contactPhone;
// 省略构造方法和 getter/setter
}
}
源码解析
-
BeanContext
核心方法javapublic interface BeanContext { Class<?> getBeanClass(); // 获取当前对象的类 Method getMethod(); // 获取当前字段的 getter 方法 Field getField(); // 获取当前字段的反射对象 }
- 可通过
getBeanClass()
判断对象类型,实现差异化处理。
- 可通过
五、组合过滤器与性能优化
场景
同时使用多个过滤器(如脱敏 + 字段名转换)。
示例代码
java
public class CombinedFilterDemo {
public static void main(String[] args) {
User user = new User("赵六", "13912345678");
// 过滤器1:手机号脱敏
ValueFilter phoneFilter = (obj, name, value) ->
"phone".equals(name) ? "***-****-" + ((String) value).substring(7) : value;
// 过滤器2:字段名转下划线
NameFilter nameFilter = (obj, name, value) ->
name.replaceAll("([A-Z])", "_$1").toLowerCase();
// 组合使用两个过滤器
String json = JSON.toJSONString(user, phoneFilter, nameFilter);
System.out.println(json);
// 输出:{"name":"赵六","phone":"***-****-5678"}
}
static class User {
private String name;
private String phone;
// 省略构造方法和 getter/setter
}
}
最佳实践
-
性能优化
- 避免在过滤器中执行耗时操作(如数据库查询)。
- 优先使用
@JSONField
处理静态规则,过滤器处理动态逻辑。
-
全局过滤器注册
java// 全局注册 PhoneFilter,对所有序列化生效 SerializeConfig.getGlobalInstance().addFilter(User.class, phoneFilter);
- 谨慎使用全局过滤器,避免影响其他模块。
文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读