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 的依赖:
java
<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>
序列化示例:
java
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
}
反序列化示例:
java
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
注解,用于标记需要脱敏处理的字段。
java
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
注解的字段。下面详细解释代码的每个部分:
JsonSerializer<String>
SensitiveJsonSerializer
类继承自 Jackson 的 JsonSerializer<String>
。这是一个泛型类,用于自定义如何将 String
类型的对象序列化为 JSON。
serialize
方法
serialize
方法是 JsonSerializer
类的抽象方法,必须实现。它的作用是定义如何将 Java 对象(在这个例子中是 String
)转换为 JSON 字符串。
2. 定义脱敏策略
创建一个枚举 SensitiveStrategy
,定义不同的脱敏策略。
java
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
,用于将一个输入值转换成一个输出值:
java
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
T
是输入类型R
是输出类型apply
方法接受一个T
类型的参数,并返回一个R
类型的结果
SensitiveStrategy 枚举
在 SensitiveStrategy
枚举中,每个枚举实例都被赋予了一个 Function<String, String>
类型的对象。这个对象用于定义字符串脱敏的具体实现。
java
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
注解的字段。
java
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private SensitiveStrategy strategy;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(strategy.desensitizer().apply(value));
}
/**
* 获取属性上的注解属性
*/
@Override
public 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
注解(如果有)
java
Sensitive annotation = property.getAnnotation(Sensitive.class);
然后,检查注解是否存在且字段类型是否为 String
。
java
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
注解来标记需要脱敏处理的字段。
java
@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.测试
java
@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;
}
}