前言
在项目开发过程中,有一些特殊场景需要对敏感数据进行脱敏返回展示,比如用户的手机号、证件号、真实姓名、邮箱等,返回如:176****9331 之类的,怎么实现呢?
使用@JsonSerialize对数据进行格式化
首先,来看个简单的例子,数据库有个20位的Long
类型的ID,返回到前端之后,因为前端类型问题,会丢失精度,这个时候,我们就需要将Long
类型的数据格式化为String
类型进行返回,代码如下:
@Data
public class Demo {
/** 数据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();
}
// 主要关注这个方法,这个是序列化方法
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
// 将 object 直接转换成 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);
}
}
其实,只需要关注 serialize
这个方法,其他方法都是对其进行的增强,我们先看看StringSerializer
的UML 关系图:
这个时候我们就会发现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() {
}
}
}
分析到这里,聪明的小伙伴是不是精神一震,我了个擦,那我是不是可以自己继承这个超级类,实现自己的格式化逻辑(比如:脱敏~!!!)!没错了,就是这样,下面我们继续看,怎么去实现数据脱敏。
对手机号进行脱敏处理
开始之前,推进一款开源工具框架,只要你能想到的,这个工具基本上都支持,而且还是国产,那就是: hutool。
首先,引入依赖(spring boot 自行引入):
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
继承JsonSerializer
并实现 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 方法。
总结
在遇到一个问题时,一定要多想,因为我们能遇到,别人一定也会遇到,总会找到快速解决问题的办法。
网友评论