Compare commits

...

2 Commits

Author SHA1 Message Date
42f0212a40 fix static method 2025-12-26 15:52:00 +08:00
7378078299 update StringInterpolator 2025-11-06 14:08:30 +08:00
4 changed files with 120 additions and 75 deletions

View File

@ -77,12 +77,13 @@
<dependency> <dependency>
<groupId>com.imyeyu.java</groupId> <groupId>com.imyeyu.java</groupId>
<artifactId>timi-java</artifactId> <artifactId>timi-java</artifactId>
<version>0.0.1</version> <version>0.0.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>de.mkammerer</groupId> <groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId> <artifactId>argon2-jvm</artifactId>
<version>2.12</version> <version>2.12</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>

View File

@ -22,7 +22,7 @@ public class Decryptor {
* @param key 密钥 * @param key 密钥
* @return 解密结果 * @return 解密结果
*/ */
public byte[] aes(String data, byte[] key) { public static byte[] aes(String data, byte[] key) {
return aes(data.getBytes(), key); return aes(data.getBytes(), key);
} }
@ -33,7 +33,7 @@ public class Decryptor {
* @param key 密钥 * @param key 密钥
* @return 解密结果 * @return 解密结果
*/ */
public byte[] aes(byte[] data, byte[] key) { public static byte[] aes(byte[] data, byte[] key) {
try { try {
SecretKey secretKey = new SecretKeySpec(key, "AES"); SecretKey secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

View File

@ -16,11 +16,11 @@ import java.security.NoSuchAlgorithmException;
*/ */
public class Encryptor { public class Encryptor {
public byte[] aesKey() { public static byte[] aesKey() {
return aesKey(256); return aesKey(256);
} }
public byte[] aesKey(int size) { public static byte[] aesKey(int size) {
try { try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(size); keyGen.init(size);
@ -37,7 +37,7 @@ public class Encryptor {
* @param key 密钥 * @param key 密钥
* @return 加密结果 * @return 加密结果
*/ */
public byte[] aes(String data, byte[] key) { public static byte[] aes(String data, byte[] key) {
return aes(data.getBytes(), key); return aes(data.getBytes(), key);
} }
@ -48,7 +48,7 @@ public class Encryptor {
* @param key 密钥 * @param key 密钥
* @return 加密结果 * @return 加密结果
*/ */
public byte[] aes(byte[] data, byte[] key) { public static byte[] aes(byte[] data, byte[] key) {
try { try {
SecretKey secretKey = new SecretKeySpec(key, "AES"); SecretKey secretKey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

View File

@ -6,6 +6,8 @@ import com.imyeyu.java.ref.Ref;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -16,26 +18,21 @@ import java.util.regex.Pattern;
*/ */
public class StringInterpolator { public class StringInterpolator {
/** ${} 插值正则 */
public static final String DOLLAR_OBJ = "\\$\\{(.+?)\\}"; public static final String DOLLAR_OBJ = "\\$\\{(.+?)\\}";
/** {} 插值正则 */
public static final String SIMPLE_OBJ = "\\{(.+?)\\}"; public static final String SIMPLE_OBJ = "\\{(.+?)\\}";
/** 缓存解析过的嵌套属性路径 */
private final Map<String, String[]> deepKeyCache = new ConcurrentHashMap<>();
/** 正则匹配器 */ /** 正则匹配器 */
private final Pattern pattern; private final Pattern pattern;
/** 为 true 时允许安全插值空,变量可以插值 null 而不抛出异常 */ /** 过滤器映射 */
private final Map<String, CallbackArgReturn<String, String>> filterMap = new HashMap<>();
/** 空值处理策略 */
private boolean nullable = false; private boolean nullable = false;
/** 过滤器 */
private Map<String, CallbackArgReturn<String, String>> filterMap;
/**
* 默认构造
*
* @param regex 插槽正则
*/
public StringInterpolator(String regex) { public StringInterpolator(String regex) {
this.pattern = Pattern.compile(regex); this.pattern = Pattern.compile(regex);
} }
@ -43,80 +40,115 @@ public class StringInterpolator {
/** /**
* 注入变量 * 注入变量
* *
* @param string 字符串 * @param template 字符串
* @param argsMap 变量表 * @param argsMap 变量表
* @return 插值结果 * @return 插值结果
*/ */
public String inject(String string, Map<String, Object> argsMap) { public String inject(String template, Map<String, Object> argsMap) {
return pattern.matcher(string).replaceAll(result -> { if (TimiJava.isEmpty(template) || TimiJava.isEmpty(argsMap)) {
String group = result.group(1); return template;
String key = group.trim();
String[] filters = null;
if (group.contains("|")) {
// 过滤器
String[] groups = group.split("\\|");
key = groups[0].trim();
filters = new String[groups.length - 1];
System.arraycopy(groups, 1, filters, 0, filters.length);
} }
Object value = argsMap.get(key); Matcher matcher = pattern.matcher(template);
if (key.contains(".")) { StringBuilder result = new StringBuilder();
// 反射获取 while (matcher.find()) {
String replacement = processReplacement(matcher.group(1), argsMap);
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(result);
return result.toString();
}
/** 处理单个替换项 */
private String processReplacement(String expression, Map<String, Object> argsMap) {
// 解析表达式:变量名和过滤器
ExpressionParts parts = parseExpression(expression);
// 获取变量值
Object value = getVariableValue(parts.variable, argsMap);
// 应用过滤器
value = applyFilters(value, parts.filters);
// 处理空值
return handleNullValue(value, parts.variable);
}
/** 解析表达式为变量名和过滤器数组 */
private ExpressionParts parseExpression(String expression) {
if (!expression.contains("|")) {
return new ExpressionParts(expression.trim(), new String[0]);
}
String[] parts = expression.split("\\|");
String variable = parts[0].trim();
String[] filters = new String[parts.length - 1];
for (int i = 1; i < parts.length; i++) {
filters[i - 1] = parts[i].trim();
}
return new ExpressionParts(variable, filters);
}
/** 获取变量值,支持嵌套属性 */
private Object getVariableValue(String variable, Map<String, Object> argsMap) {
Object value = argsMap.get(variable);
if (variable.contains(".")) {
value = getNestedPropertyValue(variable, argsMap);
}
return value;
}
/** 获取嵌套属性值 */
private Object getNestedPropertyValue(String deepKey, Map<String, Object> argsMap) {
String[] keyPath = deepKeyCache.computeIfAbsent(deepKey, k -> k.split("\\."));
try { try {
String[] deepKey = key.split("\\."); Object value = argsMap.get(keyPath[0]);
value = argsMap.get(deepKey[0]); for (int i = 1; i < keyPath.length && value != null; i++) {
for (int i = 1; i < deepKey.length; i++) { value = Ref.getFieldValue(value, keyPath[i], Object.class);
value = Ref.getFieldValue(value, deepKey[i], Object.class);
} }
return value;
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new RuntimeException("ref field file: " + e.getMessage(), e); throw new RuntimeException("ref field error: " + e.getMessage(), e);
} }
} }
if (TimiJava.isNotEmpty(filterMap) && TimiJava.isNotEmpty(filters)) {
// 过滤 /** 应用过滤器链 */
for (int i = 0; i < filters.length; i++) { private Object applyFilters(Object value, String[] filters) {
CallbackArgReturn<String, String> filter = filterMap.get(filters[i].trim()); if (TimiJava.isEmpty(filters) || TimiJava.isEmpty(filterMap) || value == null) {
return value;
}
String currentValue = String.valueOf(value);
for (String filterName : filters) {
CallbackArgReturn<String, String> filter = filterMap.get(filterName);
if (filter == null) { if (filter == null) {
throw new NullPointerException("not found %s filter for %s".formatted(filters[i], key)); throw new IllegalArgumentException("not found %s filter for".formatted(filterName));
} }
value = filter.handler((String) value); currentValue = filter.handler(currentValue);
} }
return currentValue;
} }
/** 处理空值情况 */
private String handleNullValue(Object value, String variable) {
if (value == null) { if (value == null) {
if (!nullable) { if (!nullable) {
throw new NullPointerException("null pointer exception for arg: " + key); throw new NullPointerException("not found %s value".formatted(variable));
} }
value = ""; return "";
} }
return String.valueOf(value); return String.valueOf(value);
});
} }
public void putFilter(String name, CallbackArgReturn<String, String> callback) { public void putFilter(String name, CallbackArgReturn<String, String> callback) {
if (filterMap == null) {
filterMap = new HashMap<>();
}
filterMap.put(name, callback); filterMap.put(name, callback);
} }
public void putAllFilter(Map<String, CallbackArgReturn<String, String>> filterMap) { public void putAllFilter(Map<String, CallbackArgReturn<String, String>> filters) {
if (this.filterMap == null) { filterMap.putAll(filters);
this.filterMap = new HashMap<>();
}
this.filterMap.putAll(filterMap);
} }
public void removeFilter(String name) { public void removeFilter(String name) {
if (TimiJava.isNotEmpty(filterMap)) {
filterMap.remove(name); filterMap.remove(name);
} }
}
public void clearFilter() { public void clearFilter() {
if (TimiJava.isNotEmpty(filterMap)) {
filterMap.clear(); filterMap.clear();
} }
}
public void setNullable(boolean nullable) { public void setNullable(boolean nullable) {
this.nullable = nullable; this.nullable = nullable;
@ -125,4 +157,16 @@ public class StringInterpolator {
public boolean isNullable() { public boolean isNullable() {
return nullable; return nullable;
} }
/** 表达式部分内部类 */
private record ExpressionParts(String variable, String[] filters) {
}
public static StringInterpolator createDollarInterpolator() {
return new StringInterpolator(DOLLAR_OBJ);
}
public static StringInterpolator createSimpleInterpolator() {
return new StringInterpolator(SIMPLE_OBJ);
}
} }