太強(qiáng)了,一個(gè)注解搞定接口返回?cái)?shù)據(jù)脫敏
往期熱門文章:
1、isEmpty和isBlank的區(qū)別,至少一半人答不上來... 2、Lombok同時(shí)使?@Data和@Builder 的坑 3、IntelliJ IDEA快捷鍵大全 + 動(dòng)圖演示,建議收藏! 4、如何防止你的 jar 被反編譯? 5、大公司為什么禁止SpringBoot項(xiàng)目使用Tomcat? juejin.cn/post/7110110794188062727
思路
代碼
1. 自定義數(shù)據(jù)注解,并可以配置數(shù)據(jù)脫敏策略
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataMasking {
DataMaskingFunc maskFunc() default DataMaskingFunc.NO_MASK;
}
2. 自定義Serializer,參考jackson的StringSerializer,下面的示例只針對(duì)String類型進(jìn)行脫敏
public interface DataMaskingOperation {
String MASK_CHAR = "*";
String mask(String content, String maskChar);
}
public enum DataMaskingFunc {
/**
* 脫敏轉(zhuǎn)換器
*/
NO_MASK((str, maskChar) -> {
return str;
}),
ALL_MASK((str, maskChar) -> {
if (StringUtils.hasLength(str)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
sb.append(StringUtils.hasLength(maskChar) ? maskChar : DataMaskingOperation.MASK_CHAR);
}
return sb.toString();
} else {
return str;
}
});
private final DataMaskingOperation operation;
private DataMaskingFunc(DataMaskingOperation operation) {
this.operation = operation;
}
public DataMaskingOperation operation() {
return this.operation;
}
}
public final class DataMaskingSerializer extends StdScalarSerializer<Object> {
private final DataMaskingOperation operation;
public DataMaskingSerializer() {
super(String.class, false);
this.operation = null;
}
public DataMaskingSerializer(DataMaskingOperation operation) {
super(String.class, false);
this.operation = operation;
}
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 {
if (Objects.isNull(operation)) {
String content = DataMaskingFunc.ALL_MASK.operation().mask((String) value, null);
gen.writeString(content);
} else {
String content = operation.mask((String) value, null);
gen.writeString(content);
}
}
public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
this.serialize(value, gen, provider);
}
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);
}
}
3. 自定義AnnotationIntrospector,適配我們自定義注解返回相應(yīng)的Serializer
@Slf4j
public class DataMaskingAnnotationIntrospector extends NopAnnotationIntrospector {
@Override
public Object findSerializer(Annotated am) {
DataMasking annotation = am.getAnnotation(DataMasking.class);
if (annotation != null) {
return new DataMaskingSerializer(annotation.maskFunc().operation());
}
return null;
}
}
4. 覆蓋ObjectMapper
@Configuration(
proxyBeanMethods = false
)
public class DataMaskConfiguration {
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({Jackson2ObjectMapperBuilder.class})
static class JacksonObjectMapperConfiguration {
JacksonObjectMapperConfiguration() {
}
@Bean
@Primary
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
AnnotationIntrospector ai = objectMapper.getSerializationConfig().getAnnotationIntrospector();
AnnotationIntrospector newAi = AnnotationIntrospectorPair.pair(ai, new DataMaskingAnnotationIntrospector());
objectMapper.setAnnotationIntrospector(newAi);
return objectMapper;
}
}
}
5. 返回對(duì)象加上注解
public class User implements Serializable {
/**
* 主鍵ID
*/
private Long id;
/**
* 姓名
*/
@DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
private String name;
/**
* 年齡
*/
private Integer age;
/**
* 郵箱
*/
@DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
private String email;
}
往期熱門文章:
1、計(jì)算機(jī)專業(yè)會(huì)不會(huì)成為下一個(gè)土木? 2、xxl-job驚艷的設(shè)計(jì),怎能叫人不愛 3、ArrayList#subList這四個(gè)坑,一不小心就中招 4、面試官:大量請(qǐng)求 Redis 不存在的數(shù)據(jù),從而影響數(shù)據(jù)庫,該如何解決? 5、MySQL 暴跌! 6、超越 Xshell!號(hào)稱下一代 Terminal 終端神器,用完愛不釋手! 7、IDEA 官宣全新默認(rèn) UI,太震撼了?。?/span> 8、讓你直呼「臥槽」的 GitHub 項(xiàng)目! 9、Kafka又笨又重,為啥不選Redis? 10、50多個(gè)高頻免費(fèi) API 接口分享
評(píng)論
圖片
表情
