diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..8fa5a60
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,91 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.2
+
+
+ org.applesline
+ desensitize
+ 1.0.0
+ desensitize
+ 数据脱敏工具库
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.aspectj
+ aspectjweaver
+
+
+ com.jayway.jsonpath
+ json-path
+ 2.2.0
+
+
+ com.google.code.gson
+ gson
+
+
+
+
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+ default-deploy
+ deploy
+
+ deploy
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.5.1
+
+
+ default-deploy
+ deploy
+
+ deploy
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/applesline/desensitize/annotation/Desensitize.java b/src/main/java/org/applesline/desensitize/annotation/Desensitize.java
new file mode 100644
index 0000000..ef11803
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/annotation/Desensitize.java
@@ -0,0 +1,17 @@
+package org.applesline.desensitize.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/13
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Desensitize {
+
+ FieldMapping[] fieldMapping() default {};
+
+ String[] ignoreByJpe() default {};
+}
diff --git a/src/main/java/org/applesline/desensitize/annotation/EnableDesensitize.java b/src/main/java/org/applesline/desensitize/annotation/EnableDesensitize.java
new file mode 100644
index 0000000..dd5cc2e
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/annotation/EnableDesensitize.java
@@ -0,0 +1,27 @@
+package org.applesline.desensitize.annotation;
+
+import org.applesline.desensitize.config.AutoDesensitizeConfiguration;
+import org.applesline.desensitize.config.AutoDesensitizeRegistrar;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/19
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Import({AutoDesensitizeConfiguration.class, AutoDesensitizeRegistrar.class})
+public @interface EnableDesensitize {
+
+ FieldMapping[] fieldMapping() default {};
+
+ /**
+ * ignore by JsonPath expression language
+ *
+ * @return
+ */
+ String[] ignoreByJpe() default {};
+}
diff --git a/src/main/java/org/applesline/desensitize/annotation/FieldMapping.java b/src/main/java/org/applesline/desensitize/annotation/FieldMapping.java
new file mode 100644
index 0000000..b992150
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/annotation/FieldMapping.java
@@ -0,0 +1,15 @@
+package org.applesline.desensitize.annotation;
+
+
+import org.applesline.desensitize.constants.DesensitizeType;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public @interface FieldMapping {
+
+ DesensitizeType type();
+
+ String[] fields() default {};
+}
diff --git a/src/main/java/org/applesline/desensitize/aop/DesensitizeAdvice.java b/src/main/java/org/applesline/desensitize/aop/DesensitizeAdvice.java
new file mode 100644
index 0000000..4d9e209
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/aop/DesensitizeAdvice.java
@@ -0,0 +1,69 @@
+package org.applesline.desensitize.aop;
+
+import org.applesline.desensitize.annotation.Desensitize;
+import org.applesline.desensitize.annotation.FieldMapping;
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.executor.DesensitizeExecutor;
+import org.applesline.desensitize.executor.JsonPathDesensitizeExecutor;
+import org.applesline.desensitize.handle.DesensitizeHandlerSelector;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+@Aspect
+public class DesensitizeAdvice implements ApplicationContextAware {
+
+ private DesensitizeExecutor desensitizeExecutor;
+ private DesensitizeExecutor globalDesensitizeExecutor;
+
+ public DesensitizeAdvice(DesensitizeExecutor desensitizeExecutor) {
+ this.desensitizeExecutor = desensitizeExecutor;
+ }
+
+ @Around("@annotation(org.applesline.desensitize.annotation.Desensitize)")
+ public Object desensitize(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+ Signature signature = proceedingJoinPoint.getSignature();
+ Object obj = proceedingJoinPoint.proceed();
+ if (signature instanceof MethodSignature) {
+ MethodSignature methodSignature = (MethodSignature)signature;
+ Desensitize desensitize = methodSignature.getMethod().getAnnotation(Desensitize.class);
+ Map fieldMappingMap = new HashMap<>();
+ FieldMapping[] fieldMappings = desensitize.fieldMapping();
+ for (FieldMapping fieldMapping : fieldMappings) {
+ DesensitizeType desensitizeType = fieldMapping.type();
+ String[] fields = fieldMapping.fields();
+ for (String field : fields) {
+ fieldMappingMap.putIfAbsent(field,desensitizeType);
+ }
+ }
+ if (fieldMappingMap.isEmpty()) {
+ obj = globalDesensitizeExecutor.executeMask(obj);
+ } else {
+ desensitizeExecutor.configFields(fieldMappingMap, Arrays.stream(desensitize.ignoreByJpe()).collect(Collectors.toList()));
+ obj = desensitizeExecutor.executeMask(obj);
+ }
+ }
+ return obj;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ DesensitizeHandlerSelector selector = applicationContext.getBean(DesensitizeHandlerSelector.class);
+ this.globalDesensitizeExecutor = new JsonPathDesensitizeExecutor(selector);
+ this.globalDesensitizeExecutor.configFields(this.desensitizeExecutor.getMaskWordsMap(),this.desensitizeExecutor.getIgnoreJsonPathExpression());
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/config/AutoDesensitizeConfiguration.java b/src/main/java/org/applesline/desensitize/config/AutoDesensitizeConfiguration.java
new file mode 100644
index 0000000..c266930
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/config/AutoDesensitizeConfiguration.java
@@ -0,0 +1,32 @@
+package org.applesline.desensitize.config;
+
+import org.applesline.desensitize.aop.DesensitizeAdvice;
+import org.applesline.desensitize.executor.DesensitizeExecutor;
+import org.applesline.desensitize.executor.JsonPathDesensitizeExecutor;
+import org.applesline.desensitize.handle.DesensitizeHandlerSelector;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/18
+ */
+@Configuration
+public class AutoDesensitizeConfiguration {
+
+ @Bean
+ public DesensitizeHandlerSelector maskHandlerSelector() {
+ return new DesensitizeHandlerSelector();
+ }
+
+ @Bean
+ public DesensitizeExecutor maskSensitiveExecutor(DesensitizeHandlerSelector desensitizeHandlerSelector) {
+ return new JsonPathDesensitizeExecutor(desensitizeHandlerSelector);
+ }
+
+ @Bean
+ public DesensitizeAdvice desensitizeAdvice(DesensitizeExecutor desensitizeExecutor) {
+ return new DesensitizeAdvice(desensitizeExecutor);
+ }
+
+}
diff --git a/src/main/java/org/applesline/desensitize/config/AutoDesensitizeRegistrar.java b/src/main/java/org/applesline/desensitize/config/AutoDesensitizeRegistrar.java
new file mode 100644
index 0000000..c8ebb5a
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/config/AutoDesensitizeRegistrar.java
@@ -0,0 +1,68 @@
+package org.applesline.desensitize.config;
+
+import org.applesline.desensitize.annotation.EnableDesensitize;
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.impl.AddressHandler;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/19
+ */
+public class AutoDesensitizeRegistrar implements ImportBeanDefinitionRegistrar {
+
+ private static final String DESENSITIZE_BEAN_POST_PROCESSOR = "desensitizeBeanPostProcessor";
+ private static final String FIELD_MAPPING = "fieldMapping";
+ private static final String IGNORE_BY_JSONPATH_EXPRESS = "ignoreByJpe";
+ private static final String TYPE = "type";
+ private static final String FIELDS = "fields";
+
+ private static final String SCAN_DESENSITIZE_HANDLER_BASE_PACKAGE = AddressHandler.class.getPackage().getName();
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
+ Map defaultAttrs = importingClassMetadata.getAnnotationAttributes(EnableDesensitize.class.getName());
+
+ AnnotationAttributes[] annotationAttributes = (AnnotationAttributes[]) defaultAttrs.get(FIELD_MAPPING);
+ Map fieldMappingMap = new HashMap<>();
+ for (AnnotationAttributes annotationAttribute : annotationAttributes) {
+ String[] fields = (String[])annotationAttribute.get(FIELDS);
+ DesensitizeType desensitizeType = (DesensitizeType)annotationAttribute.get(TYPE);
+ for (String field : fields) {
+ fieldMappingMap.putIfAbsent(field,desensitizeType);
+ }
+ }
+ String[] ignoreByJsonPathExpress = (String[])defaultAttrs.get(IGNORE_BY_JSONPATH_EXPRESS);
+ List jpeList = new ArrayList<>();
+ for (String str : ignoreByJsonPathExpress) {
+ if (!StringUtils.isEmpty(str.trim())) {
+ jpeList.add(str.trim());
+ }
+ }
+
+ if (!registry.containsBeanDefinition(DESENSITIZE_BEAN_POST_PROCESSOR)) {
+ AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
+ .genericBeanDefinition(DesensitizeBeanPostProcessor.class)
+ .addConstructorArgValue(fieldMappingMap)
+ .addConstructorArgValue(jpeList)
+ .getBeanDefinition();
+ registry.registerBeanDefinition(DESENSITIZE_BEAN_POST_PROCESSOR, beanDefinition);
+ }
+
+ ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
+ scanner.scan(SCAN_DESENSITIZE_HANDLER_BASE_PACKAGE);
+ }
+
+}
diff --git a/src/main/java/org/applesline/desensitize/config/DesensitizeBeanPostProcessor.java b/src/main/java/org/applesline/desensitize/config/DesensitizeBeanPostProcessor.java
new file mode 100644
index 0000000..a30a0a6
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/config/DesensitizeBeanPostProcessor.java
@@ -0,0 +1,38 @@
+package org.applesline.desensitize.config;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.executor.JsonPathDesensitizeExecutor;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/20
+ */
+public class DesensitizeBeanPostProcessor implements BeanPostProcessor {
+
+ Map maskFieldMapping;
+ List ignoreByJsonPathExpress;
+
+ public DesensitizeBeanPostProcessor(Map maskFieldMapping, List ignoreByJsonPathExpress) {
+ this.maskFieldMapping = maskFieldMapping;
+ this.ignoreByJsonPathExpress = ignoreByJsonPathExpress;
+ }
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (bean.getClass() == JsonPathDesensitizeExecutor.class) {
+ JsonPathDesensitizeExecutor executor = (JsonPathDesensitizeExecutor)bean;
+ executor.configFields(maskFieldMapping,ignoreByJsonPathExpress);
+ }
+ return bean;
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/constants/DesensitizeType.java b/src/main/java/org/applesline/desensitize/constants/DesensitizeType.java
new file mode 100644
index 0000000..8bb0bf8
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/constants/DesensitizeType.java
@@ -0,0 +1,22 @@
+package org.applesline.desensitize.constants;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public enum DesensitizeType {
+
+ EMAIL,
+ MOBILE,
+ PASSWORD,
+ USER_ID,
+ IP,
+ ADDRESS,
+ OTHER_CARD,
+ BANK_CARD,
+ CAR_LICENSE,
+ GENDER,
+ BIRTHDAY,
+ CHINESE_NAME,
+ ID_CARD;
+}
diff --git a/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutor.java b/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutor.java
new file mode 100644
index 0000000..05c9062
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutor.java
@@ -0,0 +1,23 @@
+package org.applesline.desensitize.executor;
+
+
+import org.applesline.desensitize.constants.DesensitizeType;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/13
+ */
+public interface DesensitizeExecutor {
+
+ void configFields(Map maskWordsMap, Collection ignoreJsonPathExpression);
+
+ Map getMaskWordsMap();
+
+ Collection getIgnoreJsonPathExpression();
+
+ Object executeMask(Object obj);
+
+}
diff --git a/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutorAdapter.java b/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutorAdapter.java
new file mode 100644
index 0000000..7c8e649
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/executor/DesensitizeExecutorAdapter.java
@@ -0,0 +1,57 @@
+package org.applesline.desensitize.executor;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.DesensitizeHandlerSelector;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/17
+ */
+public class DesensitizeExecutorAdapter implements DesensitizeExecutor {
+
+ protected DesensitizeHandlerSelector desensitizeHandlerSelector;
+
+ protected Map maskWordsMap;
+ protected Collection ignoreJsonPathExpression;
+
+ public DesensitizeExecutorAdapter(DesensitizeHandlerSelector desensitizeHandlerSelector) {
+ this.desensitizeHandlerSelector = desensitizeHandlerSelector;
+ }
+
+ protected Gson gson = new GsonBuilder().create();
+
+ @Override
+ public void configFields(Map maskWordsMap, Collection ignoreJsonPathExpression) {
+ this.maskWordsMap = maskWordsMap;
+ this.ignoreJsonPathExpression = ignoreJsonPathExpression;
+ }
+
+ @Override
+ public Map getMaskWordsMap() {
+ return this.maskWordsMap;
+ }
+
+ @Override
+ public Collection getIgnoreJsonPathExpression() {
+ return this.ignoreJsonPathExpression;
+ }
+
+ @Override
+ public Object executeMask(Object obj) {
+ throw new RuntimeException();
+ }
+
+ public Long doMask(DesensitizeType desensitizeType) {
+ return desensitizeHandlerSelector.getService(desensitizeType).doMask();
+ }
+
+ public String doMask(DesensitizeType desensitizeType, String origin) {
+ return desensitizeHandlerSelector.getService(desensitizeType).doMask(origin);
+ }
+
+}
diff --git a/src/main/java/org/applesline/desensitize/executor/JsonPathDesensitizeExecutor.java b/src/main/java/org/applesline/desensitize/executor/JsonPathDesensitizeExecutor.java
new file mode 100644
index 0000000..3b7cd7c
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/executor/JsonPathDesensitizeExecutor.java
@@ -0,0 +1,73 @@
+package org.applesline.desensitize.executor;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.jayway.jsonpath.JsonPath;
+import org.applesline.desensitize.handle.DesensitizeHandlerSelector;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public class JsonPathDesensitizeExecutor extends DesensitizeExecutorAdapter {
+
+ public JsonPathDesensitizeExecutor(DesensitizeHandlerSelector desensitizeHandlerSelector) {
+ super(desensitizeHandlerSelector);
+ }
+
+ @Override
+ public Object executeMask(Object obj) {
+ JsonElement jsonTree = gson.toJsonTree(obj);
+ maskSensitiveWords(jsonTree,matchIgnoreFields(obj));
+ return gson.fromJson(jsonTree.toString(),obj.getClass());
+ }
+
+ private void maskSensitiveWords(JsonElement originElement,Collection ignoreMaskWords) {
+ Set needMaskWords = maskWordsMap.keySet();
+ if (originElement.isJsonArray()) {
+ JsonArray jsonArray = originElement.getAsJsonArray();
+ for (JsonElement jsonElement : jsonArray) {
+ maskSensitiveWords(jsonElement,ignoreMaskWords);
+ }
+ } else if (originElement.isJsonObject()) {
+ JsonObject jsonObject = originElement.getAsJsonObject();
+ for (Map.Entry entry : originElement.getAsJsonObject().entrySet()) {
+ JsonElement element = entry.getValue();
+ if (element.isJsonArray()) {
+ maskSensitiveWords(element.getAsJsonArray(),ignoreMaskWords);
+ } else if (element.isJsonObject()) {
+ maskSensitiveWords(element.getAsJsonObject(),ignoreMaskWords);
+ } else {
+ if (needMaskWords.contains(entry.getKey()) && !ignoreMaskWords.contains(entry.getValue().getAsString())) {
+ if (element.getAsJsonPrimitive().isNumber()) {
+ jsonObject.addProperty(entry.getKey(), doMask(maskWordsMap.get(entry.getKey())));
+ } else {
+ jsonObject.addProperty(entry.getKey(), doMask(maskWordsMap.get(entry.getKey()),entry.getValue().getAsString()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private Collection matchIgnoreFields(Object obj) {
+ Collection ignoreMaskFields = new HashSet<>();
+ for (String ignoreJpe : ignoreJsonPathExpression) {
+ Object field = JsonPath.read(gson.toJsonTree(obj).toString(),ignoreJpe);
+ if (field instanceof Collection) {
+ ignoreMaskFields.addAll((Collection extends String>) field);
+ } else {
+ ignoreMaskFields.add(String.valueOf(field));
+ }
+ }
+ return ignoreMaskFields;
+ }
+
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/DesensitizeAdapter.java b/src/main/java/org/applesline/desensitize/handle/DesensitizeAdapter.java
new file mode 100644
index 0000000..6b8bab5
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/DesensitizeAdapter.java
@@ -0,0 +1,131 @@
+package org.applesline.desensitize.handle;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+
+/**
+ * 屏蔽敏感字段处理器。
+ *
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public class DesensitizeAdapter implements DesensitizeHandler {
+
+ @Override
+ public String doMask(String fieldValue) {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public Long doMask() {
+ return 0L;
+ }
+
+ protected String maskCardNumber(String idCardNum,int front,int end) {
+ if (!isBlank(idCardNum) && front + end > idCardNum.length()) {
+ return front >= 0 && end >= 0 ? hide(idCardNum, front, idCardNum.length() - end) : "";
+ }
+ return "";
+ }
+
+ protected String hide(CharSequence str, int startInclude, int endExclude) {
+ return replace(str, startInclude, endExclude, '*');
+ }
+
+ protected String replace(CharSequence str, int startInclude, int endExclude, char replacedChar) {
+ if (isEmpty(str)) {
+ return str(str);
+ } else {
+ int strLength = str.length();
+ if (startInclude > strLength) {
+ return str(str);
+ } else {
+ if (endExclude > strLength) {
+ endExclude = strLength;
+ }
+
+ if (startInclude > endExclude) {
+ return str(str);
+ } else {
+ char[] chars = new char[strLength];
+
+ for(int i = 0; i < strLength; ++i) {
+ if (i >= startInclude && i < endExclude) {
+ chars[i] = replacedChar;
+ } else {
+ chars[i] = str.charAt(i);
+ }
+ }
+
+ return new String(chars);
+ }
+ }
+ }
+ }
+
+ protected int indexOf(CharSequence seq, int searchChar) {
+ return isEmpty(seq) ? -1 : indexOf(seq, searchChar, 0);
+ }
+
+ private int indexOf(final CharSequence cs, final int searchChar, int start) {
+ if (cs instanceof String) {
+ return ((String)cs).indexOf(searchChar, start);
+ } else {
+ int sz = cs.length();
+ if (start < 0) {
+ start = 0;
+ }
+
+ for(int i = start; i < sz; ++i) {
+ if (cs.charAt(i) == searchChar) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+ }
+
+ private boolean isEmpty(CharSequence cs) {
+ return cs == null || cs.length() == 0;
+ }
+
+ protected String str(CharSequence cs) {
+ return cs == null ? null : cs.toString();
+ }
+
+ protected String repeat(char c, int count) {
+ if (count <= 0) {
+ return "";
+ } else {
+ char[] result = new char[count];
+
+ for(int i = 0; i < count; ++i) {
+ result[i] = c;
+ }
+ return new String(result);
+ }
+ }
+
+ protected boolean isBlank(CharSequence cs) {
+ int strLen;
+ if (cs != null && (strLen = cs.length()) != 0) {
+ for(int i = 0; i < strLen; ++i) {
+ if (!Character.isWhitespace(cs.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return true;
+ }
+ }
+
+ public static String trim(String str) {
+ return str == null ? null : str.trim();
+ }
+
+ @Override
+ public DesensitizeType getFieldType() {
+ throw new RuntimeException();
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/DesensitizeHandler.java b/src/main/java/org/applesline/desensitize/handle/DesensitizeHandler.java
new file mode 100644
index 0000000..80b0c62
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/DesensitizeHandler.java
@@ -0,0 +1,18 @@
+package org.applesline.desensitize.handle;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+
+/**
+ * 屏蔽敏感字段处理器。
+ *
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public interface DesensitizeHandler {
+
+ String doMask(String fieldValue);
+
+ Long doMask();
+
+ DesensitizeType getFieldType();
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/DesensitizeHandlerSelector.java b/src/main/java/org/applesline/desensitize/handle/DesensitizeHandlerSelector.java
new file mode 100644
index 0000000..a630669
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/DesensitizeHandlerSelector.java
@@ -0,0 +1,30 @@
+package org.applesline.desensitize.handle;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/14
+ */
+public class DesensitizeHandlerSelector implements ApplicationContextAware {
+
+ private Map serviceMap = new HashMap<>();
+
+ public DesensitizeHandler getService(DesensitizeType desensitizeType) {
+ return serviceMap.get(desensitizeType);
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ Map handlers = applicationContext.getBeansOfType(DesensitizeHandler.class);
+ handlers.values().forEach(handler->{
+ serviceMap.putIfAbsent(handler.getFieldType(),handler);
+ });
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/impl/AddressHandler.java b/src/main/java/org/applesline/desensitize/handle/impl/AddressHandler.java
new file mode 100644
index 0000000..7dae2ea
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/impl/AddressHandler.java
@@ -0,0 +1,28 @@
+package org.applesline.desensitize.handle.impl;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.DesensitizeAdapter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/13
+ */
+@Component
+public class AddressHandler extends DesensitizeAdapter {
+
+ @Override
+ public String doMask(String address) {
+ if (isBlank(address)) {
+ return "";
+ } else {
+ int length = address.length();
+ return hide(address, length - 8, length);
+ }
+ }
+
+ @Override
+ public DesensitizeType getFieldType() {
+ return DesensitizeType.ADDRESS;
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/impl/BankCardHandler.java b/src/main/java/org/applesline/desensitize/handle/impl/BankCardHandler.java
new file mode 100644
index 0000000..05e1f06
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/impl/BankCardHandler.java
@@ -0,0 +1,46 @@
+package org.applesline.desensitize.handle.impl;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.DesensitizeAdapter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/13
+ */
+@Component
+public class BankCardHandler extends DesensitizeAdapter {
+
+ @Override
+ public String doMask(String bankCardNo) {
+ if (isBlank(bankCardNo)) {
+ return bankCardNo;
+ } else {
+ bankCardNo = trim(bankCardNo);
+ if (bankCardNo.length() < 9) {
+ return bankCardNo;
+ } else {
+ int length = bankCardNo.length();
+ int midLength = length - 8;
+ StringBuilder buf = new StringBuilder();
+ buf.append(bankCardNo, 0, 4);
+
+ for(int i = 0; i < midLength; ++i) {
+ if (i % 4 == 0) {
+ buf.append(" ");
+ }
+
+ buf.append('*');
+ }
+
+ buf.append(" ").append(bankCardNo, length - 4, length);
+ return buf.toString();
+ }
+ }
+ }
+
+ @Override
+ public DesensitizeType getFieldType() {
+ return DesensitizeType.BANK_CARD;
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/impl/BirthdayHandler.java b/src/main/java/org/applesline/desensitize/handle/impl/BirthdayHandler.java
new file mode 100644
index 0000000..58b08a9
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/impl/BirthdayHandler.java
@@ -0,0 +1,22 @@
+package org.applesline.desensitize.handle.impl;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.DesensitizeAdapter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/19
+ */
+@Component
+public class BirthdayHandler extends DesensitizeAdapter {
+ @Override
+ public String doMask(String birthday) {
+ return isBlank(birthday) ? "" : "****-**-**";
+ }
+
+ @Override
+ public DesensitizeType getFieldType() {
+ return DesensitizeType.BIRTHDAY;
+ }
+}
diff --git a/src/main/java/org/applesline/desensitize/handle/impl/CarLicenseHandler.java b/src/main/java/org/applesline/desensitize/handle/impl/CarLicenseHandler.java
new file mode 100644
index 0000000..eaa8c1e
--- /dev/null
+++ b/src/main/java/org/applesline/desensitize/handle/impl/CarLicenseHandler.java
@@ -0,0 +1,32 @@
+package org.applesline.desensitize.handle.impl;
+
+import org.applesline.desensitize.constants.DesensitizeType;
+import org.applesline.desensitize.handle.DesensitizeAdapter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author liuyaping
+ * @date 2022/1/19
+ */
+@Component
+public class CarLicenseHandler extends DesensitizeAdapter {
+ @Override
+ public String doMask(String carLicense) {
+ if (isBlank(carLicense)) {
+ return "";
+ } else {
+ if (carLicense.length() == 7) {
+ carLicense = hide(carLicense, 3, 6);
+ } else if (carLicense.length() == 8) {
+ carLicense = hide(carLicense, 3, 7);
+ }
+
+ return carLicense;
+ }
+ }
+
+ @Override
+ public DesensitizeType getFieldType() {
+ return DesensitizeType.CAR_LICENSE;
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1 @@
+