初始化仓库
This commit is contained in:
30
xtools-boot-mask/pom.xml
Normal file
30
xtools-boot-mask/pom.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>org.xujun</groupId>
|
||||
<artifactId>xtools-boot</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<artifactId>xtools-boot-mask</artifactId>
|
||||
|
||||
<!-- 依赖 -->
|
||||
<dependencies>
|
||||
<!-- xtools-boot begin -->
|
||||
<!-- xtools-boot-core -->
|
||||
<dependency>
|
||||
<groupId>org.xujun</groupId>
|
||||
<artifactId>xtools-boot-core</artifactId>
|
||||
</dependency>
|
||||
<!-- xtools-boot end -->
|
||||
|
||||
<!-- jackson-databind -->
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package xtools.boot.mask;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import xtools.boot.core.utils.ModuleLoadUtils;
|
||||
import xtools.boot.mask.selector.BootMaskImportSelector;
|
||||
|
||||
/**
|
||||
* <p>Title : BootMaskConfiguration</p>
|
||||
* <p>Description : BootMaskConfiguration</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
@Import(BootMaskImportSelector.class)
|
||||
public class BootMaskConfiguration {
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
public BootMaskConfiguration() {
|
||||
ModuleLoadUtils.loadSuccess(BootMaskConfiguration.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xtools.boot.mask;
|
||||
|
||||
import xtools.boot.mask.anntation.Mask;
|
||||
|
||||
/**
|
||||
* <p>Title : MaskCustom</p>
|
||||
* <p>Description : MaskCustom</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/9 10:08
|
||||
*/
|
||||
public interface MaskCustom {
|
||||
|
||||
/**
|
||||
* 脱敏处理
|
||||
*
|
||||
* @param value 待处理的字符串
|
||||
* @param mask 脱敏注解
|
||||
* @return 脱敏后的字符串
|
||||
*/
|
||||
String mask(String value, Mask mask);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package xtools.boot.mask.anntation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import xtools.boot.mask.MaskCustom;
|
||||
import xtools.boot.mask.enums.MaskType;
|
||||
import xtools.boot.mask.handle.DefaultMaskHandle;
|
||||
import xtools.boot.mask.serializer.MaskSerializer;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Title : Mask</p>
|
||||
* <p>Description : Mask</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/9 10:07
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@JacksonAnnotationsInside
|
||||
@JsonSerialize(using = MaskSerializer.class)
|
||||
public @interface Mask {
|
||||
|
||||
/**
|
||||
* 脱敏类型
|
||||
*
|
||||
* @return 脱敏类型
|
||||
*/
|
||||
MaskType value();
|
||||
|
||||
/**
|
||||
* 是否总是脱敏(无法忽略脱敏)
|
||||
*
|
||||
* @return 是否总是脱敏
|
||||
*/
|
||||
boolean always() default false;
|
||||
|
||||
/**
|
||||
* 前缀不脱敏长度
|
||||
*
|
||||
* @return 前缀不脱敏长度
|
||||
*/
|
||||
int prefixNoMaskLen() default 0;
|
||||
|
||||
/**
|
||||
* 后缀不脱敏长度
|
||||
*
|
||||
* @return 后缀不脱敏长度
|
||||
*/
|
||||
int suffixNoMaskLen() default 0;
|
||||
|
||||
/**
|
||||
* 脱敏替代字符
|
||||
*
|
||||
* @return 脱敏替代字符
|
||||
*/
|
||||
String maskChar() default "*";
|
||||
|
||||
/**
|
||||
* 自定义脱敏接口
|
||||
*
|
||||
* @return 自定义脱敏接口
|
||||
*/
|
||||
Class<? extends MaskCustom> custom() default DefaultMaskHandle.class;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package xtools.boot.mask.enums;
|
||||
|
||||
/**
|
||||
* <p>Title : MaskType</p>
|
||||
* <p>Description : MaskType</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/9 10:07
|
||||
*/
|
||||
public enum MaskType {
|
||||
|
||||
// 中文名
|
||||
CHINESE_NAME,
|
||||
// 身份证号
|
||||
ID_CARD,
|
||||
// 手机号
|
||||
MOBILE_PHONE,
|
||||
// 邮箱
|
||||
EMAIL,
|
||||
// 银行卡
|
||||
BANK_CARD,
|
||||
// 密码
|
||||
PASSWORD,
|
||||
// 地址
|
||||
ADDRESS,
|
||||
// 自定义
|
||||
CUSTOM
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package xtools.boot.mask.handle;
|
||||
|
||||
import xtools.boot.mask.MaskCustom;
|
||||
import xtools.boot.mask.anntation.Mask;
|
||||
|
||||
/**
|
||||
* <p>Title : DefaultMaskHandle</p>
|
||||
* <p>Description : DefaultMaskHandle</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/4 15:19
|
||||
*/
|
||||
public class DefaultMaskHandle implements MaskCustom {
|
||||
|
||||
/**
|
||||
* 脱敏处理
|
||||
*
|
||||
* @param value 待处理的字符串
|
||||
* @param mask 脱敏注解
|
||||
* @return 脱敏后的字符串
|
||||
*/
|
||||
@Override
|
||||
public String mask(String value, Mask mask) {
|
||||
final int length = value.length();
|
||||
int prefixNoMaskLen = mask.prefixNoMaskLen();
|
||||
int suffixNoMaskLen = mask.suffixNoMaskLen();
|
||||
if (prefixNoMaskLen > 0 && length <= prefixNoMaskLen) {
|
||||
return value;
|
||||
}
|
||||
if (suffixNoMaskLen > 0 && length <= suffixNoMaskLen) {
|
||||
return value;
|
||||
}
|
||||
int maskLength = length - prefixNoMaskLen - suffixNoMaskLen;
|
||||
if (maskLength <= 0) {
|
||||
return value;
|
||||
}
|
||||
return value.substring(0, prefixNoMaskLen) + mask.maskChar().repeat(maskLength) + value.substring(length - suffixNoMaskLen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package xtools.boot.mask.selector;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
||||
/**
|
||||
* <p>Title : BootMaskImportSelector</p>
|
||||
* <p>Description : BootMaskImportSelector</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/01/01 09:30
|
||||
*/
|
||||
public class BootMaskImportSelector implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* 根据给定的注释元数据,根据需要注册bean
|
||||
*
|
||||
* @param importingClassMetadata AnnotationMetadata
|
||||
* @param registry BeanDefinitionRegistry
|
||||
*/
|
||||
@Override
|
||||
public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
|
||||
// 构建扫描对象
|
||||
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true);
|
||||
// 扫描包下路径
|
||||
scanner.scan("xtools.boot.mask");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package xtools.boot.mask.serializer;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.core.TokenStreamContext;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
import tools.jackson.databind.ValueSerializer;
|
||||
import xtools.boot.mask.MaskCustom;
|
||||
import xtools.boot.mask.anntation.Mask;
|
||||
import xtools.boot.mask.utils.MaskIgnoreUtils;
|
||||
import xtools.core.StringUtils;
|
||||
import xtools.core.extend.MaskUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>Title : MaskSerializer</p>
|
||||
* <p>Description : MaskSerializer</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/1/9 10:08
|
||||
*/
|
||||
@Slf4j
|
||||
public class MaskSerializer extends ValueSerializer<String> {
|
||||
|
||||
/**
|
||||
* 序列化字符串
|
||||
*
|
||||
* @param value 待处理的字符串
|
||||
* @param gen JsonGenerator
|
||||
* @param context SerializationContext
|
||||
* @throws JacksonException JacksonException
|
||||
*/
|
||||
@Override
|
||||
public void serialize(String value, JsonGenerator gen, SerializationContext context) throws JacksonException {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
value = value.trim();
|
||||
TokenStreamContext streamContext = gen.streamWriteContext();
|
||||
if (Objects.isNull(streamContext)) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Field field = streamContext.currentValue().getClass().getDeclaredField(streamContext.currentName());
|
||||
// 获取注解
|
||||
Mask mask = field.getAnnotation(Mask.class);
|
||||
if (mask == null) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
// 判断是否总是脱敏
|
||||
if (!mask.always()) {
|
||||
// 判断是否忽略脱敏
|
||||
if (MaskIgnoreUtils.isIgnore()) {
|
||||
gen.writeString(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gen.writeString(mask(value, mask));
|
||||
} catch (Exception e) {
|
||||
log.error("脱敏处理异常", e);
|
||||
gen.writeString(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脱敏处理
|
||||
*
|
||||
* @param value 待处理的字符串
|
||||
* @param mask 脱敏注解
|
||||
* @return 脱敏后的字符串
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private String mask(String value, Mask mask) throws Exception {
|
||||
String maskString = mask.maskChar();
|
||||
return switch (mask.value()) {
|
||||
case PASSWORD -> MaskUtils.password(value, maskString);
|
||||
case MOBILE_PHONE -> MaskUtils.mobilePhone(value, maskString);
|
||||
case EMAIL -> MaskUtils.email(value, maskString);
|
||||
case CHINESE_NAME -> MaskUtils.chineseName(value, maskString);
|
||||
case ADDRESS -> MaskUtils.address(value, maskString);
|
||||
case ID_CARD -> MaskUtils.idCard(value, maskString);
|
||||
case BANK_CARD -> MaskUtils.bankCard(value, maskString);
|
||||
case CUSTOM -> customMask(value, mask);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义脱敏处理
|
||||
*
|
||||
* @param value 待处理的字符串
|
||||
* @param mask 脱敏注解
|
||||
* @return 脱敏后的字符串
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
private String customMask(String value, Mask mask) throws Exception {
|
||||
Class<? extends MaskCustom> custom = mask.custom();
|
||||
return custom.getDeclaredConstructor().newInstance().mask(value, mask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package xtools.boot.mask.utils;
|
||||
|
||||
import xtools.boot.core.holder.CommonHolder;
|
||||
|
||||
/**
|
||||
* <p>Title : MaskUtils</p>
|
||||
* <p>Description : MaskUtils</p>
|
||||
* <p>DevelopTools : Idea_x64_v2026.1</p>
|
||||
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
|
||||
* <p>Company : org.xujun</p>
|
||||
*
|
||||
* @author : XuJun
|
||||
* @version : 5.0.0
|
||||
* @date : 2026/2/9 16:38
|
||||
*/
|
||||
public class MaskIgnoreUtils {
|
||||
|
||||
/**
|
||||
* 忽略脱敏
|
||||
*/
|
||||
private static final String IGNORE = "mask-ignore";
|
||||
|
||||
/**
|
||||
* 忽略脱敏
|
||||
*/
|
||||
public static void ignore() {
|
||||
CommonHolder.set(IGNORE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否忽略脱敏
|
||||
*
|
||||
* @return true 忽略, false 不忽略
|
||||
*/
|
||||
public static boolean isIgnore() {
|
||||
return CommonHolder.getBoolean(IGNORE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
xtools.boot.mask.BootMaskConfiguration
|
||||
Reference in New Issue
Block a user