org.springframework.boot
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java b/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java
index 4ce7656..371b0b6 100644
--- a/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/exception/ErrorCode.java
@@ -2,6 +2,8 @@ package cd.casic.framework.commons.exception;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cd.casic.framework.commons.exception.enums.ServiceErrorCodeRange;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
/**
@@ -13,6 +15,8 @@ import lombok.Data;
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
*/
@Data
+@Builder
+@AllArgsConstructor
public class ErrorCode {
/**
@@ -24,9 +28,4 @@ public class ErrorCode {
*/
private final String msg;
- public ErrorCode(Integer code, String message) {
- this.code = code;
- this.msg = message;
- }
-
}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java b/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java
index 70dd1da..b375093 100644
--- a/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/exception/enums/GlobalErrorCodeConstants.java
@@ -6,7 +6,7 @@ import cd.casic.framework.commons.exception.ErrorCode;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
- *
+ *
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
@@ -39,4 +39,6 @@ public interface GlobalErrorCodeConstants {
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
+ ErrorCode ID_DUPLICATION = new ErrorCode(1000, "ID重复");
+
}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java
index 848bd47..b64e8f8 100644
--- a/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/cache/CacheUtils.java
@@ -38,7 +38,7 @@ public class CacheUtils {
// 只阻塞当前数据加载线程,其他线程返回旧值
.refreshAfterWrite(duration)
// 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程
- .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置
+ .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool()));
}
/**
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java
new file mode 100644
index 0000000..70a44d2
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/AESUtil.java
@@ -0,0 +1,89 @@
+package cd.casic.framework.commons.util.encrypt;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.PKCS7Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Base64;
+
+/**
+ * @author by mianbin
+ * @Classname AESUtil
+ * @Description 加密算法,后面加GM算法
+ * @Date 2025/3/18 11:15
+ */
+public class AESUtil {
+ private static final String AES = "AES";
+ private static final Integer SEED = 256;
+
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public static String decrypt(String key, String content) {
+ byte[] bytes = Base64.getDecoder().decode(content);
+ KeyParameter keyParameter = generateKeyParameter(key);
+ byte[] output = processData(false, keyParameter, bytes);
+ return Base64.getEncoder().encodeToString(output);
+ }
+
+ public static byte[] decrypt(String key, byte[] content) {
+ KeyParameter keyParameter = generateKeyParameter(key);
+ return processData(false, keyParameter, content);
+ }
+
+ public static String encrypt(String key, String content) {
+ byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
+ KeyParameter keyParameter = generateKeyParameter(key);
+ byte[] output = processData(true, keyParameter, bytes);
+ return Base64.getEncoder().encodeToString(output);
+ }
+
+ public static byte[] encrypt(String key, byte[] content) {
+ KeyParameter keyParameter = generateKeyParameter(key);
+ return processData(true, keyParameter, content);
+ }
+
+ private static byte[] processData(boolean encrypt, KeyParameter keyParameter, byte[] bytes) {
+ PKCS7Padding blockCipherPadding = new PKCS7Padding();
+ CBCBlockCipher blockCipher = new CBCBlockCipher(new AESEngine());
+ PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(blockCipher, blockCipherPadding);
+ paddedBufferedBlockCipher.init(encrypt, keyParameter);
+
+ byte[] output = new byte[paddedBufferedBlockCipher.getOutputSize(bytes.length)];
+ int offset = paddedBufferedBlockCipher.processBytes(bytes, 0, bytes.length, output, 0);
+ int outputLength = 0;
+ try {
+ outputLength = paddedBufferedBlockCipher.doFinal(output, offset);
+ } catch (InvalidCipherTextException e) {
+ e.printStackTrace();
+ }
+ return Arrays.copyOf(output, offset + outputLength);
+ }
+
+ private static KeyParameter generateKeyParameter(String key) {
+ KeyGenerator keyGenerator = null;
+ SecureRandom secureRandom = null;
+ try {
+ keyGenerator = KeyGenerator.getInstance(AES);
+ secureRandom = SecureRandom.getInstance("SHA1PRNG");
+ secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ keyGenerator.init(SEED, secureRandom);
+ SecretKey secretKey = keyGenerator.generateKey();
+ byte[] encoded = secretKey.getEncoded();
+ return new KeyParameter(encoded);
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java
new file mode 100644
index 0000000..34da2d1
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHKeyPair.java
@@ -0,0 +1,41 @@
+package cd.casic.framework.commons.util.encrypt;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * @author liubin
+ * @date 2023/10/10 14:00
+ * @description
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DHKeyPair {
+
+ private byte[] publicKey;
+
+ private byte[] privateKey;
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ assert other != null;
+ if (this.getClass() != other.getClass()) return false;
+
+ if (!Arrays.equals(publicKey,((DHKeyPair) other).publicKey)) return false;
+ if (!Arrays.equals(privateKey, ((DHKeyPair) other).privateKey)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Arrays.hashCode(publicKey);
+ result = 31 * result + Arrays.hashCode(privateKey);
+ return result;
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java
new file mode 100644
index 0000000..9a9cb26
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/encrypt/DHUtil.java
@@ -0,0 +1,106 @@
+package cd.casic.framework.commons.util.encrypt;
+
+import lombok.SneakyThrows;
+
+import javax.crypto.*;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+
+public class DHUtil {
+
+ private static final String KEY_ALGORITHM = "DH";
+ private static final String KEY_PROVIDER = "BC";
+ private static final String SECRET_ALGORITHM = "DES";
+
+ private static BigInteger p = new BigInteger("16560215747140417249215968347342080587", 16);
+ private static BigInteger g = new BigInteger("1234567890", 16);
+
+ public static DHKeyPair initKey(){
+ try {
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, KEY_PROVIDER);
+ DHParameterSpec serverParam = new DHParameterSpec(p, g, 128);
+ keyPairGenerator.initialize(serverParam, new SecureRandom());
+ //keyPairGenerator.initialize(KEY_SIZE);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ return new DHKeyPair(keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded());
+ } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static DHKeyPair initKey(byte[] partyAPublicKey) {
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(partyAPublicKey);
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ PrivateKey publicKey = keyFactory.generatePrivate(x509KeySpec);
+
+ DHParameterSpec dhParameterSpec = ((DHPublicKey) publicKey).getParams();
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, KEY_PROVIDER);
+ keyPairGenerator.initialize(dhParameterSpec);
+// keyPairGenerator.initialize(KEY_SIZE);
+ KeyPair keyPair = keyPairGenerator.genKeyPair();
+ return new DHKeyPair(keyPair.getPublic().getEncoded(), keyPair.getPrivate().getEncoded());
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static byte[] encrypt(byte[] data, byte[] partAPublicKey, byte[] partBPrivateKey) {
+ byte[] key = getSecretKey(partAPublicKey, partBPrivateKey);
+ SecretKeySpec secretKey = new SecretKeySpec(key, SECRET_ALGORITHM);
+ try {
+ Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ return cipher.doFinal(data);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static byte[] decrypt(byte[] data, byte[] partBPublicKey, byte[] partAPrivateKey){
+ byte[] key = getSecretKey(partBPublicKey, partAPrivateKey);
+ SecretKeySpec secretKey = new SecretKeySpec(key, SECRET_ALGORITHM);
+ Cipher cipher = null;
+ try {
+ cipher = Cipher.getInstance(secretKey.getAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
+ return cipher.doFinal(data);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ @SneakyThrows
+ private static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) {
+ // 实例化密钥工厂
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
+ // 初始化公钥
+ X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
+ // 产生公钥
+ PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
+ // 初始化私钥
+ PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
+ // 产生私钥
+ PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
+ // 实例化
+ KeyAgreement keyAgree = KeyAgreement.getInstance(KEY_ALGORITHM, KEY_PROVIDER);
+ // 初始化
+ keyAgree.init(priKey);
+ keyAgree.doPhase(pubKey, true);
+ // 生成本地密钥
+ SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
+ return secretKey.getEncoded();
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java
new file mode 100644
index 0000000..304e926
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/generator/IdGenerator.java
@@ -0,0 +1,34 @@
+package cd.casic.framework.commons.util.generator;
+
+import java.util.List;
+
+/**
+ * @author mianbin
+ * @Classname UserTypeEnum
+ * @Description 业务id生成接口
+ * @Date 2025/3/18 14:16
+ */
+public interface IdGenerator {
+
+ /**
+ * 生成id
+ *
+ * @param key 业务标识
+ * @return 结果
+ */
+ Long get(String key);
+
+ /**
+ * 初始化
+ */
+ boolean init();
+
+ /**
+ * 批量生成id
+ *
+ * @param key 业务标识
+ * @param num id数量
+ * @return id集合
+ */
+ List batchGenerateSegmentId(String key, Integer num);
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java
new file mode 100644
index 0000000..9851ee4
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/http/OkhttpUtils.java
@@ -0,0 +1,72 @@
+package cd.casic.framework.commons.util.http;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import cd.casic.framework.commons.exception.ServiceException;
+import lombok.SneakyThrows;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author liubin
+ * @date 2023/10/11 14:02
+ * @description
+ */
+public class OkhttpUtils {
+
+ private static final long connectTimeout = 5L;
+ private static final long readTimeout = 30L;
+ private static final long writeTimeout = 30L;
+
+ private static final TrustManager[] trustAnyCerts = new TrustManager[]{new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ }};
+
+ private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
+ .connectTimeout(connectTimeout, TimeUnit.SECONDS)
+ .readTimeout(readTimeout, TimeUnit.MINUTES)
+ .writeTimeout(writeTimeout, TimeUnit.MINUTES)
+ .sslSocketFactory(anySslSocketFactory(), (X509TrustManager) trustAnyCerts[0])
+ .hostnameVerifier((s, sslSession) -> true)
+ .build();
+
+ private static SSLSocketFactory anySslSocketFactory(){
+ try {
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustAnyCerts, new SecureRandom());
+ return sslContext.getSocketFactory();
+ } catch (Exception ignore){
+ throw new ServiceException();
+ }
+ }
+
+ public static Response doHttp(Request request) {
+ return doHttp(okHttpClient, request);
+ }
+
+ @SneakyThrows
+ private static Response doHttp(OkHttpClient okHttpClient, Request request) {
+ return okHttpClient.newCall(request).execute();
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java
new file mode 100644
index 0000000..b8bd4bc
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/reflect/ReflectUtil.java
@@ -0,0 +1,22 @@
+package cd.casic.framework.commons.util.reflect;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+public class ReflectUtil {
+
+ public static Boolean isNativeType(Object bean) {
+ return bean instanceof Integer ||
+ bean instanceof Long ||
+ bean instanceof Double ||
+ bean instanceof Float ||
+ bean instanceof Short ||
+ bean instanceof Byte ||
+ bean instanceof Boolean;
+ }
+
+ public static Boolean isCollectionType(Object obj) {
+ return obj instanceof Map || obj instanceof Collection;
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java
new file mode 100644
index 0000000..34731c8
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/retry/RetryUtils.java
@@ -0,0 +1,33 @@
+package cd.casic.framework.commons.util.retry;
+
+import lombok.SneakyThrows;
+
+/**
+ * @author by mianbin
+ * @Classname RetryUtils
+ * @Description TODO
+ * @Date 2025/3/18 11:28
+ */
+public class RetryUtils {
+ @SneakyThrows
+ public static T execute(Action action, Integer retryTime, Long retryPeriodMills) {
+ try {
+ return action.execute();
+ } catch (Throwable ignored) {
+ if (retryTime - 1 <= 0) {
+ return action.fail(ignored);
+ }
+ Thread.sleep(retryPeriodMills);
+ return execute(action, retryTime - 1, 500L);
+ }
+ }
+
+ public interface Action {
+
+ T execute();
+
+ default T fail(Throwable e) throws Throwable {
+ throw e;
+ }
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java
index 3236d31..866781d 100644
--- a/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/string/StrUtils.java
@@ -63,7 +63,6 @@ public class StrUtils {
/**
* 移除字符串中,包含指定字符串的行
- *
* @param content 字符串
* @param sequence 包含的字符串
* @return 移除后的字符串
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java
new file mode 100644
index 0000000..ef71548
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/validation/ValidGroup.java
@@ -0,0 +1,21 @@
+package cd.casic.framework.commons.util.validation;
+
+/**
+ * @author by mianbin
+ * @Classname ValidGroup
+ * @Description 验证组
+ * @Date 2025/3/18 15:09
+ */
+public interface ValidGroup {
+ interface Create extends ValidGroup {
+ }
+
+ interface Update extends ValidGroup {
+ }
+
+ interface Delete extends ValidGroup {
+ }
+
+ interface Query extends ValidGroup {
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java
new file mode 100644
index 0000000..56da864
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/LogUtils.java
@@ -0,0 +1,44 @@
+package cd.casic.framework.commons.util.watcher;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author by mianbin
+ * @Classname LogUtils
+ * @Description 流水线和watcher监控日志的工具类,放一起
+ * @Date 2025/3/18 11:26
+ */
+@Slf4j
+public class LogUtils {
+
+ /**
+ * 计算[watcher].createTime与当前时间的毫秒数的耗时在[warnThreshold]与[errorThreshold]之间,
+ * 会将[watcher]序列化为字符串并打印到WARN日志,当超出[errorThreshold]会打印ERROR日志。否则什么都不会打印
+ */
+ public static void printCostTimeWE(Watcher watcher, Long warnThreshold, Long errorThreshold) {
+ watcher.stop();
+ long cost = System.currentTimeMillis() - watcher.getCreateTime();
+ if (cost >= warnThreshold) {
+ if (cost > errorThreshold) {
+ log.error(watcher + " cost " + cost + " ms");
+ } else {
+ log.warn(watcher + " cost " + cost + " ms");
+ }
+ }
+ }
+
+ public static void costTime(String message, Long startTime, Long warnThreshold, Long errorThreshold) {
+ long cost = System.currentTimeMillis() - startTime;
+ if (cost < warnThreshold) {
+ log.info(message + " cost " + cost + " ms");
+ } else if (cost >= warnThreshold && cost < errorThreshold) {
+ log.warn(message + " cost " + cost + " ms");
+ } else {
+ log.error(message + " cost " + cost + " ms");
+ }
+ }
+
+ public static void printCostTimeWE(Watcher watcher) {
+ printCostTimeWE(watcher, 1000L, 5000L);
+ }
+}
diff --git a/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java
new file mode 100644
index 0000000..29f79d5
--- /dev/null
+++ b/framework/commons/src/main/java/cd/casic/framework/commons/util/watcher/Watcher.java
@@ -0,0 +1,82 @@
+package cd.casic.framework.commons.util.watcher;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StopWatch;
+
+/**
+ * @author by mianbin
+ * @Classname Watcher
+ * @Description 针对running值导致抛出异常的位置主动做了stop,并增加了一个全部耗时统计
+ * @Date 2025/3/18 10:49
+ */
+@Slf4j
+public class Watcher extends StopWatch {
+
+ @Getter
+ private long createTime = System.currentTimeMillis();
+
+ public Watcher(String id) {
+ super(id);
+ this.createTime = System.currentTimeMillis();
+ }
+
+ public long elapsed() {
+ return System.currentTimeMillis() - createTime;
+ }
+
+ @Override
+ public void start() {
+ if (isRunning()) {
+ stop();
+ }
+ super.start();
+ }
+
+ @Override
+ public void start(String taskName) {
+ if (isRunning()) {
+ stop();
+ }
+ super.start(taskName);
+ }
+
+ @Override
+ public String toString() {
+ if (isRunning()) {
+ stop();
+ }
+ StringBuilder sb = new StringBuilder(shortSummary());
+ for (TaskInfo task : this.getTaskInfo()) {
+ sb.append("|").append(task.getTaskName()).append("=").append(task.getTimeMillis());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String shortSummary() {
+ return "watcher|" + getId() + "|total=" + getTotalTimeMillis() + "|elapsed=" + elapsed();
+ }
+
+ @Override
+ public void stop() {
+ if (isRunning()) {
+ try {
+ super.stop();
+ } catch (IllegalStateException ignored) {
+ }
+ }
+ }
+
+ public void safeAround(String taskName, Runnable action) {
+ try {
+ this.start(taskName);
+ action.run();
+ } catch (Exception e) {
+ log.warn(getId() + " , " + taskName, e);
+ } finally {
+ this.stop();
+ }
+ }
+
+}
diff --git a/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java b/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java
index bc3a2db..3795719 100644
--- a/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java
+++ b/framework/spring-boot-starter-monitor/src/main/java/cd/casic/framework/monitor/config/OpsTracerAutoConfiguration.java
@@ -22,7 +22,7 @@ import org.springframework.context.annotation.Bean;
@ConditionalOnProperty(prefix = "ops.tracer", value = "enable", matchIfMissing = true)
public class OpsTracerAutoConfiguration {
- // TODO 重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证阿里云短信 sdk
+ // TODO 重要。目前 opentracing 版本存在冲突,要么保证 skywalking,要么保证云短信 sdk
// @Bean
// public TracerProperties bizTracerProperties() {
// return new TracerProperties();
diff --git a/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java b/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java
index ee98c14..5376ed5 100644
--- a/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java
+++ b/framework/spring-boot-starter-mybatis/src/main/java/cd/casic/framework/mybatis/core/dataobject/BaseDO.java
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
*/
@Data
@Accessors(chain = true)
-@JsonIgnoreProperties(value = "transMap") // 由于 Easy-Trans 会添加 transMap 属性,避免 Jackson 在 Spring Cache 反序列化报错
+@JsonIgnoreProperties(value = "transMap")
public abstract class BaseDO implements Serializable, TransPojo {
/**
diff --git a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java
index bfcc9e7..c40c0a4 100644
--- a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java
+++ b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/config/OpsRedisAutoConfiguration.java
@@ -1,5 +1,6 @@
package cd.casic.framework.redis.config;
+import cd.casic.framework.redis.core.RedisTemplateUtils;
import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@@ -42,4 +43,9 @@ public class OpsRedisAutoConfiguration {
return json;
}
+ @Bean
+ public RedisTemplateUtils redisTemplateUtils() {
+ return new RedisTemplateUtils();
+ }
+
}
diff --git a/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java
new file mode 100644
index 0000000..53e6fb0
--- /dev/null
+++ b/framework/spring-boot-starter-redis/src/main/java/cd/casic/framework/redis/core/RedisTemplateUtils.java
@@ -0,0 +1,570 @@
+package cd.casic.framework.redis.core;
+
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author by mianbin
+ * @Classname RedisTemplateUtils
+ * @Description TODO
+ * @Date 2025/3/20 11:03
+ */
+public class RedisTemplateUtils {
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+
+ /**
+ * 指定缓存失效时间
+ *
+ * @param key 键
+ * @param time 时间(秒)
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 根据key 获取过期时间
+ *
+ * @param key 键 不能为null
+ * @return 时间(秒) 返回0代表为永久有效
+ */
+ public long getExpire(String key) {
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 判断key是否存在
+ *
+ * @param key 键
+ * @return true 存在 false不存在
+ */
+ public boolean hasKey(String key) {
+ try {
+ return Boolean.TRUE.equals(redisTemplate.hasKey(key));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 删除缓存
+ *
+ * @param key 可以传一个值 或多个
+ */
+ @SuppressWarnings("unchecked")
+ public void del(String... key) {
+ if (key != null && key.length > 0) {
+ if (key.length == 1) {
+ redisTemplate.delete(key[0]);
+ } else {
+ redisTemplate.delete((Collection) CollectionUtils.arrayToList(key));
+ }
+ }
+ }
+
+ //============================String=============================
+
+ /**
+ * 普通缓存获取
+ *
+ * @param key 键
+ * @return 值
+ */
+ public Object get(String key) {
+ return key == null ? null : redisTemplate.opsForValue().get(key);
+ }
+
+ /**
+ * 普通缓存放入
+ *
+ * @param key 键
+ * @param value 值
+ * @return true成功 false失败
+ */
+ public boolean set(String key, Object value) {
+ try {
+ redisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 普通缓存放入并设置时间
+ *
+ * @param key 键
+ * @param value 值
+ * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+ * @return true成功 false 失败
+ */
+ public boolean set(String key, Object value, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 递增
+ *
+ * @param key 键
+ * @param delta 要增加几(大于0)
+ * @return
+ */
+ public long incr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("递增因子必须大于0");
+ }
+ return redisTemplate.opsForValue().increment(key, delta);
+ }
+
+ /**
+ * 递减
+ *
+ * @param key 键
+ * @param delta 要减少几(小于0)
+ * @return
+ */
+ public long decr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("递减因子必须大于0");
+ }
+ return redisTemplate.opsForValue().increment(key, -delta);
+ }
+
+ //================================Map=================================
+
+ /**
+ * HashGet
+ *
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return 值
+ */
+ public Object hget(String key, String item) {
+ return redisTemplate.opsForHash().get(key, item);
+ }
+
+ /**
+ * 获取hashKey对应的所有键值
+ *
+ * @param key 键
+ * @return 对应的多个键值
+ */
+ public Map