初始化仓库

This commit is contained in:
2026-04-21 15:08:07 +08:00
parent 444d984122
commit b5119afb9f
195 changed files with 11034 additions and 19 deletions

30
xtools-boot-mask/pom.xml Normal file
View 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>

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
xtools.boot.mask.BootMaskConfiguration