通透!一口气搞懂注解到底怎么用
日志脱敏场景简介
在日志里我们的日志一般打印的是 model 的 Json string,比如有以下 model 类
public class Request {/*** 用户姓名*/private String name;/*** 身份证 */private String idcard;/*** 手机号*/private String phone;/*** 图片的 base64*/private String imgBase64;
}
有以下类实例
Request request = new Request();
request.setName("爱新觉罗");
request.setIdcard("450111112222");
request.setPhone("18611111767");
request.setImgBase64("xxx");
我们一般使用 fastJson 来打印此 Request 的 json string:
log.info(JSON.toJSONString(request));
这样就能把 Request 的所有属性值给打印出来,日志如下:
{"idcard":"450111112222","imgBase64":"xxx","name":"张三","phone":"17120227942"}
这里的日志有两个问题
- 安全性: name,phone, idcard 这些个人信息极其敏感,不应以明文的形式打印出来,我们希望这些敏感信息是以脱敏的形式输出的
- 字段冗余:imgBase64 是图片的 base64,是一串非常长的字符串,在生产上,图片 base64数据对排查问题帮助不大,反而会增大存储成本,而且这个字段是身份证正反面的
base64,也属于敏感信息,所以这个字段在日志中需要把它去掉。我们希望经过脱敏和瘦身(移除 imgBase64 字段)后的日志如下:
{"idcard":"450******222","name":"爱**罗","phone":"186****1767","imgBase64":""}
可以看到各个字段最后都脱敏了,不过需要注意的这几个字段的脱敏规则是不一样的
- 身份证(idcard),保留前三位,后三位,其余号码
- 姓名(name)保留前后两位,其余打码
- 电话号码(phone)保持前三位,后四位,其余打码
- 图片的 base64(imgBase64)直接展示空字符串
该怎么实现呢,首先我们需要知道一个知识点,即 JSON.toJSONString 方法指定了一个参数 ValueFilter,可以定制要转化的属性。我们可以利用此 Filter 让最终的 JSON string 不展示或展示脱敏后的 value。大概逻辑如下
public class Util {public static String toJSONString(Object object) {try {return JSON.toJSONString(object, getValueFilter());} catch (Exception e) {return ToStringBuilder.reflectionToString(object);}}private static ValueFilter getValueFilter() {return (obj, key, value) -> {// obj-对象 key-字段名 value-字段值return 格式化后的value};
}
如上图示,我们只要在 getValueFilter 方法中对 value 作相关的脱敏操作,即可在最终的日志中展示脱敏后的日志。现在问题来了,该怎么处理字段的脱敏问题,我们知道有些字段需要脱敏,有些字段不需要脱敏,所以有人可能会根据 key 的名称来判断是否脱敏,代码如下:
private static ValueFilter getValueFilter() {return (obj, key, value) -> {// obj-对象 key-字段名 value-字段值if (Objects.equal(key, "phone")) {return 脱敏后的phone}if (Objects.equal(key, "idcard")) {return 脱敏后的idcard}if (Objects.equal(key, "name")) {return 脱敏后的name}// 其余不需要脱敏的按原值返回return value};
}
这样看起来确实实现了需求,但仅仅实现了需求就够了吗,这样的实现有个比较严重的问题:
脱敏规则与具体的属性名紧藕合,需要在 valueFilter 里写大量的 if else 判断逻辑,可扩展性不高,通用性不强,举个简单的例子,由于业务原因,在我们的工程中电话有些字段名叫 phone, 有些叫 tel,有些叫 telephone,它们的脱敏规则是一样的,但你不得不在上面的方法中写出如下丑陋的代码。
private static ValueFilter getValueFilter() {return (obj, key, value) -> {// obj-对象 key-字段名 value-字段值if (Objects.equal(key, "phone") || Objects.equal(key, "tel") || Objects.equal(key, "telephone") || ) {return 脱敏后的phone}// 其余不需要脱敏的按原值返回return value};
}
那么能否用一种通用的,可扩展性好的方法来解决呢,相信你看到文章的标题已经心中有数了,没错,就是用的注解,接下来我们来看看什么是注解以及如何自定义注解
注解的定义与实现原理
注解(Annotation)又称 Java 标注,是 JDK 5.0 引入的一种注释机制,如果说代码的注释是
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
