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;
}
}