需求:
1、通過註解的方式指定字段在序列化時進行脫敏或者加密;
2、通過註解的方式指定字段在序列化時忽略掉;
3、某些情況下需要處理的類不是我們可以修改的,但是也要實現上述兩項需求;
實現如下:
工具類SensitiveJsonUtil:
package com.example.jackson;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SensitiveJsonUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
// 反序列化時忽略不存在的字段
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 註冊處理敏感字段的擴展模塊
objectMapper.registerModule(new SensitiveFieldProcessModule());
// 通過mixIn功能來按字段名忽略一些字段
objectMapper.addMixIn(Object.class, IgnoreSensitiveFieldsMixin.class);
}
@JsonIgnoreProperties(
value = {
"password",
"secret",
"token"
}
)
static class IgnoreSensitiveFieldsMixin {
}
public static String toJsonString(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException(String.format("toJsonString error, %s", e.getMessage()), e);
}
}
}
擴展模塊類SensitiveFieldProcessModule(這裏僅爲demo,所以一些相關的類直接以嵌套類放在了一起)
package com.example.jackson;
import com.fasterxml.jackson.annotation.JacksonAnnotation;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.util.VersionUtil;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.type.MapType;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
public class SensitiveFieldProcessModule extends Module {
private static final String MODULE_NAME = "jackson-sensitive-field-process-module";
private Version version = VersionUtil.parseVersion("0.0.1", "com.example", MODULE_NAME);
@Override
public String getModuleName() {
return MODULE_NAME;
}
@Override
public Version version() {
return version;
}
@Override
public void setupModule(SetupContext setupContext) {
setupContext.addBeanSerializerModifier(new SensitiveFieldModifier());
}
public static class SensitiveFieldModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
List<BeanPropertyWriter> newWriters = new ArrayList<>();
for (BeanPropertyWriter writer : beanProperties) {
if (writer.getAnnotation(Sensitive.class) != null && writer.getType().isTypeOrSubTypeOf(String.class)) {
// 如果帶有 @Sensitive 註解,並且是字符串,則使用自定義處理
JsonSerializer<Object> serializer = new SensitiveJsonSerializer(writer.getSerializer());
writer.assignSerializer(serializer);
}
newWriters.add(writer);
}
return newWriters;
// super.changeProperties(config, beanDesc, beanProperties);
}
@Override
public JsonSerializer<?> modifyMapSerializer(SerializationConfig config, MapType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
return super.modifyMapSerializer(config, valueType, beanDesc, serializer);
}
}
@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Sensitive {
}
public static class SensitiveJsonSerializer extends JsonSerializer<Object> {
private final JsonSerializer<Object> serializer;
public SensitiveJsonSerializer(JsonSerializer<Object> serializer) {
this.serializer = serializer;
}
@Override
public void serialize(Object object, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
if (object != null && object instanceof String) {
String str = (String) object;
if (StringUtils.isNotBlank(str)) {
object = processSensitiveField(str);
}
}
if (this.serializer == null) {
serializerProvider.defaultSerializeValue(object, jsonGenerator);
} else {
this.serializer.serialize(object, jsonGenerator, serializerProvider);
}
}
private static String processSensitiveField(String input) {
if (StringUtils.isBlank(input)) {
return input;
}
input = StringUtils.trim(input);
int strLen = input.length();
if (strLen <= 1) {
return "*";
} else if (strLen == 2) {
return String.format("%s*", input.charAt(0));
} else if (strLen == 3) {
return String.format("%s*%s", input.charAt(0), input.charAt(strLen - 1));
} else {
int left = strLen / 4;
int right = strLen / 3;
return String.format("%s%s%s",
StringUtils.left(input, left),
StringUtils.repeat('*', (strLen - left - right)),
StringUtils.right(input, right));
}
}
}
}
使用示例:
package com.example;
import com.example.jackson.SensitiveFieldProcessModule;
import com.example.jackson.SensitiveJsonUtil;
import java.util.HashMap;
import java.util.Map;
public class App {
public static void main(String[] args) {
Person person = new Person();
person.setUsername("張一二");
person.setIdNumber("1000000000112245");
person.setPassword("123456(password)");
Map<String, String> otherInfo = new HashMap<>();
otherInfo.put("nation", "CN");
otherInfo.put("secret", "(secret)");
person.setOtherInfo(otherInfo);
System.out.println(SensitiveJsonUtil.toJsonString(person));
// 輸出:{"username":"張一二","idNumber":"1000*******12245","otherInfo":{"nation":"CN"}}
}
static class Person {
private String username;
@SensitiveFieldProcessModule.Sensitive
private String idNumber;
private String password;
private Map<String, String> otherInfo;
// ... 省略getter/setter
}
}
參考文檔: