自定义注解进行数据脱敏
前言
有些时候,我们可能对输出的某些字段要做特殊的处理在输出到前端,比如:身份证号,电话等信息,在前端展示的时候我们需要进行脱敏处理,这时候通过自定义注解就非常的有用了。在Jackson中要自定义注解,我们可以通过@JacksonAnnotationsInside注解来实现,如下示例:
一、自定义注解
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotationsInside @JsonSerialize(using = SensitiveSerializer.class) public @interface Sensitive { //加密开始位置 int start()default 0 ; //加密结束位置 int end() default 0 ; //加密掩码 String mask() default "*" ; }
二、自定义序列化处理器SensitiveSerializer
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import org.springframework.util.StringUtils; import java.io.IOException; import java.util.Collections; /** * @author songwp * @date 2024-11-15 * @desc 自定义序列化器,用于对敏感字段进行脱敏处理 */ public class SensitiveSerializer extends JsonSerializer<String> implements ContextualSerializer { private Sensitive sensitive; @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { String val = value; if (sensitive != null && StringUtils.hasLength(val)) { String m = sensitive.mask(); int start = sensitive.start(); int end = sensitive.end(); int totalLength = value.length(); if (totalLength <= 2) { val = totalLength == 1 ? value + m : value.substring(0, 1) + m; } else if (totalLength <= 6) { val = value.substring(0, 1) + String.join("", Collections.nCopies(totalLength - 2, m)) + value.substring(totalLength - 1); } else { int prefixLength = Math.min(start, totalLength - 1); int suffixLength = Math.min(end, totalLength - 1); if (prefixLength > totalLength) { prefixLength = totalLength / 2; } if (suffixLength > totalLength) { suffixLength = totalLength / 2; } int maskLength = Math.max(0, totalLength - (prefixLength + suffixLength)); if (maskLength == 0) { prefixLength -= 2; suffixLength -= 2; maskLength = Math.max(2, totalLength - (prefixLength + suffixLength)); } prefixLength = Math.min(prefixLength, totalLength - 1); suffixLength = Math.min(suffixLength, totalLength - 1); maskLength = totalLength - prefixLength - suffixLength; val = value.substring(0, prefixLength) + String.join("", Collections.nCopies(maskLength, m)) + value.substring(totalLength - suffixLength); } } gen.writeString(val); } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { sensitive = property.getAnnotation(Sensitive.class); return this; } }
三、在输出的Java Bean中使用上面的注解
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.songwp.config.Sensitive; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @author songwp * @version 1.0 * @date 2024-11-15 * @description: user domain */ @Data @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { @JsonSerialize(using = ToStringSerializer.class) private Long id; @Sensitive(start = 2, end = 4) private String name; @Sensitive(start = 6, end = 4) private String idCard; @Sensitive(start = 4, end = 3) private String phone; }
四、在前端展示结果如下:
敏感数据得到了脱敏处理。
古今成大事者,不唯有超世之才,必有坚韧不拔之志!