前言
在項目開發(fā)過程中,有一些特殊場景需要對敏感數(shù)據(jù)進行脫敏返回展示烛占,比如用戶的手機號胎挎、證件號、真實姓名忆家、郵箱等犹菇,返回如:176****9331 之類的,怎么實現(xiàn)呢芽卿?
使用@JsonSerialize對數(shù)據(jù)進行格式化
首先项栏,來看個簡單的例子,數(shù)據(jù)庫有個20位的Long
類型的ID蹬竖,返回到前端之后沼沈,因為前端類型問題,會丟失精度币厕,這個時候列另,我們就需要將Long
類型的數(shù)據(jù)格式化為String
類型進行返回,代碼如下:
@Data
public class Demo {
/** 數(shù)據(jù)ID **/
@JsonSerialize(using = StringSerializer.class)
private Long id;
}
上面的代碼旦装,只需要在字段添加 @JsonSerialize(using = StringSerializer.class)
注解就可以完成Long
返回 String
的格式化效果页衙。接下來,我們看看 StringSerializer
做了什么事情阴绢,源碼:
public final class StringSerializer extends StdScalarSerializer<Object> {
private static final long serialVersionUID = 1L;
public StringSerializer() {
super(String.class, false);
}
public boolean isEmpty(SerializerProvider prov, Object value) {
String str = (String)value;
return str.isEmpty();
}
// 主要關(guān)注這個方法店乐,這個是序列化方法
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
// 將 object 直接轉(zhuǎn)換成 String 返回
gen.writeString((String)value);
}
public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
gen.writeString((String)value);
}
public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
return this.createSchemaNode("string", true);
}
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
this.visitStringFormat(visitor, typeHint);
}
}
其實,只需要關(guān)注 serialize
這個方法呻袭,其他方法都是對其進行的增強眨八,我們先看看StringSerializer
的UML 關(guān)系圖:
這個時候我們就會發(fā)現(xiàn)serialize()
其實是JsonSerializer
的抽象方法,來看看 JsonSerializer
源碼:
public abstract class JsonSerializer<T> implements JsonFormatVisitable {
public JsonSerializer() {
}
public JsonSerializer<T> unwrappingSerializer(NameTransformer unwrapper) {
return this;
}
public JsonSerializer<T> replaceDelegatee(JsonSerializer<?> delegatee) {
throw new UnsupportedOperationException();
}
public JsonSerializer<?> withFilterId(Object filterId) {
return this;
}
// 序列化抽象方法
public abstract void serialize(T var1, JsonGenerator var2, SerializerProvider var3) throws IOException;
public void serializeWithType(T value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
Class<?> clz = this.handledType();
if (clz == null) {
clz = value.getClass();
}
serializers.reportBadDefinition(clz, String.format("Type id handling not implemented for type %s (by serializer of type %s)", clz.getName(), this.getClass().getName()));
}
public Class<T> handledType() {
return null;
}
/** @deprecated */
@Deprecated
public boolean isEmpty(T value) {
return this.isEmpty((SerializerProvider)null, value);
}
public boolean isEmpty(SerializerProvider provider, T value) {
return value == null;
}
public boolean usesObjectId() {
return false;
}
public boolean isUnwrappingSerializer() {
return false;
}
public JsonSerializer<?> getDelegatee() {
return null;
}
public Iterator<PropertyWriter> properties() {
return ClassUtil.emptyIterator();
}
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType type) throws JsonMappingException {
visitor.expectAnyFormat(type);
}
public abstract static class None extends JsonSerializer<Object> {
public None() {
}
}
}
分析到這里左电,聰明的小伙伴是不是精神一震廉侧,我了個擦页响,那我是不是可以自己繼承這個超級類,實現(xiàn)自己的格式化邏輯(比如:脫敏~6翁堋H虿稀!)连舍!沒錯了没陡,就是這樣,下面我們繼續(xù)看索赏,怎么去實現(xiàn)數(shù)據(jù)脫敏盼玄。
對手機號進行脫敏處理
開始之前,推進一款開源工具框架参滴,只要你能想到的强岸,這個工具基本上都支持锻弓,而且還是國產(chǎn)砾赔,那就是: hutool。
首先青灼,引入依賴(spring boot 自行引入):
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
繼承JsonSerializer
并實現(xiàn) serialize
抽象方法:
public class PhoneDesensitizationSerializer extends JsonSerializer<String> {
@Override
public void serialize(String phone, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String phoneDesensitization = DesensitizedUtil.mobilePhone(phone);
jsonGenerator.writeString(phoneDesensitization);
}
}
最后暴心,使用PhoneDesensitizationSerializer
對說幾號進行脫敏:
public class UserInfo {
// 省略其他字段
@JsonSerialize(using = PhoneDesensitizationSerializer.class)
private String phoneNumber;
// 省略其他字段
}
完活,其他的脫敏思路都是一樣的杂拨,無非就是copy 改一下tool 方法专普。
總結(jié)
在遇到一個問題時,一定要多想弹沽,因為我們能遇到檀夹,別人一定也會遇到,總會找到快速解決問題的辦法策橘。