- 在开发中有时候需要打印一些对象的属性值, 但是其中含有一些敏感字段, 不能打印明文而是需要脱敏打印,写了一个工具, 可以将对象转换成JSON字符串,并且可以指定要脱敏的字段名称
java
package com.visy.utils;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.Arrays;
public class LogUtil {
/**
* 安全的JSON字符串转换(可脱敏)
* @param obj 待序列化对象
* @param fieldNames 待脱敏的字段名称
* @return JSON字符串
*/
public static String toJsonSafety(Object obj, String... fieldNames){
if(fieldNames==null || fieldNames.length==0){
return toJson(obj);
}
JSONObject jsonObject = (JSONObject) JSON.toJSON( obj);
for(String fieldName : fieldNames){
Object value = jsonObject.get(fieldName);
if(ObjectUtil.isNotNull(value)){
jsonObject.put(fieldName, mask(value.toString()));
}
}
return toJson(jsonObject);
}
private static String toJson(Object obj){
return JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue);
}
/**
* 字符串脱敏方法(自动计算并隐藏部分字符)
* @param value 待脱敏的字符串
* @return 脱敏后的字符串
*/
public static String mask(String value){
if(value == null || value.isEmpty()){
return value;
}
int length = value.length(), halfLength = length / 2;
if(halfLength <= 1){ // 1 ~ 3 个字符, 全部脱敏
return createRepeatedString('*', length);
}else{ // >= 4 个字符, 前后各保留1/4 个字符
int beforeLength = halfLength / 2;
return mask(value, '*', beforeLength, halfLength-beforeLength);
}
}
/**
* 数据脱敏方法
* @param value 待脱敏的原始数据
* @param ch 脱敏占位字符
* @param beforeLength 前保留字符数
* @param afterLength 后保留字符数
* @return 脱敏后的数据
*/
public static String mask(String value, char ch, int beforeLength, int afterLength) {
// 空值安全检查
if (value == null || value.isEmpty()) {
return value;
}
final int length = value.length(), leastLength = beforeLength + afterLength;
// 长度小于等于leastLength位,全部脱敏
if (length <= leastLength) {
if(length <= afterLength){
// 剩余长度小于等于afterLength,全部脱敏
return createRepeatedString(ch, length);
}
// 剩余长度大于afterLength,只脱敏前length-afterLength位
return createRepeatedString(ch, length-afterLength) + value.substring(length-afterLength);
}
return value.substring(0, beforeLength) + createRepeatedString(ch, length-leastLength) + value.substring(length-afterLength);
}
/**
* 创建重复字符的字符串
* @param ch 要重复的字符
* @param count 重复次数
* @return 重复字符组成的字符串
*/
private static String createRepeatedString(char ch, int count) {
if (count <= 0) {
return "";
}
char[] chars = new char[count];
Arrays.fill(chars, ch);
return new String(chars);
}
}
- 使用
java
public class LogUtilTest {
public static void main(String[] args) {
User user = new User();
user.setName("张三");
user.setAge(22);
user.setIdCard("320381198812252138");
//打印结果:{"idCard":"3203*********52138","name":"张三","age":22}
System.out.println(LogUtil.toJsonSafety(user, "idCard"));
}
@Data
static class User{
private String name;
private Integer age;
private String idCard;
}
}