Jackson 是一个流行的 Java JSON 处理库,它提供了将 Java 对象与 JSON 数据相互转换的功能。Jackson 的主要功能包括:
- 序列化:将 Java 对象转换为 JSON 字符串。
- 反序列化:将 JSON 字符串转换为 Java 对象。
Jackson 提供了以下几个核心组件:
- jackson-core:核心库,提供 JSON 的解析和生成。
- jackson-databind:数据绑定库,负责将 JSON 数据绑定到 Java 对象。
- jackson-annotations:包含用于 JSON 处理的注解,如 @JsonProperty、@JsonIgnore等。
基本使用
在使用 Jackson 之前,你需要在 pom.xml 中添加 Jackson 的依赖:
<dependencies><!-- Jackson 核心库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.13.3</version></dependency><!-- Jackson 数据绑定库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.3</version></dependency><!-- Jackson 注解库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.13.3</version></dependency>
</dependencies>
序列化示例:
import com.fasterxml.jackson.databind.ObjectMapper;public class Example {public static void main(String[] args) throws Exception {ObjectMapper objectMapper = new ObjectMapper();// 创建一个示例对象User user = new User();user.setName("John");user.setAge(30);// 将对象转换为 JSON 字符串String json = objectMapper.writeValueAsString(user);System.out.println(json); // 输出: {"name":"John","age":30}}
}class User {private String name;private int age;// Getter 和 Setter
}
反序列化示例:
import com.fasterxml.jackson.databind.ObjectMapper;public class Example {public static void main(String[] args) throws Exception {ObjectMapper objectMapper = new ObjectMapper();// JSON 字符串String json = "{\"name\":\"John\",\"age\":30}";// 将 JSON 字符串转换为 Java 对象User user = objectMapper.readValue(json, User.class);System.out.println(user.getName()); // 输出: John}
}class User {private String name;private int age;// Getter 和 Setter
}
实现自定义注解
如果你需要自定义序列化或反序列化逻辑,你可以创建自定义注解和序列化器。以下是详细步骤:
1. 定义自定义注解
创建一个自定义注解,用于标记需要特殊处理的字段。例如,我们可以创建一个 @Sensitive 注解,用于标记需要脱敏处理的字段。
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JsonSerialize(using = SensitiveJsonSerializer.class) // 指定自定义序列化器
public @interface Sensitive {SensitiveStrategy strategy(); // 指定脱敏策略
}
理解 SensitiveJsonSerializer 类的代码时,可以将其分为几个部分来讲解。这个类实现了 JsonSerializer,用于自定义序列化过程,特别是处理带有 @Sensitive 注解的字段。下面详细解释代码的每个部分:
1. JsonSerializer<String>
SensitiveJsonSerializer 类继承自 Jackson 的 JsonSerializer<String>。这是一个泛型类,用于自定义如何将 String 类型的对象序列化为 JSON。
2. serialize 方法
serialize 方法是 JsonSerializer 类的抽象方法,必须实现。它的作用是定义如何将 Java 对象(在这个例子中是 String)转换为 JSON 字符串。
2. 定义脱敏策略
创建一个枚举 SensitiveStrategy,定义不同的脱敏策略。
import java.util.function.Function;public enum SensitiveStrategy {USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));private final Function<String, String> desensitizer;SensitiveStrategy(Function<String, String> desensitizer) {this.desensitizer = desensitizer;}public Function<String, String> desensitizer() {return desensitizer;}
}
理解 strategy.desensitizer().apply(value) 是如何工作的,我们需要详细了解 Function<String, String> 这个接口,以及 SensitiveStrategy 枚举类是如何定义和使用这个接口的。
Function 接口
Function 是 Java 8 引入的一个函数式接口,它位于 java.util.function 包中。这个接口定义了一个方法 apply,用于将一个输入值转换成一个输出值:
@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}
- T是输入类型
- R是输出类型
- apply方法接受一个- T类型的参数,并返回一个- R类型的结果
SensitiveStrategy 枚举
在 SensitiveStrategy 枚举中,每个枚举实例都被赋予了一个 Function<String, String> 类型的对象。这个对象用于定义字符串脱敏的具体实现。
public enum SensitiveStrategy {USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));private final Function<String, String> desensitizer;SensitiveStrategy(Function<String, String> desensitizer) {this.desensitizer = desensitizer;}public Function<String, String> desensitizer() {return desensitizer;}
}
每个枚举实例都使用一个 Function<String, String> 对象来定义如何进行字符串替换:
- USERNAME实例的- Function对象:- s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")- 这个函数会将用户名的第二个字符替换为 *
 
- 这个函数会将用户名的第二个字符替换为 
- ID_CARD实例的- Function对象:- s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")- 这个函数会将身份证号码的中间部分替换为 ****
 
- 这个函数会将身份证号码的中间部分替换为 
- 其他实例类似。
这些 Function 对象都实现了 apply 方法,用于对输入的字符串进行处理。
调用 desensitizer.apply(value)
当你调用 strategy.desensitizer().apply(value) 时,实际上执行了以下步骤:
- strategy.desensitizer()返回- Function<String, String>类型的- desensitizer对象。
- desensitizer.apply(value)调用- Function对象的- apply方法,对输入的- value进行处理并返回处理后的结果。
总结
- 在序列化过程中,调用 strategy.desensitizer().apply(value)对字符串进行脱敏处理。
- 将处理后的字符串写入 JsonGenerator以生成最终的 JSON 输出。
3. 实现自定义序列化器
创建一个自定义的 JsonSerializer 类,用于处理带有 @Sensitive 注解的字段。
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {private SensitiveStrategy strategy;@Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {gen.writeString(strategy.desensitizer().apply(value));}/*** 获取属性上的注解属性*/@Overridepublic JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {Sensitive annotation = property.getAnnotation(Sensitive.class);System.out.println(annotation);if (Objects.nonNull(annotation)&& Objects.equals(String.class, property.getType().getRawClass())) {this.strategy = annotation.strategy();return this;}return prov.findValueSerializer(property.getType(), property);}
}这段代码是一个自定义的 Jackson 序列化器,它实现了 JsonSerializer<String> 和 ContextualSerializer 接口,用于在序列化过程中对特定类型的字段进行脱敏处理。让我们逐行解释代码的含义和作用。
- SensitiveJsonSerializer继承了- JsonSerializer<String>,表示这是一个自定义的序列化器,专门用于序列化- String类型的字段。
- 它还实现了 ContextualSerializer接口,这使得序列化器能够访问字段的上下文(如注解)并根据上下文进行调整。
- strategy是一个- SensitiveStrategy类型的字段,用于存储从注解中提取的脱敏策略。
 serialize 方法
 
- serialize方法用于序列化对象。
- value是需要序列化的字段值。
- gen是- JsonGenerator,用于将序列化的内容写入输出。
- serializers是- SerializerProvider,提供了其他序列化器。
- 在方法内部,使用脱敏策略 (strategy.desensitizer()) 对字段值 (value) 进行脱敏处理,并将处理后的值写入输出 (gen.writeString)。
createContextual 方法
 
- createContextual方法用于在序列化过程中根据上下文(即字段的注解)配置序列化器。
- prov是- SerializerProvider,提供了其他序列化器。
- property是- BeanProperty,表示当前正在序列化的字段。
方法内部,首先获取字段上的 Sensitive 注解(如果有) 
Sensitive annotation = property.getAnnotation(Sensitive.class);
然后,检查注解是否存在且字段类型是否为 String。
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {this.strategy = annotation.strategy();return this;
}
-  - 如果注解存在并且字段类型是 String,则从注解中提取脱敏策略 (annotation.strategy()) 并赋值给this.strategy。
- 返回当前的序列化器 (return this;)。
 
- 如果注解存在并且字段类型是 
- 如果没有注解或字段类型不是 String,则使用默认的序列化器 (prov.findValueSerializer(property.getType(), property))。
4. 使用自定义注解
在你的类中使用 @Sensitive 注解来标记需要脱敏处理的字段。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {/*** 真实姓名*/@Sensitive(strategy = SensitiveStrategy.USERNAME)private String realName;/*** 地址*/@Sensitive(strategy = SensitiveStrategy.ADDRESS)private String address;/*** 电话号码*/@Sensitive(strategy = SensitiveStrategy.PHONE)private String phoneNumber;/*** 身份证号码*/@Sensitive(strategy = SensitiveStrategy.ID_CARD)private String idCard;}5.测试
@RestController
public class TestController {@GetMapping("/test")public Person test(){Person user = new Person();user.setRealName("xxxx");user.setPhoneNumber(" 15242554546");user.setAddress("天津市河西区....");user.setIdCard("111111111111111");return user;}
}