前言
有些時候,我們可能對輸出的某些欄位要做特殊的處理在輸出到前端,比如:身份證號,電話等資訊,在前端展示的時候我們需要進行脫敏處理,這時候透過自定義註解就非常的有用了。在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; }
四、在前端展示結果如下:
敏感資料得到了脫敏處理。