mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-29 17:28:42 +08:00 
			
		
		
		
	feat: 支持 vo 返回的脱敏
This commit is contained in:
		| @@ -4,9 +4,9 @@ | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <parent> | ||||
|         <groupId>cn.iocoder.boot</groupId> | ||||
|         <artifactId>yudao-framework</artifactId> | ||||
|         <version>1.6.6-snapshot</version> | ||||
|         <groupId>cn.iocoder.boot</groupId> | ||||
|         <version>${revision}</version> | ||||
|     </parent> | ||||
|  | ||||
|     <artifactId>yudao-spring-boot-starter-biz-desensitize</artifactId> | ||||
| @@ -22,5 +22,22 @@ | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|             <artifactId>yudao-common</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- jackson --> | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.core</groupId> | ||||
|             <artifactId>jackson-annotations</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.core</groupId> | ||||
|             <artifactId>jackson-databind</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Test 测试相关 --> | ||||
|         <dependency> | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|             <artifactId>yudao-spring-boot-starter-test</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| </project> | ||||
| @@ -1,7 +1,9 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.enums.DesensitizationStrategyEnum; | ||||
| import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandler; | ||||
| import cn.iocoder.yudao.framework.desensitize.serializer.StringDesensitizeSerializer; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
| import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| @@ -11,40 +13,18 @@ import java.lang.annotation.Target; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Desensitize 注解配置会覆盖 DesensitizationStrategyEnum 配置 | ||||
|  * Desensitize 顶级脱敏注解 | ||||
|  */ | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Documented | ||||
| @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @JsonSerialize(using = StringDesensitizeSerializer.class) | ||||
| public @interface Desensitize { | ||||
|  | ||||
|     /** | ||||
|      * 脱敏策略 | ||||
|      */ | ||||
|     DesensitizationStrategyEnum strategy(); | ||||
|  | ||||
|     /** | ||||
|      * 脱敏替换字符 | ||||
|      */ | ||||
|     String replacer(); | ||||
|  | ||||
|     /** | ||||
|      * 正则表达式 | ||||
|      */ | ||||
|     String regex(); | ||||
|  | ||||
|     /** | ||||
|      * 前缀保留长度 | ||||
|      */ | ||||
|     int preKeep(); | ||||
|  | ||||
|     /** | ||||
|      * 后缀保留长度 | ||||
|      */ | ||||
|     int suffixKeep(); | ||||
|  | ||||
|     /** | ||||
|      * 脱敏处理器 | ||||
|      */ | ||||
|     Class<? extends DesensitizationHandler> handler(); | ||||
|     Class<? extends DesensitizationHandler> desensitizationHandler(); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.handler.RegexDesensitizationHandler; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 正则脱敏注解 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @Desensitize(desensitizationHandler = RegexDesensitizationHandler.class) | ||||
| public @interface RegexDesensitize { | ||||
|     /** | ||||
|      * 匹配的正则表达式(默认匹配所有) | ||||
|      */ | ||||
|     String regex() default "^[\\s\\S]*$"; | ||||
|  | ||||
|     /** | ||||
|      * 替换规则,会将匹配到的字符串全部替换成 replacer | ||||
|      * 例如:regex=123; replacer=****** | ||||
|      * 原始字符串 123456789 | ||||
|      * 脱敏后字符串 ******456789 | ||||
|      */ | ||||
|     String replacer() default "******"; | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.handler.SliderDesensitizationHandler; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 滑动脱敏注解 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @Desensitize(desensitizationHandler = SliderDesensitizationHandler.class) | ||||
| public @interface SliderDesensitize { | ||||
|  | ||||
|     /** | ||||
|      * 后缀保留长度 | ||||
|      */ | ||||
|     int suffixKeep() default 0; | ||||
|  | ||||
|     /** | ||||
|      * 替换规则,会将前缀后缀保留后,全部替换成 replacer | ||||
|      * 例如:prefixKeep = 1; suffixKeep = 2; replacer = "*"; | ||||
|      * 原始字符串  123456 | ||||
|      * 脱敏后     1***56 | ||||
|      */ | ||||
|     String replacer() default "*"; | ||||
|  | ||||
|     /** | ||||
|      * 前缀保留长度 | ||||
|      */ | ||||
|     int prefixKeep() default 0; | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 银行卡号 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 6, suffixKeep = 2, replacer = "*") // 银行卡号;比如:9988002866797031脱敏之后为998800********31 | ||||
| public @interface BankCardDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 车牌号 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 3, suffixKeep = 1, replacer = "*") // 车牌号;比如:粤A66666脱敏之后为粤A6***6 | ||||
| public @interface CarLicenseDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 中文名 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 1, suffixKeep = 0, replacer = "*") // 中文名;比如:刘子豪脱敏之后为刘** | ||||
| public @interface ChineseNameDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.RegexDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 邮箱 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @RegexDesensitize(regex = "(^.)[^@]*(@.*$)", replacer ="$1****$2")  // 邮箱;比如:example@gmail.com脱敏之后为e****@gmail.com | ||||
| public @interface EmailDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 固定电话 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 4, suffixKeep = 2, replacer = "*") // 固定电话;比如:01086551122脱敏之后为0108*****22 | ||||
| public @interface FixedPhoneDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 身份证 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 6, suffixKeep = 2, replacer = "*") // 身份证号码;比如:530321199204074611脱敏之后为530321**********11 | ||||
| public @interface IdCardDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 密码 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 0, suffixKeep = 0, replacer = "*") // 密码;比如:123456脱敏之后为****** | ||||
| public @interface PasswordDesensitize { | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.annotation.constraints; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; | ||||
|  | ||||
| import java.lang.annotation.Documented; | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
|  | ||||
| /** | ||||
|  * 手机号 | ||||
|  */ | ||||
| @Documented | ||||
| @Target({ElementType.FIELD}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @JacksonAnnotationsInside | ||||
| @SliderDesensitize(prefixKeep = 3, suffixKeep = 4, replacer = "*") // 手机号;比如:13248765917脱敏之后为132****5917 | ||||
| public @interface PhoneNumberDesensitize { | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.constants; | ||||
|  | ||||
| import lombok.AccessLevel; | ||||
| import lombok.NoArgsConstructor; | ||||
|  | ||||
| @NoArgsConstructor(access = AccessLevel.PRIVATE) | ||||
| public class DesensitizeConstants { | ||||
|  | ||||
|     /** | ||||
|      * 默认正则 | ||||
|      */ | ||||
|     public static final String DEFAULT_REGEX = null; | ||||
|  | ||||
|     /** | ||||
|      * 默认保持长度 | ||||
|      */ | ||||
|     public static final int DEFAULT_KEEP_LENGTH = -1; | ||||
|  | ||||
|     /** | ||||
|      * 默认替换字符 | ||||
|      */ | ||||
|     public static final String DEFAULT_REPLACER = "****"; | ||||
|  | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.enums; | ||||
|  | ||||
| import lombok.Getter; | ||||
| import lombok.RequiredArgsConstructor; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_KEEP_LENGTH; | ||||
| import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_REGEX; | ||||
| import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_REPLACER; | ||||
|  | ||||
| @Getter | ||||
| @RequiredArgsConstructor | ||||
| public enum DesensitizationStrategyEnum { | ||||
|     // 常用脱敏业务 | ||||
|     PHONE_NUMBER(DEFAULT_REGEX, 3, 4, DEFAULT_REPLACER), // 手机号;比如:13248765917脱敏之后为132****5917 | ||||
|     FIXED_PHONE(DEFAULT_REGEX, 4, 2, DEFAULT_REPLACER), // 固定电话;比如:01086551122脱敏之后为0108*****22 | ||||
|     ID_CARD(DEFAULT_REGEX, 6, 2, DEFAULT_REPLACER), // 身份证号码;比如:530321199204074611脱敏之后为530321**********11 | ||||
|     BANK_CARD(DEFAULT_REGEX, 6, 2, DEFAULT_REPLACER), // 银行卡号;比如:9988002866797031脱敏之后为998800********31 | ||||
|     CHINESE_NAME(DEFAULT_REGEX, 1, 0, "**"),// 中文名;比如:刘子豪脱敏之后为刘** | ||||
|     ADDRESS("[\\s\\S]+区", DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 地址只显示到地区,不显示详细地址;比如:广州市天河区幸福小区102号脱敏之后为广州市天河区******** | ||||
|     EMAIL("(^.)[^@]*(@.*$)", DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, "$1****$2"), // 邮箱;比如:example@gmail.com脱敏之后为e******@gmail.com | ||||
|     CAR_LICENSE(DEFAULT_REGEX, 3, 1, DEFAULT_REPLACER), // 车牌号;比如:粤A66666脱敏之后为粤A6***6 | ||||
|     PASSWORD(DEFAULT_REGEX, 0, 0, DEFAULT_REPLACER), // 密码;比如:123456脱敏之后为****** | ||||
|  | ||||
|     // 自定义脱敏业务 | ||||
|     REGEX(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 自定义正则表达式 | ||||
|     SLIDE(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 滑动脱敏 | ||||
|     CUSTOM_HANDLE(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER); // 自定义处理器 | ||||
|     ; | ||||
|  | ||||
|     /** | ||||
|      * 正则表达式 | ||||
|      */ | ||||
|     private final String regex; | ||||
|  | ||||
|     /** | ||||
|      * 前缀保留长度 | ||||
|      */ | ||||
|     private final int preKeep; | ||||
|  | ||||
|     /** | ||||
|      * 后缀保留长度 | ||||
|      */ | ||||
|     private final int suffixKeep; | ||||
|  | ||||
|     /** | ||||
|      * 脱敏替换字符 | ||||
|      */ | ||||
|     private final String replacer; | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.handler; | ||||
|  | ||||
| public class DefaultDesensitizationHandler implements DesensitizationHandler { | ||||
|  | ||||
|     @Override | ||||
|     public String handle(String origin) { | ||||
|         return origin; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -8,6 +8,6 @@ public interface DesensitizationHandler { | ||||
|      * @param origin 原始字符串 | ||||
|      * @return 脱敏后的字符串 | ||||
|      */ | ||||
|     String handle(String origin); | ||||
|     String desensitize(String origin, Object... arg); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,34 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.handler; | ||||
|  | ||||
| import cn.hutool.core.util.ReflectUtil; | ||||
|  | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| public class DesensitizationHandlerHolder { | ||||
|     /** | ||||
|      * handler 缓存,默认初始化内置的处理器 | ||||
|      */ | ||||
|     private static final Map<Class<? extends DesensitizationHandler>, DesensitizationHandler> HANDLER_MAP = new ConcurrentHashMap<>() {{ | ||||
|         put(RegexDesensitizationHandler.class, new RegexDesensitizationHandler()); | ||||
|         put(SliderDesensitizationHandler.class, new SliderDesensitizationHandler()); | ||||
|     }}; | ||||
|  | ||||
|     public static DesensitizationHandler getDesensitizationHandler(Class<? extends DesensitizationHandler> clazz) { | ||||
|         DesensitizationHandler handler = HANDLER_MAP.get(clazz); | ||||
|         if (handler != null) { | ||||
|             return handler; | ||||
|         } | ||||
|         synchronized (DesensitizationHandlerHolder.class) { | ||||
|             handler = HANDLER_MAP.get(clazz); | ||||
|             // 双重校验锁 | ||||
|             if (handler != null) { | ||||
|                 return handler; | ||||
|             } | ||||
|             handler = ReflectUtil.newInstanceIfPossible(clazz); | ||||
|             HANDLER_MAP.put(clazz, handler); | ||||
|         } | ||||
|         return handler; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.handler; | ||||
|  | ||||
| public class RegexDesensitizationHandler implements DesensitizationHandler { | ||||
|  | ||||
|     @Override | ||||
|     public String desensitize(String origin, Object... arg) { | ||||
|         String regex = (String) arg[0]; | ||||
|         String replacer = (String) arg[1]; | ||||
|  | ||||
|         return origin.replaceAll(regex, replacer); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.handler; | ||||
|  | ||||
| public class SliderDesensitizationHandler implements DesensitizationHandler { | ||||
|  | ||||
|     @Override | ||||
|     public String desensitize(String origin, Object... arg) { | ||||
|         int prefixKeep = (Integer) arg[0]; | ||||
|         int suffixKeep = (Integer) arg[1]; | ||||
|         String replacer = (String) arg[2]; | ||||
|  | ||||
|         int length = origin.length(); | ||||
|  | ||||
|         // 原始字符串长度小于等于保留长度,则原始字符串全部替换 | ||||
|         if (prefixKeep >= length || suffixKeep >= length) { | ||||
|             return buildReplacerByLength(replacer, length); | ||||
|         } | ||||
|  | ||||
|         // 如果原始字符串小于等于前后缀保留字符串长度,则原始字符串全部替换 | ||||
|         if ((prefixKeep + suffixKeep) >= length) { | ||||
|             return buildReplacerByLength(replacer, length); | ||||
|         } | ||||
|  | ||||
|         int interval = length - prefixKeep - suffixKeep; | ||||
|         return origin.substring(0, prefixKeep) + | ||||
|                 buildReplacerByLength(replacer, interval) + | ||||
|                 origin.substring(prefixKeep + interval); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据长度循环构建替换符 | ||||
|      * | ||||
|      * @param replacer 替换符 | ||||
|      * @param length   长度 | ||||
|      * @return 构建后的替换符 | ||||
|      */ | ||||
|     private String buildReplacerByLength(String replacer, int length) { | ||||
|         return String.valueOf(replacer).repeat(Math.max(0, length)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,76 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.serializer; | ||||
|  | ||||
| import cn.hutool.core.util.ReflectUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.Desensitize; | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.RegexDesensitize; | ||||
| import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize; | ||||
| import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandler; | ||||
| import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandlerHolder; | ||||
| 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 com.fasterxml.jackson.databind.ser.std.StdSerializer; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.lang.reflect.Field; | ||||
|  | ||||
| /** | ||||
|  * 脱敏序列化器 | ||||
|  */ | ||||
| public class StringDesensitizeSerializer extends StdSerializer<String> implements ContextualSerializer { | ||||
|     private final DesensitizationHandler desensitizationHandler; | ||||
|  | ||||
|     protected StringDesensitizeSerializer(DesensitizationHandler desensitizationHandler) { | ||||
|         super(String.class); | ||||
|         this.desensitizationHandler = desensitizationHandler; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { | ||||
|         Desensitize annotation = beanProperty.getAnnotation(Desensitize.class); | ||||
|         if (annotation == null) { | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         return new StringDesensitizeSerializer(DesensitizationHandlerHolder.getDesensitizationHandler(annotation.desensitizationHandler())); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException { | ||||
|         if (StrUtil.isBlank(value)) { | ||||
|             gen.writeNull(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         String currentName = gen.getOutputContext().getCurrentName(); | ||||
|         Object currentValue = gen.getCurrentValue(); | ||||
|         Class<?> currentValueClass = currentValue.getClass(); | ||||
|         Field field = ReflectUtil.getField(currentValueClass, currentName); | ||||
|  | ||||
|         // 滑动处理器 | ||||
|         SliderDesensitize sliderDesensitize = field.getAnnotation(SliderDesensitize.class); | ||||
|         if (sliderDesensitize != null) { | ||||
|             value = this.desensitizationHandler.desensitize(value, sliderDesensitize.prefixKeep(), sliderDesensitize.suffixKeep(), sliderDesensitize.replacer()); | ||||
|         } | ||||
|  | ||||
|         // 正则处理器 | ||||
|         RegexDesensitize regexDesensitize = field.getAnnotation(RegexDesensitize.class); | ||||
|         if (regexDesensitize != null) { | ||||
|             value = this.desensitizationHandler.desensitize(value, regexDesensitize.regex(), regexDesensitize.replacer()); | ||||
|         } | ||||
|  | ||||
|         // 自定义处理器 | ||||
|         Desensitize desensitize = field.getAnnotation(Desensitize.class); | ||||
|         if (desensitize != null) { | ||||
|             value = this.desensitizationHandler.desensitize(value); | ||||
|         } | ||||
|  | ||||
|         gen.writeString(value); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| package cn.iocoder.yudao.framework.desensitize.handler; | ||||
|  | ||||
| import org.junit.jupiter.api.Assertions; | ||||
| import org.junit.jupiter.api.Test; | ||||
|  | ||||
| public class DesensitizationHandlerTest { | ||||
|  | ||||
|     @Test | ||||
|     public void testSliderDesensitizationHandler() { | ||||
|         DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(SliderDesensitizationHandler.class); | ||||
|  | ||||
|         Assertions.assertEquals("A****FG", handler.desensitize("ABCDEFG", 1, 2, "*")); | ||||
|         Assertions.assertEquals("芋**码", handler.desensitize("芋道源码", 1, 1, "*")); | ||||
|         Assertions.assertEquals("****", handler.desensitize("芋道源码", 4, 0, "*")); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void testRegexDesensitizationHandler() { | ||||
|         DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(RegexDesensitizationHandler.class); | ||||
|  | ||||
|         Assertions.assertEquals("e****@gmail.com", handler.desensitize("example@gmail.com", "(^.)[^@]*(@.*$)", "$1****$2")); | ||||
|         Assertions.assertEquals("***,铁***", handler.desensitize("他妈的,铁废物", "他妈的|去你大爷|卧槽|草泥马|废物", "***")); | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 gaibu
					gaibu