;
break;
// 自定义脱敏
case CUSTOM:
jsonGenerator.writeString(CharSequenceUtil.hide(value, startIndex, endIndex));
break;
default:
break;
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
if (beanProperty != null) {
// 判断数据类型是否为String类型
if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
// 获取定义的注解
Desensitize desensitize = beanProperty.getAnnotation(Desensitize.class);
// 为null
if (desensitize == null) {
desensitize = beanProperty.getContextAnnotation(Desensitize.class);
}
// 不为null
if (desensitize != null) {
// 创建定义的序列化类的实例并且返回,入参为注解定义的type,开始位置,结束位置。
return new DesensitizeSerializer(desensitize.type(), desensitize.startIndex(),
desensitize.endIndex());
}
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}
该类实现了com.fasterxml.jackson.databind.ser.ContextualSerializer
接口并重写了createContextual
方法,
该方法会解析字段的类型是不是String以及字段上有没有之前自定义的注解Desensitize
,如果有的话,
就返回自定义的序列化类的实例,创建实例时用到了注解中的参数。
该类还继承了com.fasterxml.jackson.databind.JsonSerializer
类并重写了serialize
方法,
该方法会判断脱敏的类型,执行具体的脱敏逻辑,这里用到了之前提到的脱敏工具类。
最后,新建接口进行验证:
@Getter
@Setter
public class CarInfoVO {
@Desensitize(type = DesensitizeType.LICENSE_NUMBER)
private String licenseNumber;
@Desensitize(type = DesensitizeType.MOBILE_PHONE)
private String ownerMobile;
@Desensitize(type = DesensitizeType.ID_CARD)
private String ownerIdCard;
@Desensitize(type = DesensitizeType.BANK_CARD)
private String ownerBankCardNo;
@Desensitize(type = DesensitizeType.CUSTOM, startIndex = 0, endIndex = 1)
private String ownerName;
}
@GetMapping("/car/info")
@ResponseBody
public WebResult<CarInfoVO> queryCarInfo() {
CarInfoVO carInfoVO = new CarInfoVO();
carInfoVO.setLicenseNumber("沪B08U28");
carInfoVO.setOwnerMobile("18216556791");
carInfoVO.setOwnerIdCard("410328200001010007");
carInfoVO.setOwnerBankCardNo("6214856213978533");
carInfoVO.setOwnerName("叶子农");
return WebResult.success(carInfoVO);
}
输出结果:
4. 注意事项
4.1 无参构造函数不要删
上文中新建的自定义序列化类的无参构造函数表面上看没有任何调用,在IDEA中看着是下图这样的:
但千万不要手贱删除(我就手贱了,哈哈),否则会抛运行时异常:
4.2 自定义脱敏注解不生效
如果上文中提到的每一步都正常操作了,但自定义脱敏注解还是不生效:
那很可能是Spring Boot默认的消息转换器被替换成fastjson了,因为Spring Boot默认是使用jackson进行序列化的,上面的方案也是
基于jackson的,但如果项目中明确指定了使用fastjson进行序列化,那上面的自定义脱敏注解就不会生效:
@Bean
public HttpMessageConverters httpMessageConverters() {
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, SerializerFeature.BrowserCompatible);
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastJsonHttpMessageConverter);
}
此时的解决方案是新建过滤器类,实现com.alibaba.fastjson.serializer.ValueFilter
接口并重写process方法:
public class Desensitizeva lueFilter implements ValueFilter {
@Override
public Object process(Object object, String name, Object value) {
try {
Field field =