From 34dccd1895015c1eeb948724c3a3756fbfa64fdc Mon Sep 17 00:00:00 2001 From: minglipro Date: Sun, 17 Aug 2025 19:12:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(utils):=20=E6=B7=BB=E5=8A=A0=20AES=20?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AesUtils 类,提供 AES/GCM 模式的加密解密方法- 更新 .prettierrc配置,将 useTabs 设置为 true - 重构 Base64Utils 和 Collection 类的代码结构- 简化 ComponentBean 注解定义 --- .prettierrc | 2 +- gradle.properties | 2 +- package.json | 24 +- src/com/mingliqiye/utils/Main.java | 71 +- src/com/mingliqiye/utils/aes/AesUtils.java | 112 +++ .../mingliqiye/utils/base64/Base64Utils.java | 294 +++---- src/com/mingliqiye/utils/bean/Factory.java | 423 +++++----- .../utils/bean/annotation/ComponentBean.java | 2 +- .../utils/bean/annotation/InjectBean.java | 2 +- .../utils/bean/springboot/SpringBeanUtil.java | 101 ++- .../utils/collection/Collection.java | 535 +++++++------ .../mingliqiye/utils/collection/ForEach.java | 358 ++++----- .../mingliqiye/utils/collection/Lists.java | 441 ++++++----- src/com/mingliqiye/utils/collection/Maps.java | 322 ++++---- src/com/mingliqiye/utils/collection/Sets.java | 246 +++--- .../utils/concurrent/IsChanged.java | 126 +-- .../utils/data/ThreadLocalDataHolder.java | 126 +-- src/com/mingliqiye/utils/file/FileUtil.java | 595 +++++++------- .../mingliqiye/utils/functions/Debouncer.java | 108 +-- src/com/mingliqiye/utils/hash/HashUtils.java | 135 ++-- src/com/mingliqiye/utils/http/Response.java | 56 +- .../utils/minecraft/slp/Description.java | 4 +- .../mingliqiye/utils/minecraft/slp/Extra.java | 8 +- .../minecraft/slp/MinecraftServerStatus.java | 14 +- .../utils/minecraft/slp/PlayerSample.java | 4 +- .../utils/minecraft/slp/Players.java | 6 +- .../mingliqiye/utils/minecraft/slp/SLP.java | 335 ++++---- .../utils/minecraft/slp/Version.java | 4 +- .../mingliqiye/utils/network/NetWorkUtil.java | 10 +- .../utils/network/NetworkAddress.java | 319 ++++---- .../utils/network/NetworkEndpoint.java | 231 +++--- .../utils/network/NetworkException.java | 32 +- .../mingliqiye/utils/network/NetworkPort.java | 53 +- .../mingliqiye/utils/string/StringUtil.java | 367 +++++---- .../mingliqiye/utils/system/SystemUtil.java | 323 ++++---- src/com/mingliqiye/utils/time/DateTime.java | 733 +++++++++--------- .../mingliqiye/utils/time/DateTimeOffset.java | 52 +- .../mingliqiye/utils/time/DateTimeUnit.java | 62 +- src/com/mingliqiye/utils/time/Formatter.java | 130 ++-- .../utils/time/serialization/Jackson.java | 305 ++++---- .../typehandlers/DateTimeTypeHandler.java | 167 ++-- .../mingliqiye/utils/uuid/MysqlUUIDv1.java | 66 ++ src/com/mingliqiye/utils/uuid/UUID.java | 430 +++++----- .../mingliqiye/utils/uuid/UUIDException.java | 12 +- .../utils/uuid/serialization/Jackson.java | 163 ++-- .../typehandlers/UUIDBinaryTypeHandler.java | 141 ++-- .../uuid/typehandlers/UUIDConverter.java | 31 + .../typehandlers/UUIDStringTypeHandler.java | 83 ++ 48 files changed, 4214 insertions(+), 3952 deletions(-) create mode 100644 src/com/mingliqiye/utils/aes/AesUtils.java create mode 100644 src/com/mingliqiye/utils/uuid/MysqlUUIDv1.java create mode 100644 src/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java create mode 100644 src/com/mingliqiye/utils/uuid/typehandlers/UUIDStringTypeHandler.java diff --git a/.prettierrc b/.prettierrc index 0d348b2..796a9cc 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,5 +4,5 @@ "prettier-plugin-java" ], "tabWidth": 4, - "useTabs": false + "useTabs": true } diff --git a/gradle.properties b/gradle.properties index 4d27044..074e616 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ JDKVERSIONS=1.8 GROUPSID=com.mingliqiye.utils ARTIFACTID=mingli-utils -VERSIONS=1.0.5 +VERSIONS=1.0.7 diff --git a/package.json b/package.json index 6f6039e..718cf04 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { - "name": "maven-repository", - "version": "1.0.0", - "scripts": { - "build": "gradle build-jar", - "buildw": "gradlew build-jar", - "format": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\"" - }, - "packageManager": "pnpm@10.4.1", - "devDependencies": { - "prettier-plugin-java": "^2.7.1", - "prettier": "^3.6.2" - } + "name": "maven-repository", + "version": "1.0.0", + "scripts": { + "build": "gradle build-jar", + "buildw": "gradlew build-jar", + "format": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\"" + }, + "packageManager": "pnpm@10.4.1", + "devDependencies": { + "prettier-plugin-java": "^2.7.1", + "prettier": "^3.6.2" + } } diff --git a/src/com/mingliqiye/utils/Main.java b/src/com/mingliqiye/utils/Main.java index 37b531a..ca60c5c 100644 --- a/src/com/mingliqiye/utils/Main.java +++ b/src/com/mingliqiye/utils/Main.java @@ -4,36 +4,49 @@ import com.mingliqiye.utils.collection.Lists; import com.mingliqiye.utils.string.StringUtil; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.Formatter; - import java.util.List; public class Main { - public static void main(String[] args) { - // 字符串工具使用示例 - System.out.println("=== 字符串工具使用示例 ==="); - String formatted = StringUtil.format("你好 {},今天是{}年{}月{}日", "张三", 2025, 7, 25); - System.out.println(formatted); - - List fruits = Lists.newArrayList("苹果", "香蕉", "橙子"); - String joined = StringUtil.join(", ", fruits); - System.out.println("水果列表: " + joined); - - // 时间工具使用示例 - System.out.println("\n=== 时间工具使用示例 ==="); - DateTime now = DateTime.now(); - System.out.println("当前时间: " + now); - System.out.println("标准格式: " + now.format(Formatter.STANDARD_DATETIME)); - - DateTime specificDate = DateTime.of(2025, 1, 1, 12, 0, 0); - System.out.println("指定时间: " + specificDate.format(Formatter.STANDARD_DATETIME)); - - // 集合工具使用示例 - System.out.println("\n=== 集合工具使用示例 ==="); - List numbers = Lists.newArrayList(10, 20, 30); - System.out.println("数字列表: " + numbers); - - List linkedList = Lists.newLinkedList("第一个", "第二个", "第三个"); - System.out.println("链表内容: " + linkedList); - } -} \ No newline at end of file + public static void main(String[] args) { + // 字符串工具使用示例 + System.out.println("=== 字符串工具使用示例 ==="); + String formatted = StringUtil.format( + "你好 {},今天是{}年{}月{}日", + "张三", + 2025, + 7, + 25 + ); + System.out.println(formatted); + + List fruits = Lists.newArrayList("苹果", "香蕉", "橙子"); + String joined = StringUtil.join(", ", fruits); + System.out.println("水果列表: " + joined); + + // 时间工具使用示例 + System.out.println("\n=== 时间工具使用示例 ==="); + DateTime now = DateTime.now(); + System.out.println("当前时间: " + now); + System.out.println( + "标准格式: " + now.format(Formatter.STANDARD_DATETIME) + ); + + DateTime specificDate = DateTime.of(2025, 1, 1, 12, 0, 0); + System.out.println( + "指定时间: " + specificDate.format(Formatter.STANDARD_DATETIME) + ); + + // 集合工具使用示例 + System.out.println("\n=== 集合工具使用示例 ==="); + List numbers = Lists.newArrayList(10, 20, 30); + System.out.println("数字列表: " + numbers); + + List linkedList = Lists.newLinkedList( + "第一个", + "第二个", + "第三个" + ); + System.out.println("链表内容: " + linkedList); + } +} diff --git a/src/com/mingliqiye/utils/aes/AesUtils.java b/src/com/mingliqiye/utils/aes/AesUtils.java new file mode 100644 index 0000000..5704c80 --- /dev/null +++ b/src/com/mingliqiye/utils/aes/AesUtils.java @@ -0,0 +1,112 @@ +package com.mingliqiye.utils.aes; + +import com.mingliqiye.utils.base64.Base64Utils; + +import javax.crypto.Cipher; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.SecureRandom; + +public class AesUtils { + + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/GCM/NoPadding"; + private static final int GCM_IV_LENGTH = 12; + private static final int GCM_TAG_LENGTH = 16; + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + + /** + * AES加密方法(使用GCM模式) + * @param sSrc 待加密的字符串 + * @param sKey 加密密钥 + * @return 加密后的字符串,格式为 IV:EncryptedData+Tag(均为Base64编码) + * @throws GeneralSecurityException 加密错误 + */ + public static String encrypt(String sSrc, String sKey) + throws GeneralSecurityException { + if (sKey == null) { + return null; + } + + // 生成密钥 + SecretKeySpec secretKeySpec = createSecretKey(sKey); + + // 生成安全随机IV + byte[] iv = new byte[GCM_IV_LENGTH]; + SECURE_RANDOM.nextBytes(iv); + + // 初始化加密器 + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec( + GCM_TAG_LENGTH * 8, + iv + ); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec); + + // 执行加密 + byte[] encrypted = cipher.doFinal( + sSrc.getBytes(StandardCharsets.UTF_8) + ); + + // 将IV和加密数据(包含认证标签)组合返回 + return Base64Utils.encode( + (Base64Utils.encode(iv) + + ":" + + Base64Utils.encode(encrypted)).getBytes() + ); + } + + /** + * AES解密方法(使用GCM模式) + * @param sSrc 待解密的字符串,格式为 IV:EncryptedData+Tag(均为Base64编码) + * @param sKey 解密密钥 + * @return 解密后的原始字符串 + */ + public static String decrypt(String sSrc, String sKey) { + if (sKey == null) { + return null; + } + + try { + // 分割IV和加密数据 + String sSrcs = new String(Base64Utils.decode(sSrc)); + String[] parts = sSrcs.split(":", 2); + if (parts.length != 2) { + return null; + } + byte[] iv = Base64Utils.decode(parts[0]); + byte[] encryptedData = Base64Utils.decode(parts[1]); + if (iv.length != GCM_IV_LENGTH) { + return null; + } + SecretKeySpec secretKeySpec = createSecretKey(sKey); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec( + GCM_TAG_LENGTH * 8, + iv + ); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec); + byte[] original = cipher.doFinal(encryptedData); + return new String(original, StandardCharsets.UTF_8); + } catch (Exception e) { + return null; + } + } + + /** + * 创建AES密钥,支持任意长度的密钥 + * @param sKey 字符串密钥 + * @return SecretKeySpec对象 + * @throws Exception 可能抛出的异常 + */ + private static SecretKeySpec createSecretKey(String sKey) + throws GeneralSecurityException { + byte[] key = sKey.getBytes(StandardCharsets.UTF_8); + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(key); + return new SecretKeySpec(digest, ALGORITHM); + } +} diff --git a/src/com/mingliqiye/utils/base64/Base64Utils.java b/src/com/mingliqiye/utils/base64/Base64Utils.java index 4184c80..d6b47b7 100644 --- a/src/com/mingliqiye/utils/base64/Base64Utils.java +++ b/src/com/mingliqiye/utils/base64/Base64Utils.java @@ -10,163 +10,163 @@ import java.util.Base64; */ public class Base64Utils { - // Base64编码器实例 - private static final Base64.Encoder BASE_64_ENCODER = Base64.getEncoder(); - // Base64解码器实例 - private static final Base64.Decoder BASE_64_DECODER = Base64.getDecoder(); + // Base64编码器实例 + private static final Base64.Encoder BASE_64_ENCODER = Base64.getEncoder(); + // Base64解码器实例 + private static final Base64.Decoder BASE_64_DECODER = Base64.getDecoder(); - /** - * 对字节数组进行Base64编码。 - * - * @param bytes 待编码的字节数组 - * @return 编码后的Base64字符串 - */ - public static String encode(byte[] bytes) { - return BASE_64_ENCODER.encodeToString(bytes); - } + /** + * 对字节数组进行Base64编码。 + * + * @param bytes 待编码的字节数组 + * @return 编码后的Base64字符串 + */ + public static String encode(byte[] bytes) { + return BASE_64_ENCODER.encodeToString(bytes); + } - /** - * 对文件内容进行Base64编码。 - * - * @param file 待编码的文件对象 - * @return 编码后的Base64字符串 - * @throws RuntimeException 如果读取文件时发生IO异常 - */ - public static String encode(File file) { - try { - byte[] bytes = java.nio.file.Files.readAllBytes(file.toPath()); - return encode(bytes); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + /** + * 对文件内容进行Base64编码。 + * + * @param file 待编码的文件对象 + * @return 编码后的Base64字符串 + * @throws RuntimeException 如果读取文件时发生IO异常 + */ + public static String encode(File file) { + try { + byte[] bytes = java.nio.file.Files.readAllBytes(file.toPath()); + return encode(bytes); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - /** - * 根据文件路径对文件内容进行Base64编码。 - * - * @param filePath 文件路径 - * @return 编码后的Base64字符串 - */ - public static String encode(String filePath) { - return encode(new File(filePath)); - } + /** + * 根据文件路径对文件内容进行Base64编码。 + * + * @param filePath 文件路径 + * @return 编码后的Base64字符串 + */ + public static String encode(String filePath) { + return encode(new File(filePath)); + } - /** - * 安全地对文件内容进行Base64编码,出错时返回null。 - * - * @param file 待编码的文件对象 - * @return 编码后的Base64字符串,出错时返回null - */ - public static String encodeSafe(File file) { - try { - return encode(file); - } catch (Exception e) { - return null; - } - } + /** + * 安全地对文件内容进行Base64编码,出错时返回null。 + * + * @param file 待编码的文件对象 + * @return 编码后的Base64字符串,出错时返回null + */ + public static String encodeSafe(File file) { + try { + return encode(file); + } catch (Exception e) { + return null; + } + } - /** - * 安全地根据文件路径对文件内容进行Base64编码,出错时返回null。 - * - * @param filePath 文件路径 - * @return 编码后的Base64字符串,出错时返回null - */ - public static String encodeSafe(String filePath) { - try { - return encode(filePath); - } catch (Exception e) { - return null; - } - } + /** + * 安全地根据文件路径对文件内容进行Base64编码,出错时返回null。 + * + * @param filePath 文件路径 + * @return 编码后的Base64字符串,出错时返回null + */ + public static String encodeSafe(String filePath) { + try { + return encode(filePath); + } catch (Exception e) { + return null; + } + } - /** - * 对Base64字符串进行解码。 - * - * @param base64 待解码的Base64字符串 - * @return 解码后的字节数组 - */ - public static byte[] decode(String base64) { - return BASE_64_DECODER.decode(base64); - } + /** + * 对Base64字符串进行解码。 + * + * @param base64 待解码的Base64字符串 + * @return 解码后的字节数组 + */ + public static byte[] decode(String base64) { + return BASE_64_DECODER.decode(base64); + } - /** - * 安全地对Base64字符串进行解码,出错时返回null。 - * - * @param base64 待解码的Base64字符串 - * @return 解码后的字节数组,出错时返回null - */ - public static byte[] decodeSafe(String base64) { - try { - return decode(base64); - } catch (Exception e) { - return null; - } - } + /** + * 安全地对Base64字符串进行解码,出错时返回null。 + * + * @param base64 待解码的Base64字符串 + * @return 解码后的字节数组,出错时返回null + */ + public static byte[] decodeSafe(String base64) { + try { + return decode(base64); + } catch (Exception e) { + return null; + } + } - /** - * 将Base64字符串解码并写入指定文件。 - * - * @param base64 待解码的Base64字符串 - * @param file 目标文件对象 - * @throws RuntimeException 如果写入文件时发生IO异常 - */ - public static void decodeToFile(String base64, File file) { - try (FileOutputStream fos = new FileOutputStream(file)) { - byte[] bytes = decode(base64); - fos.write(bytes); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + /** + * 将Base64字符串解码并写入指定文件。 + * + * @param base64 待解码的Base64字符串 + * @param file 目标文件对象 + * @throws RuntimeException 如果写入文件时发生IO异常 + */ + public static void decodeToFile(String base64, File file) { + try (FileOutputStream fos = new FileOutputStream(file)) { + byte[] bytes = decode(base64); + fos.write(bytes); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - /** - * 将Base64字符串解码并写入指定路径的文件。 - * - * @param base64 待解码的Base64字符串 - * @param filePath 目标文件路径 - */ - public static void decodeToFile(String base64, String filePath) { - decodeToFile(base64, new File(filePath)); - } + /** + * 将Base64字符串解码并写入指定路径的文件。 + * + * @param base64 待解码的Base64字符串 + * @param filePath 目标文件路径 + */ + public static void decodeToFile(String base64, String filePath) { + decodeToFile(base64, new File(filePath)); + } - /** - * 安全地将Base64字符串解码并写入指定文件,出错时返回false。 - * - * @param base64 待解码的Base64字符串 - * @param file 目标文件对象 - * @return 成功写入返回true,否则返回false - */ - public static boolean decodeToFileSafe(String base64, File file) { - try { - decodeToFile(base64, file); - return true; - } catch (Exception e) { - return false; - } - } + /** + * 安全地将Base64字符串解码并写入指定文件,出错时返回false。 + * + * @param base64 待解码的Base64字符串 + * @param file 目标文件对象 + * @return 成功写入返回true,否则返回false + */ + public static boolean decodeToFileSafe(String base64, File file) { + try { + decodeToFile(base64, file); + return true; + } catch (Exception e) { + return false; + } + } - /** - * 安全地将Base64字符串解码并写入指定路径的文件,出错时返回false。 - * - * @param base64 待解码的Base64字符串 - * @param filePath 目标文件路径 - * @return 成功写入返回true,否则返回false - */ - public static boolean decodeToFileSafe(String base64, String filePath) { - return decodeToFileSafe(base64, new File(filePath)); - } + /** + * 安全地将Base64字符串解码并写入指定路径的文件,出错时返回false。 + * + * @param base64 待解码的Base64字符串 + * @param filePath 目标文件路径 + * @return 成功写入返回true,否则返回false + */ + public static boolean decodeToFileSafe(String base64, String filePath) { + return decodeToFileSafe(base64, new File(filePath)); + } - /** - * 对字节数组中指定范围的数据进行Base64编码。 - * - * @param bytes 源字节数组 - * @param offset 起始偏移量 - * @param length 要编码的数据长度 - * @return 编码后的Base64字符串 - */ - public static String encodeBytes(byte[] bytes, int offset, int length) { - byte[] data = new byte[length]; - System.arraycopy(bytes, offset, data, 0, length); - return encode(data); - } + /** + * 对字节数组中指定范围的数据进行Base64编码。 + * + * @param bytes 源字节数组 + * @param offset 起始偏移量 + * @param length 要编码的数据长度 + * @return 编码后的Base64字符串 + */ + public static String encodeBytes(byte[] bytes, int offset, int length) { + byte[] data = new byte[length]; + System.arraycopy(bytes, offset, data, 0, length); + return encode(data); + } } diff --git a/src/com/mingliqiye/utils/bean/Factory.java b/src/com/mingliqiye/utils/bean/Factory.java index 039e709..d9a76cd 100644 --- a/src/com/mingliqiye/utils/bean/Factory.java +++ b/src/com/mingliqiye/utils/bean/Factory.java @@ -2,7 +2,6 @@ package com.mingliqiye.utils.bean; import com.mingliqiye.utils.bean.annotation.ComponentBean; import com.mingliqiye.utils.bean.annotation.InjectBean; - import java.io.File; import java.lang.reflect.Field; import java.net.URL; @@ -17,233 +16,233 @@ import java.util.concurrent.ConcurrentMap; */ public class Factory { - /** - * 存储所有已注册的Bean实例,键为Bean名称,值为Bean实例 - */ - public static final ConcurrentMap beans = - new ConcurrentHashMap<>(); + /** + * 存储所有已注册的Bean实例,键为Bean名称,值为Bean实例 + */ + public static final ConcurrentMap beans = + new ConcurrentHashMap<>(); - /** - * 存储按类型查找的Bean实例,键为Bean的Class对象,值为Bean实例 - */ - private static final ConcurrentMap, Object> typeBeans = - new ConcurrentHashMap<>(); + /** + * 存储按类型查找的Bean实例,键为Bean的Class对象,值为Bean实例 + */ + private static final ConcurrentMap, Object> typeBeans = + new ConcurrentHashMap<>(); - /** - * 私有构造函数,防止外部实例化该类 - */ - private Factory() {} + /** + * 私有构造函数,防止外部实例化该类 + */ + private Factory() {} - /** - * 自动扫描指定类所在包下的所有类并注册为Bean - * - * @param c 指定的类,用于获取其所在的包 - * @throws IllegalArgumentException 如果传入的类为null或位于默认包中 - */ - public static void autoScan(Class c) { - if (c == null) { - throw new IllegalArgumentException("Class cannot be null"); - } - Package pkg = c.getPackage(); - if (pkg == null) { - throw new IllegalArgumentException( - "Class is in the default package" - ); - } - scan(pkg.getName()); - } + /** + * 自动扫描指定类所在包下的所有类并注册为Bean + * + * @param c 指定的类,用于获取其所在的包 + * @throws IllegalArgumentException 如果传入的类为null或位于默认包中 + */ + public static void autoScan(Class c) { + if (c == null) { + throw new IllegalArgumentException("Class cannot be null"); + } + Package pkg = c.getPackage(); + if (pkg == null) { + throw new IllegalArgumentException( + "Class is in the default package" + ); + } + scan(pkg.getName()); + } - /** - * 扫描指定包路径下的所有类文件,并注册其中带有@ComponentBean注解的类为Bean - * - * @param basePackage 要扫描的基础包名 - * @throws RuntimeException 如果在扫描过程中发生异常 - */ - public static void scan(String basePackage) { - try { - String path = basePackage.replace('.', '/'); - ClassLoader classLoader = - Thread.currentThread().getContextClassLoader(); - Enumeration resources = null; - resources = classLoader.getResources(path); - while (resources.hasMoreElements()) { - URL resource = resources.nextElement(); - File file = new File(resource.toURI()); - scanDirectory(file, basePackage); - } - injectDependencies(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + /** + * 扫描指定包路径下的所有类文件,并注册其中带有@ComponentBean注解的类为Bean + * + * @param basePackage 要扫描的基础包名 + * @throws RuntimeException 如果在扫描过程中发生异常 + */ + public static void scan(String basePackage) { + try { + String path = basePackage.replace('.', '/'); + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader(); + Enumeration resources = null; + resources = classLoader.getResources(path); + while (resources.hasMoreElements()) { + URL resource = resources.nextElement(); + File file = new File(resource.toURI()); + scanDirectory(file, basePackage); + } + injectDependencies(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - /** - * 递归扫描目录中的所有类文件,并注册符合条件的类为Bean - * - * @param directory 当前要扫描的目录 - * @param packageName 当前目录对应的包名 - * @throws Exception 如果在扫描或类加载过程中发生异常 - */ - private static void scanDirectory(File directory, String packageName) - throws Exception { - File[] files = directory.listFiles(); - if (files == null) { - return; - } + /** + * 递归扫描目录中的所有类文件,并注册符合条件的类为Bean + * + * @param directory 当前要扫描的目录 + * @param packageName 当前目录对应的包名 + * @throws Exception 如果在扫描或类加载过程中发生异常 + */ + private static void scanDirectory(File directory, String packageName) + throws Exception { + File[] files = directory.listFiles(); + if (files == null) { + return; + } - for (File file : files) { - if (file.isDirectory()) { - scanDirectory(file, packageName + "." + file.getName()); - } else if (file.getName().endsWith(".class")) { - String className = - packageName + '.' + file.getName().replace(".class", ""); - registerComponent(Class.forName(className)); - } - } - } + for (File file : files) { + if (file.isDirectory()) { + scanDirectory(file, packageName + "." + file.getName()); + } else if (file.getName().endsWith(".class")) { + String className = + packageName + '.' + file.getName().replace(".class", ""); + registerComponent(Class.forName(className)); + } + } + } - /** - * 注册一个带有@ComponentBean注解的类为Bean实例 - * - * @param clazz 要注册的类 - * @throws Exception 如果在实例化类或处理注解时发生异常 - */ - private static void registerComponent(Class clazz) throws Exception { - if (clazz.isAnnotationPresent(ComponentBean.class)) { - ComponentBean component = clazz.getAnnotation(ComponentBean.class); - String name = component.value().isEmpty() - ? clazz.getName() - : component.value(); - Object instance = clazz.getDeclaredConstructor().newInstance(); - beans.put(name, instance); - typeBeans.put(clazz, instance); + /** + * 注册一个带有@ComponentBean注解的类为Bean实例 + * + * @param clazz 要注册的类 + * @throws Exception 如果在实例化类或处理注解时发生异常 + */ + private static void registerComponent(Class clazz) throws Exception { + if (clazz.isAnnotationPresent(ComponentBean.class)) { + ComponentBean component = clazz.getAnnotation(ComponentBean.class); + String name = component.value().isEmpty() + ? clazz.getName() + : component.value(); + Object instance = clazz.getDeclaredConstructor().newInstance(); + beans.put(name, instance); + typeBeans.put(clazz, instance); - for (Class interfaceClass : clazz.getInterfaces()) { - typeBeans.putIfAbsent(interfaceClass, instance); - } - } - } + for (Class interfaceClass : clazz.getInterfaces()) { + typeBeans.putIfAbsent(interfaceClass, instance); + } + } + } - /** - * 对所有已注册的Bean进行依赖注入处理 - * - * @throws Exception 如果在注入过程中发生异常 - */ - private static void injectDependencies() throws Exception { - for (Object bean : beans.values()) { - for (Field field : bean.getClass().getDeclaredFields()) { - if (field.isAnnotationPresent(InjectBean.class)) { - InjectBean inject = field.getAnnotation(InjectBean.class); - Object dependency = findDependency( - field.getType(), - inject.value() - ); - if (dependency == null) { - throw new IllegalStateException( - "No suitable dependency found for field " + - field.getName() + - " in class " + - bean.getClass().getName() - ); - } - field.setAccessible(true); - field.set(bean, dependency); - } - } - } - } + /** + * 对所有已注册的Bean进行依赖注入处理 + * + * @throws Exception 如果在注入过程中发生异常 + */ + private static void injectDependencies() throws Exception { + for (Object bean : beans.values()) { + for (Field field : bean.getClass().getDeclaredFields()) { + if (field.isAnnotationPresent(InjectBean.class)) { + InjectBean inject = field.getAnnotation(InjectBean.class); + Object dependency = findDependency( + field.getType(), + inject.value() + ); + if (dependency == null) { + throw new IllegalStateException( + "No suitable dependency found for field " + + field.getName() + + " in class " + + bean.getClass().getName() + ); + } + field.setAccessible(true); + field.set(bean, dependency); + } + } + } + } - /** - * 根据类型和名称查找对应的依赖实例 - * - * @param type 依赖的类型 - * @param name 依赖的名称(可为空) - * @return 找到的依赖实例,未找到则返回null - */ - private static Object findDependency(Class type, String name) { - if (!name.isEmpty()) { - return beans.get(name); - } + /** + * 根据类型和名称查找对应的依赖实例 + * + * @param type 依赖的类型 + * @param name 依赖的名称(可为空) + * @return 找到的依赖实例,未找到则返回null + */ + private static Object findDependency(Class type, String name) { + if (!name.isEmpty()) { + return beans.get(name); + } - Object dependency = typeBeans.get(type); - if (dependency != null) { - return dependency; - } + Object dependency = typeBeans.get(type); + if (dependency != null) { + return dependency; + } - for (Class interfaceType : typeBeans.keySet()) { - if (type.isAssignableFrom(interfaceType)) { - return typeBeans.get(interfaceType); - } - } + for (Class interfaceType : typeBeans.keySet()) { + if (type.isAssignableFrom(interfaceType)) { + return typeBeans.get(interfaceType); + } + } - return null; - } + return null; + } - /** - * 将一个对象添加到Bean容器中,使用其类名作为键 - * - * @param object 要添加的对象 - * @throws RuntimeException 如果在注入依赖时发生异常 - */ - public static void add(Object object) { - Class clazz = object.getClass(); - String name = clazz.getName(); - beans.put(name, object); - typeBeans.put(clazz, object); - try { - injectDependencies(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + /** + * 将一个对象添加到Bean容器中,使用其类名作为键 + * + * @param object 要添加的对象 + * @throws RuntimeException 如果在注入依赖时发生异常 + */ + public static void add(Object object) { + Class clazz = object.getClass(); + String name = clazz.getName(); + beans.put(name, object); + typeBeans.put(clazz, object); + try { + injectDependencies(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - /** - * 将一个对象以指定名称添加到Bean容器中 - * - * @param name Bean的名称 - * @param object 要添加的对象 - * @throws RuntimeException 如果在注入依赖时发生异常 - */ - public static void add(String name, Object object) { - beans.put(name, object); - typeBeans.put(object.getClass(), object); - try { - injectDependencies(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + /** + * 将一个对象以指定名称添加到Bean容器中 + * + * @param name Bean的名称 + * @param object 要添加的对象 + * @throws RuntimeException 如果在注入依赖时发生异常 + */ + public static void add(String name, Object object) { + beans.put(name, object); + typeBeans.put(object.getClass(), object); + try { + injectDependencies(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - /** - * 根据类型获取对应的Bean实例 - * - * @param objclass Bean的类型 - * @param Bean的泛型类型 - * @return 对应类型的Bean实例,未找到则返回null - */ - public static T get(Class objclass) { - return objclass.cast(typeBeans.get(objclass)); - } + /** + * 根据类型获取对应的Bean实例 + * + * @param objclass Bean的类型 + * @param Bean的泛型类型 + * @return 对应类型的Bean实例,未找到则返回null + */ + public static T get(Class objclass) { + return objclass.cast(typeBeans.get(objclass)); + } - /** - * 根据名称和类型获取对应的Bean实例 - * - * @param name Bean的名称 - * @param objclass Bean的类型 - * @param Bean的泛型类型 - * @return 对应名称和类型的Bean实例,未找到则返回null - */ - public static T get(String name, Class objclass) { - return objclass.cast(beans.get(name)); - } + /** + * 根据名称和类型获取对应的Bean实例 + * + * @param name Bean的名称 + * @param objclass Bean的类型 + * @param Bean的泛型类型 + * @return 对应名称和类型的Bean实例,未找到则返回null + */ + public static T get(String name, Class objclass) { + return objclass.cast(beans.get(name)); + } - /** - * 根据名称获取对应的Bean实例 - * - * @param name Bean的名称 - * @return 对应名称的Bean实例,未找到则返回null - */ - public static Object get(String name) { - return beans.get(name); - } + /** + * 根据名称获取对应的Bean实例 + * + * @param name Bean的名称 + * @return 对应名称的Bean实例,未找到则返回null + */ + public static Object get(String name) { + return beans.get(name); + } } diff --git a/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java b/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java index c594e9f..fd38118 100644 --- a/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java +++ b/src/com/mingliqiye/utils/bean/annotation/ComponentBean.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ComponentBean { - String value() default ""; + String value() default ""; } diff --git a/src/com/mingliqiye/utils/bean/annotation/InjectBean.java b/src/com/mingliqiye/utils/bean/annotation/InjectBean.java index be480d0..87ab334 100644 --- a/src/com/mingliqiye/utils/bean/annotation/InjectBean.java +++ b/src/com/mingliqiye/utils/bean/annotation/InjectBean.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectBean { - String value() default ""; + String value() default ""; } diff --git a/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java b/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java index d703662..0deb223 100644 --- a/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java +++ b/src/com/mingliqiye/utils/bean/springboot/SpringBeanUtil.java @@ -19,60 +19,57 @@ import org.springframework.stereotype.Component; @Component public class SpringBeanUtil implements ApplicationContextAware { - /** - * 获取applicationContext - */ - @Getter - private static ApplicationContext applicationContext; + /** + * 获取applicationContext + */ + @Getter + private static ApplicationContext applicationContext; - /** - * 通过bean名称获取Bean实例 - * - * @param name bean名称 - * @return bean实例对象 - */ - public static Object getBean(String name) { - return getApplicationContext().getBean(name); - } + /** + * 通过bean名称获取Bean实例 + * + * @param name bean名称 + * @return bean实例对象 + */ + public static Object getBean(String name) { + return getApplicationContext().getBean(name); + } - /** - * 通过bean类型获取Bean实例 - * - * @param clazz bean的Class类型 - * @param 泛型类型 - * @return 指定类型的bean实例 - */ - public static T getBean(Class clazz) { - return getApplicationContext().getBean(clazz); - } + /** + * 通过bean类型获取Bean实例 + * + * @param clazz bean的Class类型 + * @param 泛型类型 + * @return 指定类型的bean实例 + */ + public static T getBean(Class clazz) { + return getApplicationContext().getBean(clazz); + } - /** - * 通过bean名称和类型获取指定的Bean实例 - * - * @param name bean名称 - * @param clazz bean的Class类型 - * @param 泛型类型 - * @return 指定名称和类型的bean实例 - */ - public static T getBean(String name, Class clazz) { - return getApplicationContext().getBean(name, clazz); - } + /** + * 通过bean名称和类型获取指定的Bean实例 + * + * @param name bean名称 + * @param clazz bean的Class类型 + * @param 泛型类型 + * @return 指定名称和类型的bean实例 + */ + public static T getBean(String name, Class clazz) { + return getApplicationContext().getBean(name, clazz); + } - /** - * 设置ApplicationContext上下文对象 - * 当Spring容器初始化时会自动调用此方法,将ApplicationContext注入到本工具类中 - * 通过判断避免重复赋值,确保只设置一次ApplicationContext - * - * @param applicationContext Spring应用上下文对象 - * @throws BeansException bean异常 - */ - @Override - public void setApplicationContext( - @NotNull ApplicationContext applicationContext - ) throws BeansException { - // 避免重复赋值,确保只设置一次ApplicationContext - if (SpringBeanUtil.applicationContext == null) { - SpringBeanUtil.applicationContext = applicationContext; - } - } + /** + * 设置ApplicationContext上下文对象 + * 当Spring容器初始化时会自动调用此方法,将ApplicationContext注入到本工具类中 + * 通过判断避免重复赋值,确保只设置一次ApplicationContext + * + * @param applicationContext Spring应用上下文对象 + * @throws BeansException bean异常 + */ + @Override + public void setApplicationContext( + @NotNull ApplicationContext applicationContext + ) throws BeansException { + SpringBeanUtil.applicationContext = applicationContext; + } } diff --git a/src/com/mingliqiye/utils/collection/Collection.java b/src/com/mingliqiye/utils/collection/Collection.java index 3ed6e1f..369c254 100644 --- a/src/com/mingliqiye/utils/collection/Collection.java +++ b/src/com/mingliqiye/utils/collection/Collection.java @@ -1,13 +1,12 @@ package com.mingliqiye.utils.collection; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Predicate; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * 集合工具类,提供对列表和数组的常用操作方法。 @@ -16,289 +15,289 @@ import java.util.function.Predicate; */ public class Collection { - /** - * 获取集合的第一个元素。 - * - * @param collection 集合 - * @param 元素类型 - * @return 第一个元素;如果集合为空或为null则返回 null - */ - @Nullable - public static T getFirst(@Nullable java.util.Collection collection) { - if (collection == null || collection.isEmpty()) { - return null; - } + /** + * 获取集合的第一个元素。 + * + * @param collection 集合 + * @param 元素类型 + * @return 第一个元素;如果集合为空或为null则返回 null + */ + @Nullable + public static T getFirst(@Nullable java.util.Collection collection) { + if (collection == null || collection.isEmpty()) { + return null; + } - // 对于List类型,直接获取第一个元素 - if (collection instanceof List) { - return ((List) collection).get(0); - } + // 对于List类型,直接获取第一个元素 + if (collection instanceof List) { + return ((List) collection).get(0); + } - // 对于其他Collection类型,使用迭代器获取第一个元素 - return collection.iterator().next(); - } + // 对于其他Collection类型,使用迭代器获取第一个元素 + return collection.iterator().next(); + } - /** - * 获取数组的第一个元素。 - * - * @param list 数组,不能为空 - * @param 元素类型 - * @return 第一个元素;如果数组为空则返回 null - */ - @Nullable - public static T getFirst(@NotNull T[] list) { - if (list.length == 0) { - return null; - } - return list[0]; - } + /** + * 获取数组的第一个元素。 + * + * @param list 数组,不能为空 + * @param 元素类型 + * @return 第一个元素;如果数组为空则返回 null + */ + @Nullable + public static T getFirst(@NotNull T[] list) { + if (list.length == 0) { + return null; + } + return list[0]; + } - /** - * 获取集合的最后一个元素。 - * - * @param collection 集合 - * @param 元素类型 - * @return 最后一个元素;如果集合为空或为null则返回 null - */ - @Nullable - public static T getLast(@Nullable java.util.Collection collection) { - if (collection == null || collection.isEmpty()) { - return null; - } + /** + * 获取集合的最后一个元素。 + * + * @param collection 集合 + * @param 元素类型 + * @return 最后一个元素;如果集合为空或为null则返回 null + */ + @Nullable + public static T getLast(@Nullable java.util.Collection collection) { + if (collection == null || collection.isEmpty()) { + return null; + } - // 对于List类型,直接获取最后一个元素 - if (collection instanceof List) { - List list = (List) collection; - return list.get(list.size() - 1); - } + // 对于List类型,直接获取最后一个元素 + if (collection instanceof List) { + List list = (List) collection; + return list.get(list.size() - 1); + } - // 对于其他Collection类型,需要遍历到最后一个元素 - T lastElement = null; - for (T element : collection) { - lastElement = element; - } - return lastElement; - } + // 对于其他Collection类型,需要遍历到最后一个元素 + T lastElement = null; + for (T element : collection) { + lastElement = element; + } + return lastElement; + } - /** - * 获取数组的最后一个元素。 - * - * @param list 数组,不能为空 - * @param 元素类型 - * @return 最后一个元素;如果数组为空则返回 null - */ - @Nullable - public static T getLast(@NotNull T[] list) { - if (list.length == 0) { - return null; - } - return list[list.length - 1]; - } + /** + * 获取数组的最后一个元素。 + * + * @param list 数组,不能为空 + * @param 元素类型 + * @return 最后一个元素;如果数组为空则返回 null + */ + @Nullable + public static T getLast(@NotNull T[] list) { + if (list.length == 0) { + return null; + } + return list[list.length - 1]; + } - /** - * 获取列表中指定索引的元素,如果索引超出范围则返回默认值。 - * - * @param list 列表 - * @param index 索引 - * @param defaultValue 默认值 - * @param 元素类型 - * @return 指定索引的元素或默认值 - */ - @Nullable - public static T getOrDefault( - @NotNull List list, - int index, - @Nullable T defaultValue - ) { - if (index < 0 || index >= list.size()) { - return defaultValue; - } - return list.get(index); - } + /** + * 获取列表中指定索引的元素,如果索引超出范围则返回默认值。 + * + * @param list 列表 + * @param index 索引 + * @param defaultValue 默认值 + * @param 元素类型 + * @return 指定索引的元素或默认值 + */ + @Nullable + public static T getOrDefault( + @NotNull List list, + int index, + @Nullable T defaultValue + ) { + if (index < 0 || index >= list.size()) { + return defaultValue; + } + return list.get(index); + } - /** - * 获取数组中指定索引的元素,如果索引超出范围则返回默认值。 - * - * @param array 数组 - * @param index 索引 - * @param defaultValue 默认值 - * @param 元素类型 - * @return 指定索引的元素或默认值 - */ - @Nullable - public static T getOrDefault( - @NotNull T[] array, - int index, - @Nullable T defaultValue - ) { - if (index < 0 || index >= array.length) { - return defaultValue; - } - return array[index]; - } + /** + * 获取数组中指定索引的元素,如果索引超出范围则返回默认值。 + * + * @param array 数组 + * @param index 索引 + * @param defaultValue 默认值 + * @param 元素类型 + * @return 指定索引的元素或默认值 + */ + @Nullable + public static T getOrDefault( + @NotNull T[] array, + int index, + @Nullable T defaultValue + ) { + if (index < 0 || index >= array.length) { + return defaultValue; + } + return array[index]; + } - /** - * 获取列表的安全子列表,自动处理边界情况。 - * - * @param list 原始列表 - * @param fromIndex 起始索引(包含) - * @param toIndex 结束索引(不包含) - * @param 元素类型 - * @return 子列表 - */ - @NotNull - public static List safeSubList( - @NotNull List list, - int fromIndex, - int toIndex - ) { - int size = list.size(); - if (size == 0) { - return Collections.emptyList(); - } + /** + * 获取列表的安全子列表,自动处理边界情况。 + * + * @param list 原始列表 + * @param fromIndex 起始索引(包含) + * @param toIndex 结束索引(不包含) + * @param 元素类型 + * @return 子列表 + */ + @NotNull + public static List safeSubList( + @NotNull List list, + int fromIndex, + int toIndex + ) { + int size = list.size(); + if (size == 0) { + return Collections.emptyList(); + } - // 调整边界 - fromIndex = Math.max(0, fromIndex); - toIndex = Math.min(size, toIndex); - if (fromIndex >= toIndex) { - return Collections.emptyList(); - } + // 调整边界 + fromIndex = Math.max(0, fromIndex); + toIndex = Math.min(size, toIndex); + if (fromIndex >= toIndex) { + return Collections.emptyList(); + } - return list.subList(fromIndex, toIndex); - } + return list.subList(fromIndex, toIndex); + } - /** - * 判断列表是否为空或null。 - * - * @param list 待检查的列表 - * @return 如果列表为null或空则返回true,否则返回false - */ - public static boolean isEmpty(@Nullable List list) { - return list == null || list.isEmpty(); - } + /** + * 判断列表是否为空或null。 + * + * @param list 待检查的列表 + * @return 如果列表为null或空则返回true,否则返回false + */ + public static boolean isEmpty(@Nullable List list) { + return list == null || list.isEmpty(); + } - /** - * 判断数组是否为空或null。 - * - * @param array 待检查的数组 - * @return 如果数组为null或空则返回true,否则返回false - */ - public static boolean isEmpty(@Nullable Object[] array) { - return array == null || array.length == 0; - } + /** + * 判断数组是否为空或null。 + * + * @param array 待检查的数组 + * @return 如果数组为null或空则返回true,否则返回false + */ + public static boolean isEmpty(@Nullable Object[] array) { + return array == null || array.length == 0; + } - /** - * 查找列表中第一个满足条件的元素。 - * - * @param list 列表 - * @param predicate 条件谓词 - * @param 元素类型 - * @return 第一个满足条件的元素,如果没有则返回null - */ - @Nullable - public static T findFirst( - @NotNull List list, - @NotNull Predicate predicate - ) { - for (T item : list) { - if (predicate.test(item)) { - return item; - } - } - return null; - } + /** + * 查找列表中第一个满足条件的元素。 + * + * @param list 列表 + * @param predicate 条件谓词 + * @param 元素类型 + * @return 第一个满足条件的元素,如果没有则返回null + */ + @Nullable + public static T findFirst( + @NotNull List list, + @NotNull Predicate predicate + ) { + for (T item : list) { + if (predicate.test(item)) { + return item; + } + } + return null; + } - /** - * 查找数组中第一个满足条件的元素。 - * - * @param array 数组 - * @param predicate 条件谓词 - * @param 元素类型 - * @return 第一个满足条件的元素,如果没有则返回null - */ - @Nullable - public static T findFirst( - @NotNull T[] array, - @NotNull Predicate predicate - ) { - for (T item : array) { - if (predicate.test(item)) { - return item; - } - } - return null; - } + /** + * 查找数组中第一个满足条件的元素。 + * + * @param array 数组 + * @param predicate 条件谓词 + * @param 元素类型 + * @return 第一个满足条件的元素,如果没有则返回null + */ + @Nullable + public static T findFirst( + @NotNull T[] array, + @NotNull Predicate predicate + ) { + for (T item : array) { + if (predicate.test(item)) { + return item; + } + } + return null; + } - /** - * 过滤列表中满足条件的元素。 - * - * @param list 原始列表 - * @param predicate 条件谓词 - * @param 元素类型 - * @return 包含满足条件元素的新列表 - */ - @NotNull - public static List filter( - @NotNull List list, - @NotNull Predicate predicate - ) { - List result = new ArrayList<>(); - for (T item : list) { - if (predicate.test(item)) { - result.add(item); - } - } - return result; - } + /** + * 过滤列表中满足条件的元素。 + * + * @param list 原始列表 + * @param predicate 条件谓词 + * @param 元素类型 + * @return 包含满足条件元素的新列表 + */ + @NotNull + public static List filter( + @NotNull List list, + @NotNull Predicate predicate + ) { + List result = new ArrayList<>(); + for (T item : list) { + if (predicate.test(item)) { + result.add(item); + } + } + return result; + } - /** - * 过滤数组中满足条件的元素。 - * - * @param array 原始数组 - * @param predicate 条件谓词 - * @param 元素类型 - * @return 包含满足条件元素的新列表 - */ - @NotNull - public static List filter( - @NotNull T[] array, - @NotNull Predicate predicate - ) { - return filter(Arrays.asList(array), predicate); - } + /** + * 过滤数组中满足条件的元素。 + * + * @param array 原始数组 + * @param predicate 条件谓词 + * @param 元素类型 + * @return 包含满足条件元素的新列表 + */ + @NotNull + public static List filter( + @NotNull T[] array, + @NotNull Predicate predicate + ) { + return filter(Arrays.asList(array), predicate); + } - /** - * 将列表转换为数组。 - * - * @param list 列表 - * @param clazz 元素类型class - * @param 元素类型 - * @return 转换后的数组 - */ - @SuppressWarnings("unchecked") - @NotNull - public static T[] toArray( - @NotNull List list, - @NotNull Class clazz - ) { - T[] array = (T[]) java.lang.reflect.Array.newInstance( - clazz, - list.size() - ); - return list.toArray(array); - } + /** + * 将列表转换为数组。 + * + * @param list 列表 + * @param clazz 元素类型class + * @param 元素类型 + * @return 转换后的数组 + */ + @SuppressWarnings("unchecked") + @NotNull + public static T[] toArray( + @NotNull List list, + @NotNull Class clazz + ) { + T[] array = (T[]) java.lang.reflect.Array.newInstance( + clazz, + list.size() + ); + return list.toArray(array); + } - /** - * 将集合转换为列表。 - * - * @param collection 集合 - * @param 元素类型 - * @return 转换后的列表 - */ - @NotNull - public static List toList( - @NotNull java.util.Collection collection - ) { - return new ArrayList<>(collection); - } + /** + * 将集合转换为列表。 + * + * @param collection 集合 + * @param 元素类型 + * @return 转换后的列表 + */ + @NotNull + public static List toList( + @NotNull java.util.Collection collection + ) { + return new ArrayList<>(collection); + } } diff --git a/src/com/mingliqiye/utils/collection/ForEach.java b/src/com/mingliqiye/utils/collection/ForEach.java index 4b01623..1fc5763 100644 --- a/src/com/mingliqiye/utils/collection/ForEach.java +++ b/src/com/mingliqiye/utils/collection/ForEach.java @@ -10,192 +10,192 @@ import java.util.concurrent.ConcurrentMap; */ public class ForEach { - /** - * 对给定的集合执行指定的操作,操作包含元素值和索引。 - * 根据集合类型选择最优的遍历方式以提高性能。 - * - * @param collection 要遍历的集合,可以是 List 或其他 Collection 实现 - * @param action 要对每个元素执行的操作,接收元素值和索引作为参数 - * @param 集合中元素的类型 - */ - public static void forEach( - Collection collection, - ForEach.Consumer action - ) { - // 参数校验:如果集合或操作为空,则直接返回 - if (collection == null || action == null) { - return; - } + /** + * 对给定的集合执行指定的操作,操作包含元素值和索引。 + * 根据集合类型选择最优的遍历方式以提高性能。 + * + * @param collection 要遍历的集合,可以是 List 或其他 Collection 实现 + * @param action 要对每个元素执行的操作,接收元素值和索引作为参数 + * @param 集合中元素的类型 + */ + public static void forEach( + Collection collection, + ForEach.Consumer action + ) { + // 参数校验:如果集合或操作为空,则直接返回 + if (collection == null || action == null) { + return; + } - // 如果集合实现了 RandomAccess 接口(如 ArrayList),使用索引访问优化性能 - if (collection instanceof RandomAccess && collection instanceof List) { - List list = (List) collection; - for (int i = 0; i < list.size(); i++) { - action.call(list.get(i), i); - } - } - // 如果是普通 List,使用迭代器遍历并手动维护索引 - else if (collection instanceof List) { - int index = 0; - Iterator it = collection.iterator(); - while (it.hasNext()) { - action.call(it.next(), index); - index++; - } - } - // 其他类型的集合使用增强 for 循环,并手动维护索引 - else { - int index = 0; - for (T element : collection) { - action.call(element, index); - index++; - } - } - } + // 如果集合实现了 RandomAccess 接口(如 ArrayList),使用索引访问优化性能 + if (collection instanceof RandomAccess && collection instanceof List) { + List list = (List) collection; + for (int i = 0; i < list.size(); i++) { + action.call(list.get(i), i); + } + } + // 如果是普通 List,使用迭代器遍历并手动维护索引 + else if (collection instanceof List) { + int index = 0; + Iterator it = collection.iterator(); + while (it.hasNext()) { + action.call(it.next(), index); + index++; + } + } + // 其他类型的集合使用增强 for 循环,并手动维护索引 + else { + int index = 0; + for (T element : collection) { + action.call(element, index); + index++; + } + } + } - /** - * 对给定的集合执行指定的操作,仅处理元素值。 - * 根据集合是否实现 RandomAccess 接口选择最优的遍历方式。 - * - * @param collection 要遍历的集合 - * @param action 要对每个元素执行的操作,只接收元素值作为参数 - * @param 集合中元素的类型 - */ - public static void forEach( - Collection collection, - java.util.function.Consumer action - ) { - // 参数校验:如果集合或操作为空,则直接返回 - if (collection == null || action == null) { - return; - } + /** + * 对给定的集合执行指定的操作,仅处理元素值。 + * 根据集合是否实现 RandomAccess 接口选择最优的遍历方式。 + * + * @param collection 要遍历的集合 + * @param action 要对每个元素执行的操作,只接收元素值作为参数 + * @param 集合中元素的类型 + */ + public static void forEach( + Collection collection, + java.util.function.Consumer action + ) { + // 参数校验:如果集合或操作为空,则直接返回 + if (collection == null || action == null) { + return; + } - // 如果集合实现了 RandomAccess 接口,使用索引访问提升性能 - if (collection instanceof RandomAccess) { - List list = (List) collection; - for (int i = 0; i < list.size(); i++) { - action.accept(list.get(i)); - } - } - // 否则使用增强 for 循环进行遍历 - else { - for (T element : collection) { - action.accept(element); - } - } - } + // 如果集合实现了 RandomAccess 接口,使用索引访问提升性能 + if (collection instanceof RandomAccess) { + List list = (List) collection; + for (int i = 0; i < list.size(); i++) { + action.accept(list.get(i)); + } + } + // 否则使用增强 for 循环进行遍历 + else { + for (T element : collection) { + action.accept(element); + } + } + } - /** - * 对给定的映射执行指定的操作,操作包含键、值和索引。 - * 根据映射类型选择不同的遍历策略。 - * - * @param map 要遍历的映射 - * @param action 要对每个键值对执行的操作,接收键、值和索引作为参数 - * @param 映射中键的类型 - * @param 映射中值的类型 - */ - public static void forEach( - Map map, - BiConsumer action - ) { - // 参数校验:如果映射或操作为空,则直接返回 - if (map == null || action == null) { - return; - } + /** + * 对给定的映射执行指定的操作,操作包含键、值和索引。 + * 根据映射类型选择不同的遍历策略。 + * + * @param map 要遍历的映射 + * @param action 要对每个键值对执行的操作,接收键、值和索引作为参数 + * @param 映射中键的类型 + * @param 映射中值的类型 + */ + public static void forEach( + Map map, + BiConsumer action + ) { + // 参数校验:如果映射或操作为空,则直接返回 + if (map == null || action == null) { + return; + } - // 遍历 TreeMap 的条目集合并传递索引 - if (map instanceof TreeMap) { - int index = 0; - for (Map.Entry entry : map.entrySet()) { - action.call(entry.getKey(), entry.getValue(), index); - index++; - } - } - // 遍历 ConcurrentMap 或 LinkedHashMap 的条目集合并传递索引 - else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) { - int index = 0; - for (Map.Entry entry : map.entrySet()) { - action.call(entry.getKey(), entry.getValue(), index); - index++; - } - } - // 遍历其他类型映射的条目集合并传递索引 - else { - int index = 0; - for (Map.Entry entry : map.entrySet()) { - action.call(entry.getKey(), entry.getValue(), index); - index++; - } - } - } + // 遍历 TreeMap 的条目集合并传递索引 + if (map instanceof TreeMap) { + int index = 0; + for (Map.Entry entry : map.entrySet()) { + action.call(entry.getKey(), entry.getValue(), index); + index++; + } + } + // 遍历 ConcurrentMap 或 LinkedHashMap 的条目集合并传递索引 + else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) { + int index = 0; + for (Map.Entry entry : map.entrySet()) { + action.call(entry.getKey(), entry.getValue(), index); + index++; + } + } + // 遍历其他类型映射的条目集合并传递索引 + else { + int index = 0; + for (Map.Entry entry : map.entrySet()) { + action.call(entry.getKey(), entry.getValue(), index); + index++; + } + } + } - /** - * 对给定的映射执行指定的操作,仅处理键和值。 - * 根据映射类型选择不同的遍历策略。 - * - * @param map 要遍历的映射 - * @param action 要对每个键值对执行的操作,接收键和值作为参数 - * @param 映射中键的类型 - * @param 映射中值的类型 - */ - public static void forEach( - Map map, - java.util.function.BiConsumer action - ) { - // 参数校验:如果映射或操作为空,则直接返回 - if (map == null || action == null) { - return; - } + /** + * 对给定的映射执行指定的操作,仅处理键和值。 + * 根据映射类型选择不同的遍历策略。 + * + * @param map 要遍历的映射 + * @param action 要对每个键值对执行的操作,接收键和值作为参数 + * @param 映射中键的类型 + * @param 映射中值的类型 + */ + public static void forEach( + Map map, + java.util.function.BiConsumer action + ) { + // 参数校验:如果映射或操作为空,则直接返回 + if (map == null || action == null) { + return; + } - // 遍历 TreeMap 的条目集合 - if (map instanceof TreeMap) { - for (Map.Entry entry : map.entrySet()) { - action.accept(entry.getKey(), entry.getValue()); - } - } - // 如果是 ConcurrentMap 或 LinkedHashMap,使用其内置的 forEach 方法 - else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) { - map.forEach(action); - } - // 遍历其他类型映射的条目集合 - else { - for (Map.Entry entry : map.entrySet()) { - action.accept(entry.getKey(), entry.getValue()); - } - } - } + // 遍历 TreeMap 的条目集合 + if (map instanceof TreeMap) { + for (Map.Entry entry : map.entrySet()) { + action.accept(entry.getKey(), entry.getValue()); + } + } + // 如果是 ConcurrentMap 或 LinkedHashMap,使用其内置的 forEach 方法 + else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) { + map.forEach(action); + } + // 遍历其他类型映射的条目集合 + else { + for (Map.Entry entry : map.entrySet()) { + action.accept(entry.getKey(), entry.getValue()); + } + } + } - /** - * 自定义消费者接口,用于接收元素值和索引。 - * - * @param 元素类型 - */ - @FunctionalInterface - public interface Consumer { - /** - * 执行消费操作。 - * - * @param value 元素值 - * @param index 元素在集合中的索引 - */ - void call(T value, int index); - } + /** + * 自定义消费者接口,用于接收元素值和索引。 + * + * @param 元素类型 + */ + @FunctionalInterface + public interface Consumer { + /** + * 执行消费操作。 + * + * @param value 元素值 + * @param index 元素在集合中的索引 + */ + void call(T value, int index); + } - /** - * 自定义二元消费者接口,用于接收键、值和索引。 - * - * @param 键类型 - * @param 值类型 - */ - @FunctionalInterface - public interface BiConsumer { - /** - * 执行消费操作。 - * - * @param key 键 - * @param value 值 - * @param index 键值对在映射中的索引 - */ - void call(K key, V value, int index); - } + /** + * 自定义二元消费者接口,用于接收键、值和索引。 + * + * @param 键类型 + * @param 值类型 + */ + @FunctionalInterface + public interface BiConsumer { + /** + * 执行消费操作。 + * + * @param key 键 + * @param value 值 + * @param index 键值对在映射中的索引 + */ + void call(K key, V value, int index); + } } diff --git a/src/com/mingliqiye/utils/collection/Lists.java b/src/com/mingliqiye/utils/collection/Lists.java index 6b18597..34a3661 100644 --- a/src/com/mingliqiye/utils/collection/Lists.java +++ b/src/com/mingliqiye/utils/collection/Lists.java @@ -1,8 +1,7 @@ package com.mingliqiye.utils.collection; -import org.jetbrains.annotations.NotNull; - import java.util.*; +import org.jetbrains.annotations.NotNull; /** * Lists工具类提供了一系列创建List实现的便捷方法。 @@ -11,239 +10,239 @@ import java.util.*; */ public class Lists { - /** - * 创建一个空的ArrayList实例。 - * - * @param 列表元素的类型 - * @return 新创建的空ArrayList实例 - */ - public static List newArrayList() { - return new ArrayList<>(); - } + /** + * 创建一个空的ArrayList实例。 + * + * @param 列表元素的类型 + * @return 新创建的空ArrayList实例 + */ + public static List newArrayList() { + return new ArrayList<>(); + } - /** - * 根据可变参数创建一个包含指定元素的ArrayList实例。 - * - * @param ts 要添加到列表中的元素,可以为0个或多个 - * @param 列表元素的类型 - * @return 包含指定元素的新ArrayList实例 - */ - public static List newArrayList(T... ts) { - List list = newArrayList(); - list.addAll(Arrays.asList(ts)); - return list; - } + /** + * 根据可变参数创建一个包含指定元素的ArrayList实例。 + * + * @param ts 要添加到列表中的元素,可以为0个或多个 + * @param 列表元素的类型 + * @return 包含指定元素的新ArrayList实例 + */ + public static List newArrayList(T... ts) { + List list = newArrayList(); + list.addAll(Arrays.asList(ts)); + return list; + } - /** - * 根据已有列表创建一个新的ArrayList实例。 - * - * @param list 要复制的列表 - * @param 列表元素的类型 - * @return 包含原列表所有元素的新ArrayList实例 - */ - public static List newArrayList(List list) { - List newList = newArrayList(); - newList.addAll(list); - return newList; - } + /** + * 根据已有列表创建一个新的ArrayList实例。 + * + * @param list 要复制的列表 + * @param 列表元素的类型 + * @return 包含原列表所有元素的新ArrayList实例 + */ + public static List newArrayList(List list) { + List newList = newArrayList(); + newList.addAll(list); + return newList; + } - /** - * 根据可迭代对象创建一个ArrayList实例。 - * - * @param iterable 可迭代对象 - * @param 列表元素的类型 - * @return 包含可迭代对象中所有元素的新ArrayList实例 - */ - public static List newArrayList(Iterable iterable) { - List list = newArrayList(); - for (T t : iterable) { - list.add(t); - } - return list; - } + /** + * 根据可迭代对象创建一个ArrayList实例。 + * + * @param iterable 可迭代对象 + * @param 列表元素的类型 + * @return 包含可迭代对象中所有元素的新ArrayList实例 + */ + public static List newArrayList(Iterable iterable) { + List list = newArrayList(); + for (T t : iterable) { + list.add(t); + } + return list; + } - /** - * 创建一个指定初始容量的空ArrayList实例。 - * - * @param size 初始容量大小 - * @param 列表元素的类型 - * @return 指定初始容量的空ArrayList实例 - */ - public static List newArrayList(int size) { - return new ArrayList<>(size); - } + /** + * 创建一个指定初始容量的空ArrayList实例。 + * + * @param size 初始容量大小 + * @param 列表元素的类型 + * @return 指定初始容量的空ArrayList实例 + */ + public static List newArrayList(int size) { + return new ArrayList<>(size); + } - /** - * 创建一个指定大小并用单个元素填充的ArrayList实例。 - * - * @param size 列表大小 - * @param t 用于填充列表的元素 - * @param 列表元素的类型 - * @return 指定大小且所有元素都相同的ArrayList实例 - */ - public static List newArrayList(int size, T t) { - List list = newArrayList(size); - for (int i = 0; i < size; i++) { - list.add(t); - } - return list; - } + /** + * 创建一个指定大小并用单个元素填充的ArrayList实例。 + * + * @param size 列表大小 + * @param t 用于填充列表的元素 + * @param 列表元素的类型 + * @return 指定大小且所有元素都相同的ArrayList实例 + */ + public static List newArrayList(int size, T t) { + List list = newArrayList(size); + for (int i = 0; i < size; i++) { + list.add(t); + } + return list; + } - /** - * 创建一个指定大小并交替使用两个元素填充的ArrayList实例。 - * - * @param size 列表大小 - * @param t 第一个填充元素(索引为偶数时使用) - * @param t1 第二个填充元素(索引为奇数时使用) - * @param 列表元素的类型 - * @return 指定大小且交替填充两个元素的ArrayList实例 - */ - public static List newArrayList(int size, T t, T t1) { - List list = newArrayList(size); - for (int i = 0; i < size; i++) { - list.add(i % 2 == 0 ? t : t1); - } - return list; - } + /** + * 创建一个指定大小并交替使用两个元素填充的ArrayList实例。 + * + * @param size 列表大小 + * @param t 第一个填充元素(索引为偶数时使用) + * @param t1 第二个填充元素(索引为奇数时使用) + * @param 列表元素的类型 + * @return 指定大小且交替填充两个元素的ArrayList实例 + */ + public static List newArrayList(int size, T t, T t1) { + List list = newArrayList(size); + for (int i = 0; i < size; i++) { + list.add(i % 2 == 0 ? t : t1); + } + return list; + } - /** - * 创建一个指定大小并循环使用三个元素填充的ArrayList实例。 - * - * @param size 列表大小 - * @param t 第一个填充元素(索引模3等于0时使用) - * @param t1 第二个填充元素(索引模3等于1时使用) - * @param t2 第三个填充元素(索引模3等于2时使用) - * @param 列表元素的类型 - * @return 指定大小且循环填充三个元素的ArrayList实例 - */ - public static List newArrayList(int size, T t, T t1, T t2) { - List list = newArrayList(size); - for (int i = 0; i < size; i++) { - list.add(i % 3 == 0 ? t : i % 3 == 1 ? t1 : t2); - } - return list; - } + /** + * 创建一个指定大小并循环使用三个元素填充的ArrayList实例。 + * + * @param size 列表大小 + * @param t 第一个填充元素(索引模3等于0时使用) + * @param t1 第二个填充元素(索引模3等于1时使用) + * @param t2 第三个填充元素(索引模3等于2时使用) + * @param 列表元素的类型 + * @return 指定大小且循环填充三个元素的ArrayList实例 + */ + public static List newArrayList(int size, T t, T t1, T t2) { + List list = newArrayList(size); + for (int i = 0; i < size; i++) { + list.add(i % 3 == 0 ? t : i % 3 == 1 ? t1 : t2); + } + return list; + } - /** - * 创建一个指定大小并循环使用四个元素填充的ArrayList实例。 - * - * @param size 列表大小 - * @param t 第一个填充元素(索引模4等于0时使用) - * @param t1 第二个填充元素(索引模4等于1时使用) - * @param t2 第三个填充元素(索引模4等于2时使用) - * @param t3 第四个填充元素(索引模4等于3时使用) - * @param 列表元素的类型 - * @return 指定大小且循环填充四个元素的ArrayList实例 - */ - public static List newArrayList(int size, T t, T t1, T t2, T t3) { - List list = newArrayList(size); - for (int i = 0; i < size; i++) { - list.add(i % 4 == 0 ? t : i % 4 == 1 ? t1 : i % 4 == 2 ? t2 : t3); - } - return list; - } + /** + * 创建一个指定大小并循环使用四个元素填充的ArrayList实例。 + * + * @param size 列表大小 + * @param t 第一个填充元素(索引模4等于0时使用) + * @param t1 第二个填充元素(索引模4等于1时使用) + * @param t2 第三个填充元素(索引模4等于2时使用) + * @param t3 第四个填充元素(索引模4等于3时使用) + * @param 列表元素的类型 + * @return 指定大小且循环填充四个元素的ArrayList实例 + */ + public static List newArrayList(int size, T t, T t1, T t2, T t3) { + List list = newArrayList(size); + for (int i = 0; i < size; i++) { + list.add(i % 4 == 0 ? t : i % 4 == 1 ? t1 : i % 4 == 2 ? t2 : t3); + } + return list; + } - /** - * 创建一个空的LinkedList实例。 - * - * @param 列表元素的类型 - * @return 新创建的空LinkedList实例 - */ - public static List newLinkedList() { - return new LinkedList<>(); - } + /** + * 创建一个空的LinkedList实例。 + * + * @param 列表元素的类型 + * @return 新创建的空LinkedList实例 + */ + public static List newLinkedList() { + return new LinkedList<>(); + } - /** - * 根据可变参数创建一个包含指定元素的LinkedList实例。 - * - * @param ts 要添加到列表中的元素,可以为0个或多个 - * @param 列表元素的类型 - * @return 包含指定元素的新LinkedList实例 - */ - public static List newLinkedList(T... ts) { - List list = newLinkedList(); - list.addAll(Arrays.asList(ts)); - return list; - } + /** + * 根据可变参数创建一个包含指定元素的LinkedList实例。 + * + * @param ts 要添加到列表中的元素,可以为0个或多个 + * @param 列表元素的类型 + * @return 包含指定元素的新LinkedList实例 + */ + public static List newLinkedList(T... ts) { + List list = newLinkedList(); + list.addAll(Arrays.asList(ts)); + return list; + } - /** - * 根据已有列表创建一个新的LinkedList实例。 - * - * @param list 要复制的列表 - * @param 列表元素的类型 - * @return 包含原列表所有元素的新LinkedList实例 - */ - public static List newLinkedList(List list) { - List newList = newLinkedList(); - newList.addAll(list); - return newList; - } + /** + * 根据已有列表创建一个新的LinkedList实例。 + * + * @param list 要复制的列表 + * @param 列表元素的类型 + * @return 包含原列表所有元素的新LinkedList实例 + */ + public static List newLinkedList(List list) { + List newList = newLinkedList(); + newList.addAll(list); + return newList; + } - /** - * 创建一个空的Vector实例。 - * - * @param 列表元素的类型 - * @return 新创建的空Vector实例 - */ - public static List newVector() { - return new Vector<>(); - } + /** + * 创建一个空的Vector实例。 + * + * @param 列表元素的类型 + * @return 新创建的空Vector实例 + */ + public static List newVector() { + return new Vector<>(); + } - /** - * 根据可变参数创建一个包含指定元素的Vector实例。 - * - * @param ts 要添加到列表中的元素,可以为0个或多个 - * @param 列表元素的类型 - * @return 包含指定元素的新Vector实例 - */ - public static List newVector(T... ts) { - List list = newVector(); - list.addAll(Arrays.asList(ts)); - return list; - } + /** + * 根据可变参数创建一个包含指定元素的Vector实例。 + * + * @param ts 要添加到列表中的元素,可以为0个或多个 + * @param 列表元素的类型 + * @return 包含指定元素的新Vector实例 + */ + public static List newVector(T... ts) { + List list = newVector(); + list.addAll(Arrays.asList(ts)); + return list; + } - /** - * 根据已有列表创建一个新的Vector实例。 - * - * @param list 要复制的列表 - * @param 列表元素的类型 - * @return 包含原列表所有元素的新Vector实例 - */ - public static List newVector(List list) { - List newList = newVector(); - newList.addAll(list); - return newList; - } + /** + * 根据已有列表创建一个新的Vector实例。 + * + * @param list 要复制的列表 + * @param 列表元素的类型 + * @return 包含原列表所有元素的新Vector实例 + */ + public static List newVector(List list) { + List newList = newVector(); + newList.addAll(list); + return newList; + } - /** - * 将指定列表中的每个元素转换为字符串表示形式 - * - * @param 列表元素的类型 - * @param list 要转换的列表,不能为空 - * @return 包含原列表各元素字符串表示的新列表,保持相同的顺序 - */ - public static List toStringList(@NotNull List list) { - // 创建与原列表相同大小的新列表,用于存储字符串转换结果 - List newList = newArrayList(list.size()); - for (T t : list) { - newList.add(t == null ? "null" : t.toString()); - } - return newList; - } + /** + * 将指定列表中的每个元素转换为字符串表示形式 + * + * @param 列表元素的类型 + * @param list 要转换的列表,不能为空 + * @return 包含原列表各元素字符串表示的新列表,保持相同的顺序 + */ + public static List toStringList(@NotNull List list) { + // 创建与原列表相同大小的新列表,用于存储字符串转换结果 + List newList = newArrayList(list.size()); + for (T t : list) { + newList.add(t == null ? "null" : t.toString()); + } + return newList; + } - /** - * 将指定数组中的每个元素转换为字符串表示形式 - * - * @param 数组元素的类型 - * @param list 要转换的数组,不能为空 - * @return 包含原数组各元素字符串表示的新字符串数组 - */ - public static String[] toStringList(@NotNull T[] list) { - // 创建新的字符串列表,用于存储转换后的结果 - List newList = newArrayList(list.length); - for (T t : list) { - newList.add(t == null ? "null" : t.toString()); - } - return newList.toArray(new String[0]); - } + /** + * 将指定数组中的每个元素转换为字符串表示形式 + * + * @param 数组元素的类型 + * @param list 要转换的数组,不能为空 + * @return 包含原数组各元素字符串表示的新字符串数组 + */ + public static String[] toStringList(@NotNull T[] list) { + // 创建新的字符串列表,用于存储转换后的结果 + List newList = newArrayList(list.length); + for (T t : list) { + newList.add(t == null ? "null" : t.toString()); + } + return newList.toArray(new String[0]); + } } diff --git a/src/com/mingliqiye/utils/collection/Maps.java b/src/com/mingliqiye/utils/collection/Maps.java index da7b2fe..3342c6b 100644 --- a/src/com/mingliqiye/utils/collection/Maps.java +++ b/src/com/mingliqiye/utils/collection/Maps.java @@ -10,178 +10,178 @@ import java.util.concurrent.ConcurrentHashMap; */ public class Maps { - /** - * 创建一个空的HashMap实例。 - * - * @param Map键的类型 - * @param Map值的类型 - * @return 新创建的空HashMap实例 - */ - public static Map newHashMap() { - return new HashMap<>(); - } + /** + * 创建一个空的HashMap实例。 + * + * @param Map键的类型 + * @param Map值的类型 + * @return 新创建的空HashMap实例 + */ + public static Map newHashMap() { + return new HashMap<>(); + } - /** - * 创建一个指定初始容量的空HashMap实例。 - * - * @param size 初始容量大小 - * @param Map键的类型 - * @param Map值的类型 - * @return 指定初始容量的空HashMap实例 - */ - public static Map newHashMap(int size) { - return new HashMap<>(size); - } + /** + * 创建一个指定初始容量的空HashMap实例。 + * + * @param size 初始容量大小 + * @param Map键的类型 + * @param Map值的类型 + * @return 指定初始容量的空HashMap实例 + */ + public static Map newHashMap(int size) { + return new HashMap<>(size); + } - /** - * 根据已有Map创建一个新的HashMap实例。 - * - * @param map 要复制的Map - * @param Map键的类型 - * @param Map值的类型 - * @return 包含原Map所有元素的新HashMap实例 - */ - public static Map newHashMap(Map map) { - Map newMap = newHashMap(); - newMap.putAll(map); - return newMap; - } + /** + * 根据已有Map创建一个新的HashMap实例。 + * + * @param map 要复制的Map + * @param Map键的类型 + * @param Map值的类型 + * @return 包含原Map所有元素的新HashMap实例 + */ + public static Map newHashMap(Map map) { + Map newMap = newHashMap(); + newMap.putAll(map); + return newMap; + } - /** - * 创建一个空的LinkedHashMap实例。 - * - * @param Map键的类型 - * @param Map值的类型 - * @return 新创建的空LinkedHashMap实例 - */ - public static Map newLinkedHashMap() { - return new LinkedHashMap<>(); - } + /** + * 创建一个空的LinkedHashMap实例。 + * + * @param Map键的类型 + * @param Map值的类型 + * @return 新创建的空LinkedHashMap实例 + */ + public static Map newLinkedHashMap() { + return new LinkedHashMap<>(); + } - /** - * 创建一个指定初始容量的空LinkedHashMap实例。 - * - * @param size 初始容量大小 - * @param Map键的类型 - * @param Map值的类型 - * @return 指定初始容量的空LinkedHashMap实例 - */ - public static Map newLinkedHashMap(int size) { - return new LinkedHashMap<>(size); - } + /** + * 创建一个指定初始容量的空LinkedHashMap实例。 + * + * @param size 初始容量大小 + * @param Map键的类型 + * @param Map值的类型 + * @return 指定初始容量的空LinkedHashMap实例 + */ + public static Map newLinkedHashMap(int size) { + return new LinkedHashMap<>(size); + } - /** - * 根据已有Map创建一个新的LinkedHashMap实例。 - * - * @param map 要复制的Map - * @param Map键的类型 - * @param Map值的类型 - * @return 包含原Map所有元素的新LinkedHashMap实例 - */ - public static Map newLinkedHashMap(Map map) { - Map newMap = newLinkedHashMap(); - newMap.putAll(map); - return newMap; - } + /** + * 根据已有Map创建一个新的LinkedHashMap实例。 + * + * @param map 要复制的Map + * @param Map键的类型 + * @param Map值的类型 + * @return 包含原Map所有元素的新LinkedHashMap实例 + */ + public static Map newLinkedHashMap(Map map) { + Map newMap = newLinkedHashMap(); + newMap.putAll(map); + return newMap; + } - /** - * 创建一个空的TreeMap实例。 - * - * @param Map键的类型,必须实现Comparable接口 - * @param Map值的类型 - * @return 新创建的空TreeMap实例 - */ - public static , V> Map newTreeMap() { - return new TreeMap<>(); - } + /** + * 创建一个空的TreeMap实例。 + * + * @param Map键的类型,必须实现Comparable接口 + * @param Map值的类型 + * @return 新创建的空TreeMap实例 + */ + public static , V> Map newTreeMap() { + return new TreeMap<>(); + } - /** - * 根据已有Map创建一个新的TreeMap实例。 - * - * @param map 要复制的Map - * @param Map键的类型,必须实现Comparable接口 - * @param Map值的类型 - * @return 包含原Map所有元素的新TreeMap实例 - */ - public static , V> Map newTreeMap( - Map map - ) { - Map newMap = newTreeMap(); - newMap.putAll(map); - return newMap; - } + /** + * 根据已有Map创建一个新的TreeMap实例。 + * + * @param map 要复制的Map + * @param Map键的类型,必须实现Comparable接口 + * @param Map值的类型 + * @return 包含原Map所有元素的新TreeMap实例 + */ + public static , V> Map newTreeMap( + Map map + ) { + Map newMap = newTreeMap(); + newMap.putAll(map); + return newMap; + } - /** - * 创建一个空的Hashtable实例。 - * - * @param Map键的类型 - * @param Map值的类型 - * @return 新创建的空Hashtable实例 - */ - public static Map newHashtable() { - return new Hashtable<>(); - } + /** + * 创建一个空的Hashtable实例。 + * + * @param Map键的类型 + * @param Map值的类型 + * @return 新创建的空Hashtable实例 + */ + public static Map newHashtable() { + return new Hashtable<>(); + } - /** - * 创建一个指定初始容量的空Hashtable实例。 - * - * @param size 初始容量大小 - * @param Map键的类型 - * @param Map值的类型 - * @return 指定初始容量的空Hashtable实例 - */ - public static Map newHashtable(int size) { - return new Hashtable<>(size); - } + /** + * 创建一个指定初始容量的空Hashtable实例。 + * + * @param size 初始容量大小 + * @param Map键的类型 + * @param Map值的类型 + * @return 指定初始容量的空Hashtable实例 + */ + public static Map newHashtable(int size) { + return new Hashtable<>(size); + } - /** - * 根据已有Map创建一个新的Hashtable实例。 - * - * @param map 要复制的Map - * @param Map键的类型 - * @param Map值的类型 - * @return 包含原Map所有元素的新Hashtable实例 - */ - public static Map newHashtable(Map map) { - Map newMap = newHashtable(); - newMap.putAll(map); - return newMap; - } + /** + * 根据已有Map创建一个新的Hashtable实例。 + * + * @param map 要复制的Map + * @param Map键的类型 + * @param Map值的类型 + * @return 包含原Map所有元素的新Hashtable实例 + */ + public static Map newHashtable(Map map) { + Map newMap = newHashtable(); + newMap.putAll(map); + return newMap; + } - /** - * 创建一个空的ConcurrentHashMap实例。 - * - * @param Map键的类型 - * @param Map值的类型 - * @return 新创建的空ConcurrentHashMap实例 - */ - public static Map newConcurrentHashMap() { - return new ConcurrentHashMap<>(); - } + /** + * 创建一个空的ConcurrentHashMap实例。 + * + * @param Map键的类型 + * @param Map值的类型 + * @return 新创建的空ConcurrentHashMap实例 + */ + public static Map newConcurrentHashMap() { + return new ConcurrentHashMap<>(); + } - /** - * 创建一个指定初始容量的空ConcurrentHashMap实例。 - * - * @param size 初始容量大小 - * @param Map键的类型 - * @param Map值的类型 - * @return 指定初始容量的空ConcurrentHashMap实例 - */ - public static Map newConcurrentHashMap(int size) { - return new ConcurrentHashMap<>(size); - } + /** + * 创建一个指定初始容量的空ConcurrentHashMap实例。 + * + * @param size 初始容量大小 + * @param Map键的类型 + * @param Map值的类型 + * @return 指定初始容量的空ConcurrentHashMap实例 + */ + public static Map newConcurrentHashMap(int size) { + return new ConcurrentHashMap<>(size); + } - /** - * 根据已有Map创建一个新的ConcurrentHashMap实例。 - * - * @param map 要复制的Map - * @param Map键的类型 - * @param Map值的类型 - * @return 包含原Map所有元素的新ConcurrentHashMap实例 - */ - public static Map newConcurrentHashMap(Map map) { - Map newMap = newConcurrentHashMap(); - newMap.putAll(map); - return newMap; - } + /** + * 根据已有Map创建一个新的ConcurrentHashMap实例。 + * + * @param map 要复制的Map + * @param Map键的类型 + * @param Map值的类型 + * @return 包含原Map所有元素的新ConcurrentHashMap实例 + */ + public static Map newConcurrentHashMap(Map map) { + Map newMap = newConcurrentHashMap(); + newMap.putAll(map); + return newMap; + } } diff --git a/src/com/mingliqiye/utils/collection/Sets.java b/src/com/mingliqiye/utils/collection/Sets.java index 6a457af..d638461 100644 --- a/src/com/mingliqiye/utils/collection/Sets.java +++ b/src/com/mingliqiye/utils/collection/Sets.java @@ -9,137 +9,137 @@ import java.util.*; */ public class Sets { - /** - * 创建一个空的HashSet实例。 - * - * @param 集合元素的类型 - * @return 新创建的空HashSet实例 - */ - public static Set newHashSet() { - return new HashSet<>(); - } + /** + * 创建一个空的HashSet实例。 + * + * @param 集合元素的类型 + * @return 新创建的空HashSet实例 + */ + public static Set newHashSet() { + return new HashSet<>(); + } - /** - * 根据可变参数创建一个包含指定元素的HashSet实例。 - * - * @param ts 要添加到集合中的元素,可以为0个或多个 - * @param 集合元素的类型 - * @return 包含指定元素的新HashSet实例 - */ - public static Set newHashSet(T... ts) { - Set set = newHashSet(); - set.addAll(Arrays.asList(ts)); - return set; - } + /** + * 根据可变参数创建一个包含指定元素的HashSet实例。 + * + * @param ts 要添加到集合中的元素,可以为0个或多个 + * @param 集合元素的类型 + * @return 包含指定元素的新HashSet实例 + */ + public static Set newHashSet(T... ts) { + Set set = newHashSet(); + set.addAll(Arrays.asList(ts)); + return set; + } - /** - * 根据已有集合创建一个新的HashSet实例。 - * - * @param set 要复制的集合 - * @param 集合元素的类型 - * @return 包含原集合所有元素的新HashSet实例 - */ - public static Set newHashSet(Set set) { - Set newSet = newHashSet(); - newSet.addAll(set); - return newSet; - } + /** + * 根据已有集合创建一个新的HashSet实例。 + * + * @param set 要复制的集合 + * @param 集合元素的类型 + * @return 包含原集合所有元素的新HashSet实例 + */ + public static Set newHashSet(Set set) { + Set newSet = newHashSet(); + newSet.addAll(set); + return newSet; + } - /** - * 根据可迭代对象创建一个HashSet实例。 - * - * @param iterable 可迭代对象 - * @param 集合元素的类型 - * @return 包含可迭代对象中所有元素的新HashSet实例 - */ - public static Set newHashSet(Iterable iterable) { - Set set = newHashSet(); - for (T t : iterable) { - set.add(t); - } - return set; - } + /** + * 根据可迭代对象创建一个HashSet实例。 + * + * @param iterable 可迭代对象 + * @param 集合元素的类型 + * @return 包含可迭代对象中所有元素的新HashSet实例 + */ + public static Set newHashSet(Iterable iterable) { + Set set = newHashSet(); + for (T t : iterable) { + set.add(t); + } + return set; + } - /** - * 创建一个指定初始容量的空HashSet实例。 - * - * @param size 初始容量大小 - * @param 集合元素的类型 - * @return 指定初始容量的空HashSet实例 - */ - public static Set newHashSet(int size) { - return new HashSet<>(size); - } + /** + * 创建一个指定初始容量的空HashSet实例。 + * + * @param size 初始容量大小 + * @param 集合元素的类型 + * @return 指定初始容量的空HashSet实例 + */ + public static Set newHashSet(int size) { + return new HashSet<>(size); + } - /** - * 创建一个空的LinkedHashSet实例。 - * - * @param 集合元素的类型 - * @return 新创建的空LinkedHashSet实例 - */ - public static Set newLinkedHashSet() { - return new LinkedHashSet<>(); - } + /** + * 创建一个空的LinkedHashSet实例。 + * + * @param 集合元素的类型 + * @return 新创建的空LinkedHashSet实例 + */ + public static Set newLinkedHashSet() { + return new LinkedHashSet<>(); + } - /** - * 根据可变参数创建一个包含指定元素的LinkedHashSet实例。 - * - * @param ts 要添加到集合中的元素,可以为0个或多个 - * @param 集合元素的类型 - * @return 包含指定元素的新LinkedHashSet实例 - */ - public static Set newLinkedHashSet(T... ts) { - Set set = newLinkedHashSet(); - set.addAll(Arrays.asList(ts)); - return set; - } + /** + * 根据可变参数创建一个包含指定元素的LinkedHashSet实例。 + * + * @param ts 要添加到集合中的元素,可以为0个或多个 + * @param 集合元素的类型 + * @return 包含指定元素的新LinkedHashSet实例 + */ + public static Set newLinkedHashSet(T... ts) { + Set set = newLinkedHashSet(); + set.addAll(Arrays.asList(ts)); + return set; + } - /** - * 根据已有集合创建一个新的LinkedHashSet实例。 - * - * @param set 要复制的集合 - * @param 集合元素的类型 - * @return 包含原集合所有元素的新LinkedHashSet实例 - */ - public static Set newLinkedHashSet(Set set) { - Set newSet = newLinkedHashSet(); - newSet.addAll(set); - return newSet; - } + /** + * 根据已有集合创建一个新的LinkedHashSet实例。 + * + * @param set 要复制的集合 + * @param 集合元素的类型 + * @return 包含原集合所有元素的新LinkedHashSet实例 + */ + public static Set newLinkedHashSet(Set set) { + Set newSet = newLinkedHashSet(); + newSet.addAll(set); + return newSet; + } - /** - * 创建一个空的TreeSet实例。 - * - * @param 集合元素的类型,必须实现Comparable接口 - * @return 新创建的空TreeSet实例 - */ - public static > Set newTreeSet() { - return new TreeSet<>(); - } + /** + * 创建一个空的TreeSet实例。 + * + * @param 集合元素的类型,必须实现Comparable接口 + * @return 新创建的空TreeSet实例 + */ + public static > Set newTreeSet() { + return new TreeSet<>(); + } - /** - * 根据可变参数创建一个包含指定元素的TreeSet实例。 - * - * @param ts 要添加到集合中的元素,可以为0个或多个 - * @param 集合元素的类型,必须实现Comparable接口 - * @return 包含指定元素的新TreeSet实例 - */ - public static > Set newTreeSet(T... ts) { - Set set = newTreeSet(); - set.addAll(Arrays.asList(ts)); - return set; - } + /** + * 根据可变参数创建一个包含指定元素的TreeSet实例。 + * + * @param ts 要添加到集合中的元素,可以为0个或多个 + * @param 集合元素的类型,必须实现Comparable接口 + * @return 包含指定元素的新TreeSet实例 + */ + public static > Set newTreeSet(T... ts) { + Set set = newTreeSet(); + set.addAll(Arrays.asList(ts)); + return set; + } - /** - * 根据已有集合创建一个新的TreeSet实例。 - * - * @param set 要复制的集合 - * @param 集合元素的类型,必须实现Comparable接口 - * @return 包含原集合所有元素的新TreeSet实例 - */ - public static > Set newTreeSet(Set set) { - Set newSet = newTreeSet(); - newSet.addAll(set); - return newSet; - } + /** + * 根据已有集合创建一个新的TreeSet实例。 + * + * @param set 要复制的集合 + * @param 集合元素的类型,必须实现Comparable接口 + * @return 包含原集合所有元素的新TreeSet实例 + */ + public static > Set newTreeSet(Set set) { + Set newSet = newTreeSet(); + newSet.addAll(set); + return newSet; + } } diff --git a/src/com/mingliqiye/utils/concurrent/IsChanged.java b/src/com/mingliqiye/utils/concurrent/IsChanged.java index 4ed7fa4..82b4600 100644 --- a/src/com/mingliqiye/utils/concurrent/IsChanged.java +++ b/src/com/mingliqiye/utils/concurrent/IsChanged.java @@ -12,73 +12,73 @@ import java.util.concurrent.atomic.AtomicReference; */ public class IsChanged { - /** - * 使用 AtomicReference 来保证对数据的原子操作 - */ - private final AtomicReference atomicReferenceData; + /** + * 使用 AtomicReference 来保证对数据的原子操作 + */ + private final AtomicReference atomicReferenceData; - /** - * 默认构造函数,初始化数据为 null - */ - public IsChanged() { - this(null); - } + /** + * 默认构造函数,初始化数据为 null + */ + public IsChanged() { + this(null); + } - /** - * 带参数的构造函数,使用指定的初始值初始化 - * - * @param data 初始数据值 - */ - public IsChanged(T data) { - atomicReferenceData = new AtomicReference<>(data); - } + /** + * 带参数的构造函数,使用指定的初始值初始化 + * + * @param data 初始数据值 + */ + public IsChanged(T data) { + atomicReferenceData = new AtomicReference<>(data); + } - /** - * 设置新的数据值,不检查是否发生变化 - * - * @param data 要设置的新数据值 - */ - public void set(T data) { - atomicReferenceData.set(data); - } + /** + * 设置新的数据值,不检查是否发生变化 + * + * @param data 要设置的新数据值 + */ + public void set(T data) { + atomicReferenceData.set(data); + } - /** - * 获取当前数据值 - * - * @return 当前数据值 - */ - public T get() { - return atomicReferenceData.get(); - } + /** + * 获取当前数据值 + * + * @return 当前数据值 + */ + public T get() { + return atomicReferenceData.get(); + } - /** - * 设置新的数据值并返回旧的数据值 - * - * @param data 要设置的新数据值 - * @return 设置前的旧数据值 - */ - public T setAndGet(T data) { - return atomicReferenceData.getAndSet(data); - } + /** + * 设置新的数据值并返回旧的数据值 + * + * @param data 要设置的新数据值 + * @return 设置前的旧数据值 + */ + public T setAndGet(T data) { + return atomicReferenceData.getAndSet(data); + } - /** - * 设置新的数据值,如果新值与当前值不同则更新并返回 true,否则返回 false - * 使用 CAS(Compare-And-Swap) 操作确保线程安全 - * - * @param data 要设置的新数据值 - * @return 如果值发生变化返回 true,否则返回 false - */ - public boolean setAndChanged(T data) { - T currentData; - do { - currentData = get(); - // 如果新值与当前值相等,则认为没有变化,直接返回 false - if (Objects.equals(data, currentData)) { - return false; - } - // 使用 CAS 操作尝试更新值,如果失败则重试 - } while (!atomicReferenceData.compareAndSet(currentData, data)); - // 成功更新值,返回 true 表示发生了变化 - return true; - } + /** + * 设置新的数据值,如果新值与当前值不同则更新并返回 true,否则返回 false + * 使用 CAS(Compare-And-Swap) 操作确保线程安全 + * + * @param data 要设置的新数据值 + * @return 如果值发生变化返回 true,否则返回 false + */ + public boolean setAndChanged(T data) { + T currentData; + do { + currentData = get(); + // 如果新值与当前值相等,则认为没有变化,直接返回 false + if (Objects.equals(data, currentData)) { + return false; + } + // 使用 CAS 操作尝试更新值,如果失败则重试 + } while (!atomicReferenceData.compareAndSet(currentData, data)); + // 成功更新值,返回 true 表示发生了变化 + return true; + } } diff --git a/src/com/mingliqiye/utils/data/ThreadLocalDataHolder.java b/src/com/mingliqiye/utils/data/ThreadLocalDataHolder.java index 99014a5..2f67369 100644 --- a/src/com/mingliqiye/utils/data/ThreadLocalDataHolder.java +++ b/src/com/mingliqiye/utils/data/ThreadLocalDataHolder.java @@ -10,74 +10,74 @@ package com.mingliqiye.utils.data; */ public class ThreadLocalDataHolder { - private final ThreadLocal threadLocal; + private final ThreadLocal threadLocal; - /** - * 构造函数,初始化 ThreadLocal 实例 - */ - public ThreadLocalDataHolder() { - this.threadLocal = new ThreadLocal<>(); - } + /** + * 构造函数,初始化 ThreadLocal 实例 + */ + public ThreadLocalDataHolder() { + this.threadLocal = new ThreadLocal<>(); + } - /** - * 获取当前线程存储的值 - * - * @return 当前线程存储的值,如果没有则返回null - */ - public T get() { - return threadLocal.get(); - } + /** + * 获取当前线程存储的值 + * + * @return 当前线程存储的值,如果没有则返回null + */ + public T get() { + return threadLocal.get(); + } - /** - * 设置当前线程的值 - * - * @param value 要存储的值 - */ - public void set(T value) { - threadLocal.set(value); - } + /** + * 设置当前线程的值 + * + * @param value 要存储的值 + */ + public void set(T value) { + threadLocal.set(value); + } - /** - * 移除当前线程存储的值 - *

- * 防止内存泄漏,使用完毕后应调用此方法清理资源。 - */ - public void remove() { - threadLocal.remove(); - } + /** + * 移除当前线程存储的值 + *

+ * 防止内存泄漏,使用完毕后应调用此方法清理资源。 + */ + public void remove() { + threadLocal.remove(); + } - /** - * 获取当前线程存储的值,如果不存在则返回默认值 - * - * @param defaultValue 默认值 - * @return 当前线程存储的值或默认值 - */ - public T getOrDefault(T defaultValue) { - T value = threadLocal.get(); - return value != null ? value : defaultValue; - } + /** + * 获取当前线程存储的值,如果不存在则返回默认值 + * + * @param defaultValue 默认值 + * @return 当前线程存储的值或默认值 + */ + public T getOrDefault(T defaultValue) { + T value = threadLocal.get(); + return value != null ? value : defaultValue; + } - /** - * 安全获取值(避免NPE) - *

- * 在某些异常情况下防止抛出异常,直接返回 null。 - * - * @return 值或null - */ - public T safeGet() { - try { - return threadLocal.get(); - } catch (Exception e) { - return null; - } - } + /** + * 安全获取值(避免NPE) + *

+ * 在某些异常情况下防止抛出异常,直接返回 null。 + * + * @return 值或null + */ + public T safeGet() { + try { + return threadLocal.get(); + } catch (Exception e) { + return null; + } + } - /** - * 检查当前线程是否有值 - * - * @return 是否有值 - */ - public boolean isPresent() { - return threadLocal.get() != null; - } + /** + * 检查当前线程是否有值 + * + * @return 是否有值 + */ + public boolean isPresent() { + return threadLocal.get() != null; + } } diff --git a/src/com/mingliqiye/utils/file/FileUtil.java b/src/com/mingliqiye/utils/file/FileUtil.java index 7c3f52d..2f81005 100644 --- a/src/com/mingliqiye/utils/file/FileUtil.java +++ b/src/com/mingliqiye/utils/file/FileUtil.java @@ -1,9 +1,6 @@ package com.mingliqiye.utils.file; import com.mingliqiye.utils.string.StringUtil; -import lombok.Getter; -import lombok.Setter; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -15,6 +12,8 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; /** * 文件工具类,提供常用的文件操作方法 @@ -23,322 +22,322 @@ import java.util.List; */ public class FileUtil { - /** - * 默认字符集 - */ - @Getter - @Setter - private static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + /** + * 默认字符集 + */ + @Getter + @Setter + private static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; - /** - * 读取文件内容为字符串 - * - * @param filePath 文件路径 - * @return 文件内容字符串 - * @throws IOException 读取文件时发生错误 - */ - public static String readFileToString(String filePath) throws IOException { - return readFileToString(filePath, DEFAULT_CHARSET); - } + /** + * 读取文件内容为字符串 + * + * @param filePath 文件路径 + * @return 文件内容字符串 + * @throws IOException 读取文件时发生错误 + */ + public static String readFileToString(String filePath) throws IOException { + return readFileToString(filePath, DEFAULT_CHARSET); + } - /** - * 读取文件内容为字符串 - * - * @param filePath 文件路径 - * @param charset 字符集 - * @return 文件内容字符串 - * @throws IOException 读取文件时发生错误 - */ - public static String readFileToString(String filePath, Charset charset) - throws IOException { - Path path = Paths.get(filePath); - byte[] bytes = Files.readAllBytes(path); - return new String(bytes, charset); - } + /** + * 读取文件内容为字符串 + * + * @param filePath 文件路径 + * @param charset 字符集 + * @return 文件内容字符串 + * @throws IOException 读取文件时发生错误 + */ + public static String readFileToString(String filePath, Charset charset) + throws IOException { + Path path = Paths.get(filePath); + byte[] bytes = Files.readAllBytes(path); + return new String(bytes, charset); + } - /** - * 将字符串写入文件 - * - * @param filePath 文件路径 - * @param content 要写入的内容 - * @throws IOException 写入文件时发生错误 - */ - public static void writeStringToFile(String filePath, String content) - throws IOException { - writeStringToFile(filePath, content, DEFAULT_CHARSET); - } + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 要写入的内容 + * @throws IOException 写入文件时发生错误 + */ + public static void writeStringToFile(String filePath, String content) + throws IOException { + writeStringToFile(filePath, content, DEFAULT_CHARSET); + } - /** - * 将字符串写入文件 - * - * @param filePath 文件路径 - * @param content 要写入的内容 - * @param charset 字符集 - * @throws IOException 写入文件时发生错误 - */ - public static void writeStringToFile( - String filePath, - String content, - Charset charset - ) throws IOException { - Path path = Paths.get(filePath); - Files.createDirectories(path.getParent()); - Files.write(path, content.getBytes(charset)); - } + /** + * 将字符串写入文件 + * + * @param filePath 文件路径 + * @param content 要写入的内容 + * @param charset 字符集 + * @throws IOException 写入文件时发生错误 + */ + public static void writeStringToFile( + String filePath, + String content, + Charset charset + ) throws IOException { + Path path = Paths.get(filePath); + Files.createDirectories(path.getParent()); + Files.write(path, content.getBytes(charset)); + } - /** - * 读取文件内容为字符串列表(按行分割) - * - * @param filePath 文件路径 - * @return 文件内容按行分割的字符串列表 - * @throws IOException 读取文件时发生错误 - */ - public static List readLines(String filePath) throws IOException { - return readLines(filePath, DEFAULT_CHARSET); - } + /** + * 读取文件内容为字符串列表(按行分割) + * + * @param filePath 文件路径 + * @return 文件内容按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ + public static List readLines(String filePath) throws IOException { + return readLines(filePath, DEFAULT_CHARSET); + } - /** - * 读取文件内容为字符串列表(按行分割) - * - * @param filePath 文件路径 - * @param charset 字符集 - * @return 文件内容按行分割的字符串列表 - * @throws IOException 读取文件时发生错误 - */ - public static List readLines(String filePath, Charset charset) - throws IOException { - Path path = Paths.get(filePath); - return Files.readAllLines(path, charset); - } + /** + * 读取文件内容为字符串列表(按行分割) + * + * @param filePath 文件路径 + * @param charset 字符集 + * @return 文件内容按行分割的字符串列表 + * @throws IOException 读取文件时发生错误 + */ + public static List readLines(String filePath, Charset charset) + throws IOException { + Path path = Paths.get(filePath); + return Files.readAllLines(path, charset); + } - /** - * 将字符串列表写入文件(每行一个元素) - * - * @param filePath 文件路径 - * @param lines 要写入的行内容列表 - * @throws IOException 写入文件时发生错误 - */ - public static void writeLines(String filePath, List lines) - throws IOException { - writeLines(filePath, lines, DEFAULT_CHARSET); - } + /** + * 将字符串列表写入文件(每行一个元素) + * + * @param filePath 文件路径 + * @param lines 要写入的行内容列表 + * @throws IOException 写入文件时发生错误 + */ + public static void writeLines(String filePath, List lines) + throws IOException { + writeLines(filePath, lines, DEFAULT_CHARSET); + } - /** - * 将字符串列表写入文件(每行一个元素) - * - * @param filePath 文件路径 - * @param lines 要写入的行内容列表 - * @param charset 字符集 - * @throws IOException 写入文件时发生错误 - */ - public static void writeLines( - String filePath, - List lines, - Charset charset - ) throws IOException { - Path path = Paths.get(filePath); - Files.createDirectories(path.getParent()); - Files.write(path, lines, charset); - } + /** + * 将字符串列表写入文件(每行一个元素) + * + * @param filePath 文件路径 + * @param lines 要写入的行内容列表 + * @param charset 字符集 + * @throws IOException 写入文件时发生错误 + */ + public static void writeLines( + String filePath, + List lines, + Charset charset + ) throws IOException { + Path path = Paths.get(filePath); + Files.createDirectories(path.getParent()); + Files.write(path, lines, charset); + } - /** - * 复制文件 - * - * @param sourcePath 源文件路径 - * @param targetPath 目标文件路径 - * @throws IOException 复制文件时发生错误 - */ - public static void copyFile(String sourcePath, String targetPath) - throws IOException { - Path source = Paths.get(sourcePath); - Path target = Paths.get(targetPath); - Files.createDirectories(target.getParent()); - Files.copy(source, target); - } + /** + * 复制文件 + * + * @param sourcePath 源文件路径 + * @param targetPath 目标文件路径 + * @throws IOException 复制文件时发生错误 + */ + public static void copyFile(String sourcePath, String targetPath) + throws IOException { + Path source = Paths.get(sourcePath); + Path target = Paths.get(targetPath); + Files.createDirectories(target.getParent()); + Files.copy(source, target); + } - /** - * 删除文件 - * - * @param filePath 文件路径 - * @return 如果文件删除成功返回true,否则返回false - */ - public static boolean deleteFile(String filePath) { - try { - Path path = Paths.get(filePath); - return Files.deleteIfExists(path); - } catch (IOException e) { - return false; - } - } + /** + * 删除文件 + * + * @param filePath 文件路径 + * @return 如果文件删除成功返回true,否则返回false + */ + public static boolean deleteFile(String filePath) { + try { + Path path = Paths.get(filePath); + return Files.deleteIfExists(path); + } catch (IOException e) { + return false; + } + } - /** - * 检查文件是否存在 - * - * @param filePath 文件路径 - * @return 如果文件存在返回true,否则返回false - */ - public static boolean exists(String filePath) { - Path path = Paths.get(filePath); - return Files.exists(path); - } + /** + * 检查文件是否存在 + * + * @param filePath 文件路径 + * @return 如果文件存在返回true,否则返回false + */ + public static boolean exists(String filePath) { + Path path = Paths.get(filePath); + return Files.exists(path); + } - /** - * 获取文件大小 - * - * @param filePath 文件路径 - * @return 文件大小(字节),如果文件不存在返回-1 - */ - public static long getFileSize(String filePath) { - try { - Path path = Paths.get(filePath); - return Files.size(path); - } catch (IOException e) { - return -1; - } - } + /** + * 获取文件大小 + * + * @param filePath 文件路径 + * @return 文件大小(字节),如果文件不存在返回-1 + */ + public static long getFileSize(String filePath) { + try { + Path path = Paths.get(filePath); + return Files.size(path); + } catch (IOException e) { + return -1; + } + } - /** - * 创建目录 - * - * @param dirPath 目录路径 - * @return 如果目录创建成功返回true,否则返回false - */ - public static boolean createDirectory(String dirPath) { - try { - Path path = Paths.get(dirPath); - Files.createDirectories(path); - return true; - } catch (IOException e) { - return false; - } - } + /** + * 创建目录 + * + * @param dirPath 目录路径 + * @return 如果目录创建成功返回true,否则返回false + */ + public static boolean createDirectory(String dirPath) { + try { + Path path = Paths.get(dirPath); + Files.createDirectories(path); + return true; + } catch (IOException e) { + return false; + } + } - /** - * 获取文件扩展名 - * - * @param fileName 文件名 - * @return 文件扩展名(不包含点号),如果无扩展名返回空字符串 - */ - public static String getFileExtension(String fileName) { - if (StringUtil.isEmpty(fileName)) { - return ""; - } - int lastDotIndex = fileName.lastIndexOf('.'); - if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) { - return ""; - } - return fileName.substring(lastDotIndex + 1); - } + /** + * 获取文件扩展名 + * + * @param fileName 文件名 + * @return 文件扩展名(不包含点号),如果无扩展名返回空字符串 + */ + public static String getFileExtension(String fileName) { + if (StringUtil.isEmpty(fileName)) { + return ""; + } + int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) { + return ""; + } + return fileName.substring(lastDotIndex + 1); + } - /** - * 获取不带扩展名的文件名 - * - * @param fileName 文件名 - * @return 不带扩展名的文件名 - */ - public static String getFileNameWithoutExtension(String fileName) { - if (StringUtil.isEmpty(fileName)) { - return ""; - } - int lastDotIndex = fileName.lastIndexOf('.'); - if (lastDotIndex == -1) { - return fileName; - } - return fileName.substring(0, lastDotIndex); - } + /** + * 获取不带扩展名的文件名 + * + * @param fileName 文件名 + * @return 不带扩展名的文件名 + */ + public static String getFileNameWithoutExtension(String fileName) { + if (StringUtil.isEmpty(fileName)) { + return ""; + } + int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex == -1) { + return fileName; + } + return fileName.substring(0, lastDotIndex); + } - /** - * 读取文件内容为字节数组 - * - * @param filePath 文件路径 - * @return 文件内容的字节数组 - * @throws IOException 读取文件时发生错误 - */ - public static byte[] readFileToByteArray(String filePath) - throws IOException { - Path path = Paths.get(filePath); - return Files.readAllBytes(path); - } + /** + * 读取文件内容为字节数组 + * + * @param filePath 文件路径 + * @return 文件内容的字节数组 + * @throws IOException 读取文件时发生错误 + */ + public static byte[] readFileToByteArray(String filePath) + throws IOException { + Path path = Paths.get(filePath); + return Files.readAllBytes(path); + } - /** - * 将字节数组写入文件 - * - * @param filePath 文件路径 - * @param data 要写入的字节数据 - * @throws IOException 写入文件时发生错误 - */ - public static void writeByteArrayToFile(String filePath, byte[] data) - throws IOException { - Path path = Paths.get(filePath); - Files.createDirectories(path.getParent()); - Files.write(path, data); - } + /** + * 将字节数组写入文件 + * + * @param filePath 文件路径 + * @param data 要写入的字节数据 + * @throws IOException 写入文件时发生错误 + */ + public static void writeByteArrayToFile(String filePath, byte[] data) + throws IOException { + Path path = Paths.get(filePath); + Files.createDirectories(path.getParent()); + Files.write(path, data); + } - /** - * 将字节数组追加到文件末尾 - * - * @param filePath 文件路径 - * @param data 要追加的字节数据 - * @throws IOException 追加数据时发生错误 - */ - public static void appendByteArrayToFile(String filePath, byte[] data) - throws IOException { - Path path = Paths.get(filePath); - Files.createDirectories(path.getParent()); - Files.write( - path, - data, - StandardOpenOption.CREATE, - StandardOpenOption.APPEND - ); - } + /** + * 将字节数组追加到文件末尾 + * + * @param filePath 文件路径 + * @param data 要追加的字节数据 + * @throws IOException 追加数据时发生错误 + */ + public static void appendByteArrayToFile(String filePath, byte[] data) + throws IOException { + Path path = Paths.get(filePath); + Files.createDirectories(path.getParent()); + Files.write( + path, + data, + StandardOpenOption.CREATE, + StandardOpenOption.APPEND + ); + } - /** - * 分块读取大文件为字节数组列表 - * - * @param filePath 文件路径 - * @param chunkSize 每块大小(字节) - * @return 文件内容按指定大小分割的字节数组列表 - * @throws IOException 读取文件时发生错误 - */ - public static List readFileToByteArrayChunks( - String filePath, - int chunkSize - ) throws IOException { - List chunks = new ArrayList<>(); - Path path = Paths.get(filePath); + /** + * 分块读取大文件为字节数组列表 + * + * @param filePath 文件路径 + * @param chunkSize 每块大小(字节) + * @return 文件内容按指定大小分割的字节数组列表 + * @throws IOException 读取文件时发生错误 + */ + public static List readFileToByteArrayChunks( + String filePath, + int chunkSize + ) throws IOException { + List chunks = new ArrayList<>(); + Path path = Paths.get(filePath); - try (InputStream inputStream = Files.newInputStream(path)) { - byte[] buffer = new byte[chunkSize]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - byte[] chunk = new byte[bytesRead]; - System.arraycopy(buffer, 0, chunk, 0, bytesRead); - chunks.add(chunk); - } - } + try (InputStream inputStream = Files.newInputStream(path)) { + byte[] buffer = new byte[chunkSize]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + byte[] chunk = new byte[bytesRead]; + System.arraycopy(buffer, 0, chunk, 0, bytesRead); + chunks.add(chunk); + } + } - return chunks; - } + return chunks; + } - /** - * 将字节数组列表写入文件 - * - * @param filePath 文件路径 - * @param chunks 字节数组列表 - * @throws IOException 写入文件时发生错误 - */ - public static void writeByteArrayChunksToFile( - String filePath, - List chunks - ) throws IOException { - Path path = Paths.get(filePath); - Files.createDirectories(path.getParent()); + /** + * 将字节数组列表写入文件 + * + * @param filePath 文件路径 + * @param chunks 字节数组列表 + * @throws IOException 写入文件时发生错误 + */ + public static void writeByteArrayChunksToFile( + String filePath, + List chunks + ) throws IOException { + Path path = Paths.get(filePath); + Files.createDirectories(path.getParent()); - try (OutputStream outputStream = Files.newOutputStream(path)) { - for (byte[] chunk : chunks) { - outputStream.write(chunk); - } - } - } + try (OutputStream outputStream = Files.newOutputStream(path)) { + for (byte[] chunk : chunks) { + outputStream.write(chunk); + } + } + } } diff --git a/src/com/mingliqiye/utils/functions/Debouncer.java b/src/com/mingliqiye/utils/functions/Debouncer.java index 52f631b..8458262 100644 --- a/src/com/mingliqiye/utils/functions/Debouncer.java +++ b/src/com/mingliqiye/utils/functions/Debouncer.java @@ -9,63 +9,63 @@ import java.util.concurrent.*; */ public class Debouncer { - private final ScheduledExecutorService scheduler = - Executors.newSingleThreadScheduledExecutor(); - private final ConcurrentHashMap> delayedMap = - new ConcurrentHashMap<>(); - private final long delay; + private final ScheduledExecutorService scheduler = + Executors.newSingleThreadScheduledExecutor(); + private final ConcurrentHashMap> delayedMap = + new ConcurrentHashMap<>(); + private final long delay; - /** - * 构造函数,创建一个防抖器实例 - * - * @param delay 延迟时间 - * @param unit 时间单位 - */ - public Debouncer(long delay, TimeUnit unit) { - this.delay = unit.toMillis(delay); - } + /** + * 构造函数,创建一个防抖器实例 + * + * @param delay 延迟时间 + * @param unit 时间单位 + */ + public Debouncer(long delay, TimeUnit unit) { + this.delay = unit.toMillis(delay); + } - /** - * 执行防抖操作,如果在指定延迟时间内再次调用相同key的任务,则取消之前的任务并重新计时 - * - * @param key 任务的唯一标识符,用于区分不同任务 - * @param task 要执行的任务 - */ - public void debounce(final Object key, final Runnable task) { - // 提交新任务并获取之前可能存在的任务 - final Future prev = delayedMap.put( - key, - scheduler.schedule( - () -> { - try { - task.run(); - } finally { - // 任务执行完成后从映射中移除 - delayedMap.remove(key); - } - }, - delay, - TimeUnit.MILLISECONDS - ) - ); + /** + * 执行防抖操作,如果在指定延迟时间内再次调用相同key的任务,则取消之前的任务并重新计时 + * + * @param key 任务的唯一标识符,用于区分不同任务 + * @param task 要执行的任务 + */ + public void debounce(final Object key, final Runnable task) { + // 提交新任务并获取之前可能存在的任务 + final Future prev = delayedMap.put( + key, + scheduler.schedule( + () -> { + try { + task.run(); + } finally { + // 任务执行完成后从映射中移除 + delayedMap.remove(key); + } + }, + delay, + TimeUnit.MILLISECONDS + ) + ); - // 如果之前存在任务,则取消它 - if (prev != null) { - prev.cancel(true); - } - } + // 如果之前存在任务,则取消它 + if (prev != null) { + prev.cancel(true); + } + } - /** - * 关闭防抖器,取消所有待执行的任务并关闭调度器 - */ - public void shutdown() { - // 先取消所有延迟任务 - for (Future future : delayedMap.values()) { - future.cancel(true); - } - delayedMap.clear(); + /** + * 关闭防抖器,取消所有待执行的任务并关闭调度器 + */ + public void shutdown() { + // 先取消所有延迟任务 + for (Future future : delayedMap.values()) { + future.cancel(true); + } + delayedMap.clear(); - // 再关闭调度器 - scheduler.shutdownNow(); - } + // 再关闭调度器 + scheduler.shutdownNow(); + } } diff --git a/src/com/mingliqiye/utils/hash/HashUtils.java b/src/com/mingliqiye/utils/hash/HashUtils.java index e40755d..3a7195b 100644 --- a/src/com/mingliqiye/utils/hash/HashUtils.java +++ b/src/com/mingliqiye/utils/hash/HashUtils.java @@ -1,14 +1,13 @@ package com.mingliqiye.utils.hash; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.mindrot.jbcrypt.BCrypt; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Security; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.mindrot.jbcrypt.BCrypt; /** * 提供常用的哈希计算工具方法,包括文件哈希值计算、BCrypt 加密等。 @@ -17,77 +16,77 @@ import java.security.Security; */ public class HashUtils { - static { - Security.addProvider(new BouncyCastleProvider()); - } + static { + Security.addProvider(new BouncyCastleProvider()); + } - /** - * 计算指定文件的哈希值。 - * - * @param file 要计算哈希值的文件对象 - * @param algorithm 使用的哈希算法名称(如 SHA-256、MD5 等) - * @return 文件的十六进制格式哈希值字符串 - * @throws IOException 当文件不存在或读取过程中发生 I/O 错误时抛出 - * @throws NoSuchAlgorithmException 当指定的哈希算法不可用时抛出 - */ - public static String calculateFileHash(File file, String algorithm) - throws IOException, NoSuchAlgorithmException { - // 检查文件是否存在 - if (!file.exists()) { - throw new IOException("File not found: " + file.getAbsolutePath()); - } + /** + * 计算指定文件的哈希值。 + * + * @param file 要计算哈希值的文件对象 + * @param algorithm 使用的哈希算法名称(如 SHA-256、MD5 等) + * @return 文件的十六进制格式哈希值字符串 + * @throws IOException 当文件不存在或读取过程中发生 I/O 错误时抛出 + * @throws NoSuchAlgorithmException 当指定的哈希算法不可用时抛出 + */ + public static String calculateFileHash(File file, String algorithm) + throws IOException, NoSuchAlgorithmException { + // 检查文件是否存在 + if (!file.exists()) { + throw new IOException("File not found: " + file.getAbsolutePath()); + } - MessageDigest digest = MessageDigest.getInstance(algorithm); + MessageDigest digest = MessageDigest.getInstance(algorithm); - try (FileInputStream fis = new FileInputStream(file)) { - byte[] buffer = new byte[8192]; // 8KB 缓冲区 - int bytesRead; + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buffer = new byte[8192]; // 8KB 缓冲区 + int bytesRead; - // 分块读取文件内容并更新摘要 - while ((bytesRead = fis.read(buffer)) != -1) { - digest.update(buffer, 0, bytesRead); - } - } + // 分块读取文件内容并更新摘要 + while ((bytesRead = fis.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead); + } + } - return bytesToHex(digest.digest()); - } + return bytesToHex(digest.digest()); + } - /** - * 将字节数组转换为十六进制字符串表示。 - * - * @param bytes 输入的字节数组 - * @return 对应的十六进制字符串 - */ - private static String bytesToHex(byte[] bytes) { - StringBuilder hexString = new StringBuilder(2 * bytes.length); - for (byte b : bytes) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - return hexString.toString(); - } + /** + * 将字节数组转换为十六进制字符串表示。 + * + * @param bytes 输入的字节数组 + * @return 对应的十六进制字符串 + */ + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(2 * bytes.length); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } - /** - * 使用 BCrypt 算法对字符串进行加密。 - * - * @param string 需要加密的明文字符串 - * @return 加密后的 BCrypt 哈希字符串 - */ - public static String bcrypt(String string) { - return BCrypt.hashpw(string, BCrypt.gensalt()); - } + /** + * 使用 BCrypt 算法对字符串进行加密。 + * + * @param string 需要加密的明文字符串 + * @return 加密后的 BCrypt 哈希字符串 + */ + public static String bcrypt(String string) { + return BCrypt.hashpw(string, BCrypt.gensalt()); + } - /** - * 验证给定字符串与 BCrypt 哈希是否匹配。 - * - * @param string 明文字符串 - * @param bcrypted 已经使用 BCrypt 加密的哈希字符串 - * @return 如果匹配返回 true,否则返回 false - */ - public static boolean checkBcrypt(String string, String bcrypted) { - return BCrypt.checkpw(string, bcrypted); - } + /** + * 验证给定字符串与 BCrypt 哈希是否匹配。 + * + * @param string 明文字符串 + * @param bcrypted 已经使用 BCrypt 加密的哈希字符串 + * @return 如果匹配返回 true,否则返回 false + */ + public static boolean checkBcrypt(String string, String bcrypted) { + return BCrypt.checkpw(string, bcrypted); + } } diff --git a/src/com/mingliqiye/utils/http/Response.java b/src/com/mingliqiye/utils/http/Response.java index d93aca5..172f7a8 100644 --- a/src/com/mingliqiye/utils/http/Response.java +++ b/src/com/mingliqiye/utils/http/Response.java @@ -11,37 +11,37 @@ import lombok.ToString; @Getter public class Response { - private final String time = DateTime.now().format( - Formatter.STANDARD_DATETIME_MILLISECOUND7 - ); - private String message; - private T data; - private int statusCode; + private final String time = DateTime.now().format( + Formatter.STANDARD_DATETIME_MILLISECOUND7 + ); + private String message; + private T data; + private int statusCode; - public Response(String message, T data, int statusCode) { - this.message = message; - this.data = data; - this.statusCode = statusCode; - } + public Response(String message, T data, int statusCode) { + this.message = message; + this.data = data; + this.statusCode = statusCode; + } - public static Response ok(T data) { - return new Response<>("操作成功", data, 200); - } + public static Response ok(T data) { + return new Response<>("操作成功", data, 200); + } - public Response setMessage(String message) { - this.message = message; - return this; - } + public Response setMessage(String message) { + this.message = message; + return this; + } - public Response setData(T data) { - this.data = data; - return Response.ok(getData()) - .setMessage(getMessage()) - .setStatusCode(getStatusCode()); - } + public Response setData(T data) { + this.data = data; + return Response.ok(getData()) + .setMessage(getMessage()) + .setStatusCode(getStatusCode()); + } - public Response setStatusCode(int statusCode) { - this.statusCode = statusCode; - return this; - } + public Response setStatusCode(int statusCode) { + this.statusCode = statusCode; + return this; + } } diff --git a/src/com/mingliqiye/utils/minecraft/slp/Description.java b/src/com/mingliqiye/utils/minecraft/slp/Description.java index a9a5489..c7e5b43 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/Description.java +++ b/src/com/mingliqiye/utils/minecraft/slp/Description.java @@ -5,6 +5,6 @@ import lombok.Data; @Data public class Description { - private String text; - private Extra[] extra; + private String text; + private Extra[] extra; } diff --git a/src/com/mingliqiye/utils/minecraft/slp/Extra.java b/src/com/mingliqiye/utils/minecraft/slp/Extra.java index ff78b0f..996910a 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/Extra.java +++ b/src/com/mingliqiye/utils/minecraft/slp/Extra.java @@ -5,8 +5,8 @@ import lombok.Data; @Data public class Extra { - private String text; - private String color; - private Boolean bold; - private Boolean italic; + private String text; + private String color; + private Boolean bold; + private Boolean italic; } diff --git a/src/com/mingliqiye/utils/minecraft/slp/MinecraftServerStatus.java b/src/com/mingliqiye/utils/minecraft/slp/MinecraftServerStatus.java index dbfb85b..fff4fb4 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/MinecraftServerStatus.java +++ b/src/com/mingliqiye/utils/minecraft/slp/MinecraftServerStatus.java @@ -5,11 +5,11 @@ import lombok.Data; @Data public class MinecraftServerStatus { - private Description description; - private Players players; - private Version version; - private String favicon; - private boolean enforcesSecureChat; - private boolean previewsChat; - private String jsonData; + private Description description; + private Players players; + private Version version; + private String favicon; + private boolean enforcesSecureChat; + private boolean previewsChat; + private String jsonData; } diff --git a/src/com/mingliqiye/utils/minecraft/slp/PlayerSample.java b/src/com/mingliqiye/utils/minecraft/slp/PlayerSample.java index 8585b91..dd68be5 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/PlayerSample.java +++ b/src/com/mingliqiye/utils/minecraft/slp/PlayerSample.java @@ -5,6 +5,6 @@ import lombok.Data; @Data public class PlayerSample { - private String name; - private String id; + private String name; + private String id; } diff --git a/src/com/mingliqiye/utils/minecraft/slp/Players.java b/src/com/mingliqiye/utils/minecraft/slp/Players.java index 41a33d4..b1911d1 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/Players.java +++ b/src/com/mingliqiye/utils/minecraft/slp/Players.java @@ -5,7 +5,7 @@ import lombok.Data; @Data public class Players { - private int max; - private int online; - private PlayerSample[] sample; + private int max; + private int online; + private PlayerSample[] sample; } diff --git a/src/com/mingliqiye/utils/minecraft/slp/SLP.java b/src/com/mingliqiye/utils/minecraft/slp/SLP.java index 1202160..4b054d7 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/SLP.java +++ b/src/com/mingliqiye/utils/minecraft/slp/SLP.java @@ -2,7 +2,6 @@ package com.mingliqiye.utils.minecraft.slp; import com.fasterxml.jackson.databind.ObjectMapper; import com.mingliqiye.utils.network.NetworkEndpoint; - import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; @@ -17,182 +16,182 @@ import java.nio.ByteOrder; */ public class SLP { - private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectMapper objectMapper = new ObjectMapper(); - /** - * 将 int32 值截断为无符号 short(2 字节)并按大端序写入字节数组。 - * - * @param value 需要转换的整数(int32) - * @return 包含两个字节的数组,表示无符号 short - */ - public static byte[] toUnsignedShort(int value) { - byte[] array = new byte[2]; - ByteBuffer.wrap(array, 0, 2) - .order(ByteOrder.BIG_ENDIAN) - .putShort((short) (value & 0xFFFF)); - return array; - } + /** + * 将 int32 值截断为无符号 short(2 字节)并按大端序写入字节数组。 + * + * @param value 需要转换的整数(int32) + * @return 包含两个字节的数组,表示无符号 short + */ + public static byte[] toUnsignedShort(int value) { + byte[] array = new byte[2]; + ByteBuffer.wrap(array, 0, 2) + .order(ByteOrder.BIG_ENDIAN) + .putShort((short) (value & 0xFFFF)); + return array; + } - /** - * 构造 Minecraft 握手包数据。 - * 握手包用于初始化客户端与服务器之间的连接。 - * - * @param serverIP 服务器 IP 地址或域名 - * @param serverPort 服务器端口号 - * @param type 连接类型(通常为 1 表示获取状态) - * @return 握手包的完整字节数组 - * @throws IOException 如果构造过程中发生 IO 错误 - */ - public static byte[] getHandshakePack( - String serverIP, - int serverPort, - int type - ) throws IOException { - ByteArrayOutputStream pack = new ByteArrayOutputStream(); - ByteArrayOutputStream byteArrayOutputStream = - new ByteArrayOutputStream(); - pack.write(0x00); // 握手包标识符 - pack.write(toVarInt(1156)); // 协议版本号(示例值) - byte[] sip = serverIP.getBytes(); - pack.write(toVarInt(sip.length)); // 服务器地址长度 - pack.write(sip); // 服务器地址 - pack.write(toUnsignedShort(serverPort)); // 服务器端口 - pack.write(toVarInt(type)); // 下一阶段类型(1 表示状态请求) - byteArrayOutputStream.write(toVarInt(pack.size())); // 包长度前缀 - byteArrayOutputStream.write(pack.toByteArray()); + /** + * 构造 Minecraft 握手包数据。 + * 握手包用于初始化客户端与服务器之间的连接。 + * + * @param serverIP 服务器 IP 地址或域名 + * @param serverPort 服务器端口号 + * @param type 连接类型(通常为 1 表示获取状态) + * @return 握手包的完整字节数组 + * @throws IOException 如果构造过程中发生 IO 错误 + */ + public static byte[] getHandshakePack( + String serverIP, + int serverPort, + int type + ) throws IOException { + ByteArrayOutputStream pack = new ByteArrayOutputStream(); + ByteArrayOutputStream byteArrayOutputStream = + new ByteArrayOutputStream(); + pack.write(0x00); // 握手包标识符 + pack.write(toVarInt(1156)); // 协议版本号(示例值) + byte[] sip = serverIP.getBytes(); + pack.write(toVarInt(sip.length)); // 服务器地址长度 + pack.write(sip); // 服务器地址 + pack.write(toUnsignedShort(serverPort)); // 服务器端口 + pack.write(toVarInt(type)); // 下一阶段类型(1 表示状态请求) + byteArrayOutputStream.write(toVarInt(pack.size())); // 包长度前缀 + byteArrayOutputStream.write(pack.toByteArray()); - return byteArrayOutputStream.toByteArray(); - } + return byteArrayOutputStream.toByteArray(); + } - /** - * 获取状态请求包的固定字节表示。 - * 此包用于向服务器请求当前状态信息。 - * - * @return 状态请求包的字节数组 - */ - public static byte[] getStatusPack() { - return new byte[] { 0x01, 0x00 }; - } + /** + * 获取状态请求包的固定字节表示。 + * 此包用于向服务器请求当前状态信息。 + * + * @return 状态请求包的字节数组 + */ + public static byte[] getStatusPack() { + return new byte[] { 0x01, 0x00 }; + } - /** - * 从输入流中读取服务器返回的状态 JSON 数据,并解析为 MinecraftServerStatus 实体对象。 - * - * @param inputStream 输入流,包含服务器响应的数据 - * @return 解析后的 MinecraftServerStatus 对象 - * @throws IOException 如果读取过程中发生 IO 错误 - */ - public static MinecraftServerStatus getStatusJsonEntity( - DataInputStream inputStream - ) throws IOException { - readVarInt(inputStream); // 忽略第一个 VarInt(包长度) - inputStream.readByte(); // 忽略包标识符 - int lengthjson = readVarInt(inputStream); // 读取 JSON 数据长度 - byte[] data = new byte[lengthjson]; - inputStream.readFully(data); // 读取完整的 JSON 数据 - MinecraftServerStatus serverStatus = objectMapper.readValue( - data, - MinecraftServerStatus.class - ); - serverStatus.setJsonData(new String(data)); // 设置原始 JSON 字符串 - return serverStatus; - } + /** + * 从输入流中读取服务器返回的状态 JSON 数据,并解析为 MinecraftServerStatus 实体对象。 + * + * @param inputStream 输入流,包含服务器响应的数据 + * @return 解析后的 MinecraftServerStatus 对象 + * @throws IOException 如果读取过程中发生 IO 错误 + */ + public static MinecraftServerStatus getStatusJsonEntity( + DataInputStream inputStream + ) throws IOException { + readVarInt(inputStream); // 忽略第一个 VarInt(包长度) + inputStream.readByte(); // 忽略包标识符 + int lengthjson = readVarInt(inputStream); // 读取 JSON 数据长度 + byte[] data = new byte[lengthjson]; + inputStream.readFully(data); // 读取完整的 JSON 数据 + MinecraftServerStatus serverStatus = objectMapper.readValue( + data, + MinecraftServerStatus.class + ); + serverStatus.setJsonData(new String(data)); // 设置原始 JSON 字符串 + return serverStatus; + } - /** - * 从输入流中读取一个 VarInt 类型的整数(最多 5 个字节)。 - * - * @param in 输入流 - * @return 解码后的整数值 - * @throws IOException 如果读取过程中发生 IO 错误 - */ - public static int readVarInt(DataInputStream in) throws IOException { - int value = 0; - int length = 0; - byte currentByte; - do { - currentByte = in.readByte(); - value |= (currentByte & 0x7F) << (length * 7); - length += 1; - if (length > 5) { - throw new RuntimeException("VarInt too long"); - } - } while ((currentByte & 0x80) != 0); - return value; - } + /** + * 从输入流中读取一个 VarInt 类型的整数(最多 5 个字节)。 + * + * @param in 输入流 + * @return 解码后的整数值 + * @throws IOException 如果读取过程中发生 IO 错误 + */ + public static int readVarInt(DataInputStream in) throws IOException { + int value = 0; + int length = 0; + byte currentByte; + do { + currentByte = in.readByte(); + value |= (currentByte & 0x7F) << (length * 7); + length += 1; + if (length > 5) { + throw new RuntimeException("VarInt too long"); + } + } while ((currentByte & 0x80) != 0); + return value; + } - /** - * 将一个 int32 整数编码为 VarInt 格式的字节数组(1 到 5 个字节)。 - * - * @param value 需要编码的整数 - * @return 编码后的 VarInt 字节数组 - */ - public static byte[] toVarInt(int value) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - while (true) { - if ((value & 0xFFFFFF80) == 0) { - buffer.write(value); // 最后一个字节 - break; - } - buffer.write((value & 0x7F) | 0x80); // 写入带继续位的字节 - value >>>= 7; // 右移 7 位继续处理 - } - return buffer.toByteArray(); - } + /** + * 将一个 int32 整数编码为 VarInt 格式的字节数组(1 到 5 个字节)。 + * + * @param value 需要编码的整数 + * @return 编码后的 VarInt 字节数组 + */ + public static byte[] toVarInt(int value) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + while (true) { + if ((value & 0xFFFFFF80) == 0) { + buffer.write(value); // 最后一个字节 + break; + } + buffer.write((value & 0x7F) | 0x80); // 写入带继续位的字节 + value >>>= 7; // 右移 7 位继续处理 + } + return buffer.toByteArray(); + } - /** - * 创建一个新的 Socket 连接到指定的网络端点,并设置超时时间。 - * - * @param networkEndpoint 目标网络端点(包括主机和端口) - * @return 已连接的 Socket 实例 - * @throws IOException 如果连接失败或发生 IO 错误 - */ - public static Socket getNewConnect(NetworkEndpoint networkEndpoint) - throws IOException { - Socket socket = new Socket(); - socket.setSoTimeout(5000); // 设置读取超时时间为 5 秒 - socket.connect(networkEndpoint.toInetSocketAddress()); // 执行连接操作 - return socket; - } + /** + * 创建一个新的 Socket 连接到指定的网络端点,并设置超时时间。 + * + * @param networkEndpoint 目标网络端点(包括主机和端口) + * @return 已连接的 Socket 实例 + * @throws IOException 如果连接失败或发生 IO 错误 + */ + public static Socket getNewConnect(NetworkEndpoint networkEndpoint) + throws IOException { + Socket socket = new Socket(); + socket.setSoTimeout(5000); // 设置读取超时时间为 5 秒 + socket.connect(networkEndpoint.toInetSocketAddress()); // 执行连接操作 + return socket; + } - /** - * 使用 "host:port" 格式的字符串连接到 Minecraft 服务器并获取其状态信息。 - * - * @param s 域名或 IP 地址加端口号组成的字符串,例如 "127.0.0.1:25565" - * @return 服务器状态实体对象 - * @throws IOException 如果连接失败或发生 IO 错误 - */ - public static MinecraftServerStatus getServerStatus(String s) - throws IOException { - return getServerStatus(NetworkEndpoint.of(s)); - } + /** + * 使用 "host:port" 格式的字符串连接到 Minecraft 服务器并获取其状态信息。 + * + * @param s 域名或 IP 地址加端口号组成的字符串,例如 "127.0.0.1:25565" + * @return 服务器状态实体对象 + * @throws IOException 如果连接失败或发生 IO 错误 + */ + public static MinecraftServerStatus getServerStatus(String s) + throws IOException { + return getServerStatus(NetworkEndpoint.of(s)); + } - /** - * 使用指定的主机名和端口号连接到 Minecraft 服务器并获取其状态信息。 - * - * @param s 主机名或 IP 地址 - * @param i 端口号 - * @return 服务器状态实体对象 - * @throws IOException 如果连接失败或发生 IO 错误 - */ - public static MinecraftServerStatus getServerStatus(String s, Integer i) - throws IOException { - return getServerStatus(NetworkEndpoint.of(s, i)); - } + /** + * 使用指定的主机名和端口号连接到 Minecraft 服务器并获取其状态信息。 + * + * @param s 主机名或 IP 地址 + * @param i 端口号 + * @return 服务器状态实体对象 + * @throws IOException 如果连接失败或发生 IO 错误 + */ + public static MinecraftServerStatus getServerStatus(String s, Integer i) + throws IOException { + return getServerStatus(NetworkEndpoint.of(s, i)); + } - /** - * 使用 NetworkEndpoint 实例连接到 Minecraft 服务器并获取其状态信息。 - * - * @param e 网络端点实例,包含主机和端口信息 - * @return 服务器状态实体对象 - * @throws IOException 如果连接失败或发生 IO 错误 - * @see NetworkEndpoint - */ - public static MinecraftServerStatus getServerStatus(NetworkEndpoint e) - throws IOException { - Socket socket = getNewConnect(e); // 建立 TCP 连接 - OutputStream out = socket.getOutputStream(); // 获取输出流发送数据 - DataInputStream in = new DataInputStream(socket.getInputStream()); // 获取输入流接收数据 - out.write(getHandshakePack(e.getHost(), e.getPort(), 1)); // 发送握手包 - out.write(getStatusPack()); // 发送状态请求包 - return getStatusJsonEntity(in); // 读取并解析服务器响应 - } + /** + * 使用 NetworkEndpoint 实例连接到 Minecraft 服务器并获取其状态信息。 + * + * @param e 网络端点实例,包含主机和端口信息 + * @return 服务器状态实体对象 + * @throws IOException 如果连接失败或发生 IO 错误 + * @see NetworkEndpoint + */ + public static MinecraftServerStatus getServerStatus(NetworkEndpoint e) + throws IOException { + Socket socket = getNewConnect(e); // 建立 TCP 连接 + OutputStream out = socket.getOutputStream(); // 获取输出流发送数据 + DataInputStream in = new DataInputStream(socket.getInputStream()); // 获取输入流接收数据 + out.write(getHandshakePack(e.getHost(), e.getPort(), 1)); // 发送握手包 + out.write(getStatusPack()); // 发送状态请求包 + return getStatusJsonEntity(in); // 读取并解析服务器响应 + } } diff --git a/src/com/mingliqiye/utils/minecraft/slp/Version.java b/src/com/mingliqiye/utils/minecraft/slp/Version.java index 59c84bb..1002063 100644 --- a/src/com/mingliqiye/utils/minecraft/slp/Version.java +++ b/src/com/mingliqiye/utils/minecraft/slp/Version.java @@ -5,6 +5,6 @@ import lombok.Data; @Data public class Version { - private String name; - private int protocol; + private String name; + private int protocol; } diff --git a/src/com/mingliqiye/utils/network/NetWorkUtil.java b/src/com/mingliqiye/utils/network/NetWorkUtil.java index 811db93..61534e0 100644 --- a/src/com/mingliqiye/utils/network/NetWorkUtil.java +++ b/src/com/mingliqiye/utils/network/NetWorkUtil.java @@ -2,9 +2,9 @@ package com.mingliqiye.utils.network; public class NetWorkUtil { - public static void main(String[] args) { - System.out.println(NetworkEndpoint.of("127.0.0.1", 25565)); - System.out.println(NetworkEndpoint.of("127.0.0.1:25565")); - System.out.println(NetworkEndpoint.of("127.0.0.1:25565")); - } + public static void main(String[] args) { + System.out.println(NetworkEndpoint.of("127.0.0.1", 25565)); + System.out.println(NetworkEndpoint.of("127.0.0.1:25565")); + System.out.println(NetworkEndpoint.of("127.0.0.1:25565")); + } } diff --git a/src/com/mingliqiye/utils/network/NetworkAddress.java b/src/com/mingliqiye/utils/network/NetworkAddress.java index c524704..7b3754b 100644 --- a/src/com/mingliqiye/utils/network/NetworkAddress.java +++ b/src/com/mingliqiye/utils/network/NetworkAddress.java @@ -1,13 +1,12 @@ package com.mingliqiye.utils.network; import com.mingliqiye.utils.string.StringUtil; -import lombok.Getter; -import org.jetbrains.annotations.NotNull; - import java.io.Serializable; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.regex.Pattern; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; /** * 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。 @@ -17,180 +16,180 @@ import java.util.regex.Pattern; */ public class NetworkAddress implements Serializable { - /** - * IPv6标识 - */ - public static int IPV6 = 6; + /** + * IPv6标识 + */ + public static int IPV6 = 6; - /** - * IPv4标识 - */ - public static int IPV4 = 4; + /** + * IPv4标识 + */ + public static int IPV4 = 4; - /** - * IPv4地址正则表达式 - */ - static String IPV4REG = - "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + - "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"; + /** + * IPv4地址正则表达式 + */ + static String IPV4REG = + "^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"; - /** - * 编译后的IPv4地址匹配模式 - */ - private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4REG); + /** + * 编译后的IPv4地址匹配模式 + */ + private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4REG); - /** - * IPv6地址正则表达式 - */ - static String IPV6REG = - "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + - "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + - "|" + - "^(::)$|" + - "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + - "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + - "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + - "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$"; + /** + * IPv6地址正则表达式 + */ + static String IPV6REG = + "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + + "|" + + "^(::)$|" + + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$"; - /** - * 编译后的IPv6地址匹配模式 - */ - private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6REG); + /** + * 编译后的IPv6地址匹配模式 + */ + private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6REG); - /** - * IP地址类型:4 表示 IPv4,6 表示 IPv6 - */ - @Getter - private int IPv; + /** + * IP地址类型:4 表示 IPv4,6 表示 IPv6 + */ + @Getter + private int IPv; - /** - * IP地址字符串 - */ - @Getter - private String ip; + /** + * IP地址字符串 + */ + @Getter + private String ip; - /** - * 域名(如果输入的是域名) - */ - private String domain; + /** + * 域名(如果输入的是域名) + */ + private String domain; - /** - * 标识是否是域名解析来的IP - */ - private boolean isdom; + /** + * 标识是否是域名解析来的IP + */ + private boolean isdom; - /** - * 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。 - * - * @param domip 可能是IP地址或域名的字符串 - */ - NetworkAddress(String domip) { - try { - // 尝试将输入识别为IP地址 - IPv = testIp(domip); - ip = domip; - } catch (NetworkException e) { - try { - // 如果不是有效IP,则尝试作为域名解析 - String ips = getHostIp(domip); - IPv = testIp(ips); - ip = ips; - isdom = true; - domain = domip; - } catch (UnknownHostException ex) { - throw new NetworkException(ex); - } - } - } + /** + * 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。 + * + * @param domip 可能是IP地址或域名的字符串 + */ + NetworkAddress(String domip) { + try { + // 尝试将输入识别为IP地址 + IPv = testIp(domip); + ip = domip; + } catch (NetworkException e) { + try { + // 如果不是有效IP,则尝试作为域名解析 + String ips = getHostIp(domip); + IPv = testIp(ips); + ip = ips; + isdom = true; + domain = domip; + } catch (UnknownHostException ex) { + throw new NetworkException(ex); + } + } + } - /** - * 静态工厂方法,创建 NetworkAddress 实例。 - * - * @param domip 可能是IP地址或域名的字符串 - * @return 新建的 NetworkAddress 实例 - */ - public static NetworkAddress of(String domip) { - return new NetworkAddress(domip); - } + /** + * 静态工厂方法,创建 NetworkAddress 实例。 + * + * @param domip 可能是IP地址或域名的字符串 + * @return 新建的 NetworkAddress 实例 + */ + public static NetworkAddress of(String domip) { + return new NetworkAddress(domip); + } - /** - * 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。 - * - * @param inetAddress InetAddress 对象 - * @return 新建的 NetworkAddress 实例 - */ - public static NetworkAddress of(InetAddress inetAddress) { - return new NetworkAddress(inetAddress.getHostAddress()); - } + /** + * 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。 + * + * @param inetAddress InetAddress 对象 + * @return 新建的 NetworkAddress 实例 + */ + public static NetworkAddress of(InetAddress inetAddress) { + return new NetworkAddress(inetAddress.getHostAddress()); + } - /** - * 从DNS服务器解析域名获取对应的IP地址。 - * - * @param domain 域名 - * @return 解析出的第一个IP地址 - * @throws UnknownHostException 如果域名无法解析 - */ - public static String getHostIp(@NotNull String domain) - throws UnknownHostException { - InetAddress[] addresses = InetAddress.getAllByName(domain.trim()); - return addresses[0].getHostAddress(); - } + /** + * 从DNS服务器解析域名获取对应的IP地址。 + * + * @param domain 域名 + * @return 解析出的第一个IP地址 + * @throws UnknownHostException 如果域名无法解析 + */ + public static String getHostIp(@NotNull String domain) + throws UnknownHostException { + InetAddress[] addresses = InetAddress.getAllByName(domain.trim()); + return addresses[0].getHostAddress(); + } - /** - * 检测给定字符串是否为有效的IPv4或IPv6地址。 - * - * @param ip 要检测的IP地址字符串 - * @return 4 表示IPv4,6 表示IPv6 - * @throws NetworkException 如果IP格式无效 - */ - public static int testIp(String ip) { - if (ip == null) { - throw new NetworkException("IP地址不能为null"); - } - String trimmedIp = ip.trim(); + /** + * 检测给定字符串是否为有效的IPv4或IPv6地址。 + * + * @param ip 要检测的IP地址字符串 + * @return 4 表示IPv4,6 表示IPv6 + * @throws NetworkException 如果IP格式无效 + */ + public static int testIp(String ip) { + if (ip == null) { + throw new NetworkException("IP地址不能为null"); + } + String trimmedIp = ip.trim(); - // 判断是否匹配IPv4格式 - if (IPV4_PATTERN.matcher(trimmedIp).matches()) { - return IPV4; - } + // 判断是否匹配IPv4格式 + if (IPV4_PATTERN.matcher(trimmedIp).matches()) { + return IPV4; + } - // 判断是否匹配IPv6格式 - if (IPV6_PATTERN.matcher(trimmedIp).matches()) { - return IPV6; - } + // 判断是否匹配IPv6格式 + if (IPV6_PATTERN.matcher(trimmedIp).matches()) { + return IPV6; + } - // 不符合任一格式时抛出异常 - throw new NetworkException( - StringUtil.format("[{}] 不是有效的IPv4或IPv6地址", ip) - ); - } + // 不符合任一格式时抛出异常 + throw new NetworkException( + StringUtil.format("[{}] 不是有效的IPv4或IPv6地址", ip) + ); + } - /** - * 将当前 NetworkAddress 转换为 InetAddress 对象。 - * - * @return InetAddress 对象 - */ - public InetAddress toInetAddress() { - try { - return InetAddress.getByName(ip != null ? ip : domain); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } + /** + * 将当前 NetworkAddress 转换为 InetAddress 对象。 + * + * @return InetAddress 对象 + */ + public InetAddress toInetAddress() { + try { + return InetAddress.getByName(ip != null ? ip : domain); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } - /** - * 返回 NetworkAddress 的字符串表示形式。 - * - * @return 字符串表示 - */ - public String toString() { - return isdom - ? StringUtil.format( - "NetworkAddress(IP='{}',type='{}'," + "domain='{}')", - ip, - IPv, - domain - ) - : StringUtil.format("NetworkAddress(IP='{}',type='{}')", ip, IPv); - } + /** + * 返回 NetworkAddress 的字符串表示形式。 + * + * @return 字符串表示 + */ + public String toString() { + return isdom + ? StringUtil.format( + "NetworkAddress(IP='{}',type='{}'," + "domain='{}')", + ip, + IPv, + domain + ) + : StringUtil.format("NetworkAddress(IP='{}',type='{}')", ip, IPv); + } } diff --git a/src/com/mingliqiye/utils/network/NetworkEndpoint.java b/src/com/mingliqiye/utils/network/NetworkEndpoint.java index 028a810..5ee7572 100644 --- a/src/com/mingliqiye/utils/network/NetworkEndpoint.java +++ b/src/com/mingliqiye/utils/network/NetworkEndpoint.java @@ -1,10 +1,9 @@ package com.mingliqiye.utils.network; import com.mingliqiye.utils.string.StringUtil; -import lombok.Getter; - import java.io.Serializable; import java.net.InetSocketAddress; +import lombok.Getter; /** * IP和端口聚集类,用于封装网络地址与端口信息。 @@ -15,128 +14,128 @@ import java.net.InetSocketAddress; */ public class NetworkEndpoint implements Serializable { - @Getter - private final NetworkAddress networkAddress; + @Getter + private final NetworkAddress networkAddress; - @Getter - private final NetworkPort networkPort; + @Getter + private final NetworkPort networkPort; - /** - * 构造函数,使用指定的网络地址和端口创建NetworkEndpoint实例。 - * - * @param networkAddress 网络地址对象 - * @param networkPort 网络端口对象 - * @see NetworkAddress - * @see NetworkPort - */ - private NetworkEndpoint( - NetworkAddress networkAddress, - NetworkPort networkPort - ) { - this.networkAddress = networkAddress; - this.networkPort = networkPort; - } + /** + * 构造函数,使用指定的网络地址和端口创建NetworkEndpoint实例。 + * + * @param networkAddress 网络地址对象 + * @param networkPort 网络端口对象 + * @see NetworkAddress + * @see NetworkPort + */ + private NetworkEndpoint( + NetworkAddress networkAddress, + NetworkPort networkPort + ) { + this.networkAddress = networkAddress; + this.networkPort = networkPort; + } - /** - * 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。 - * - * @param address InetSocketAddress对象 - * @return 新建的NetworkEndpoint实例 - * @see InetSocketAddress - */ - public static NetworkEndpoint of(InetSocketAddress address) { - return new NetworkEndpoint( - new NetworkAddress(address.getHostString()), - new NetworkPort(address.getPort()) - ); - } + /** + * 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。 + * + * @param address InetSocketAddress对象 + * @return 新建的NetworkEndpoint实例 + * @see InetSocketAddress + */ + public static NetworkEndpoint of(InetSocketAddress address) { + return new NetworkEndpoint( + new NetworkAddress(address.getHostString()), + new NetworkPort(address.getPort()) + ); + } - /** - * 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。 - * - * @param s 主机名或IP地址字符串 - * @param i 端口号 - * @return 新建的NetworkEndpoint实例 - */ - public static NetworkEndpoint of(String s, Integer i) { - NetworkAddress networkAddress = new NetworkAddress(s); - NetworkPort networkPort = new NetworkPort(i); - return new NetworkEndpoint(networkAddress, networkPort); - } + /** + * 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。 + * + * @param s 主机名或IP地址字符串 + * @param i 端口号 + * @return 新建的NetworkEndpoint实例 + */ + public static NetworkEndpoint of(String s, Integer i) { + NetworkAddress networkAddress = new NetworkAddress(s); + NetworkPort networkPort = new NetworkPort(i); + return new NetworkEndpoint(networkAddress, networkPort); + } - /** - * 根据"host:port"格式的字符串创建NetworkEndpoint实例。 - * 例如:"127.0.0.1:8080" - * - * @param s "host:port"格式的字符串 - * @return 新建的NetworkEndpoint实例 - */ - public static NetworkEndpoint of(String s) { - // 查找最后一个冒号的位置,以支持IPv6地址中的冒号 - int lastColonIndex = s.lastIndexOf(':'); - return of( - s.substring(0, lastColonIndex), - Integer.parseInt(s.substring(lastColonIndex + 1)) - ); - } + /** + * 根据"host:port"格式的字符串创建NetworkEndpoint实例。 + * 例如:"127.0.0.1:8080" + * + * @param s "host:port"格式的字符串 + * @return 新建的NetworkEndpoint实例 + */ + public static NetworkEndpoint of(String s) { + // 查找最后一个冒号的位置,以支持IPv6地址中的冒号 + int lastColonIndex = s.lastIndexOf(':'); + return of( + s.substring(0, lastColonIndex), + Integer.parseInt(s.substring(lastColonIndex + 1)) + ); + } - /** - * 将当前NetworkEndpoint转换为InetSocketAddress对象。 - * - * @return 对应的InetSocketAddress对象 - * @see InetSocketAddress - */ - public InetSocketAddress toInetSocketAddress() { - return new InetSocketAddress( - networkAddress.toInetAddress(), - networkPort.getPort() - ); - } + /** + * 将当前NetworkEndpoint转换为InetSocketAddress对象。 + * + * @return 对应的InetSocketAddress对象 + * @see InetSocketAddress + */ + public InetSocketAddress toInetSocketAddress() { + return new InetSocketAddress( + networkAddress.toInetAddress(), + networkPort.getPort() + ); + } - /** - * 将当前NetworkEndpoint转换为"host:port"格式的字符串。 - * 例如:"127.0.0.1:25563" - * - * @return 格式化后的字符串 - */ - public String toHostPortString() { - return StringUtil.format( - "{}:{}", - networkAddress.getIp(), - networkPort.getPort() - ); - } + /** + * 将当前NetworkEndpoint转换为"host:port"格式的字符串。 + * 例如:"127.0.0.1:25563" + * + * @return 格式化后的字符串 + */ + public String toHostPortString() { + return StringUtil.format( + "{}:{}", + networkAddress.getIp(), + networkPort.getPort() + ); + } - /** - * 返回NetworkEndpoint的详细字符串表示形式。 - * 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...) - * - * @return 包含详细信息的字符串 - */ - public String toString() { - return StringUtil.format( - "NetworkEndpoint(IP={},Port={},Endpoint={})", - networkAddress.getIp(), - networkPort.getPort(), - toHostPortString() - ); - } + /** + * 返回NetworkEndpoint的详细字符串表示形式。 + * 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...) + * + * @return 包含详细信息的字符串 + */ + public String toString() { + return StringUtil.format( + "NetworkEndpoint(IP={},Port={},Endpoint={})", + networkAddress.getIp(), + networkPort.getPort(), + toHostPortString() + ); + } - /** - * 获取主机名或IP地址字符串。 - * - * @return 主机名或IP地址 - */ - public String getHost() { - return networkAddress.getIp(); - } + /** + * 获取主机名或IP地址字符串。 + * + * @return 主机名或IP地址 + */ + public String getHost() { + return networkAddress.getIp(); + } - /** - * 获取端口号。 - * - * @return 端口号 - */ - public Integer getPort() { - return networkPort.getPort(); - } + /** + * 获取端口号。 + * + * @return 端口号 + */ + public Integer getPort() { + return networkPort.getPort(); + } } diff --git a/src/com/mingliqiye/utils/network/NetworkException.java b/src/com/mingliqiye/utils/network/NetworkException.java index 597aea1..c0c5cb4 100644 --- a/src/com/mingliqiye/utils/network/NetworkException.java +++ b/src/com/mingliqiye/utils/network/NetworkException.java @@ -7,21 +7,21 @@ package com.mingliqiye.utils.network; */ public class NetworkException extends RuntimeException { - /** - * 构造一个带有指定详细消息的网络异常 - * - * @param message 异常的详细消息 - */ - public NetworkException(String message) { - super(message); - } + /** + * 构造一个带有指定详细消息的网络异常 + * + * @param message 异常的详细消息 + */ + public NetworkException(String message) { + super(message); + } - /** - * 构造一个网络异常,指定原因异常 - * - * @param e 导致此异常的原因异常 - */ - public NetworkException(Exception e) { - super(e); - } + /** + * 构造一个网络异常,指定原因异常 + * + * @param e 导致此异常的原因异常 + */ + public NetworkException(Exception e) { + super(e); + } } diff --git a/src/com/mingliqiye/utils/network/NetworkPort.java b/src/com/mingliqiye/utils/network/NetworkPort.java index 948bd26..0ce23dc 100644 --- a/src/com/mingliqiye/utils/network/NetworkPort.java +++ b/src/com/mingliqiye/utils/network/NetworkPort.java @@ -1,9 +1,8 @@ package com.mingliqiye.utils.network; import com.mingliqiye.utils.string.StringUtil; -import lombok.Getter; - import java.io.Serializable; +import lombok.Getter; /** * 网络端口类 @@ -12,31 +11,31 @@ import java.io.Serializable; */ public class NetworkPort implements Serializable { - @Getter - private final int port; + @Getter + private final int port; - /** - * 构造函数,创建一个网络端口对象 - * - * @param port 端口号,必须在0-65535范围内 - */ - public NetworkPort(int port) { - testPort(port); - this.port = port; - } + /** + * 构造函数,创建一个网络端口对象 + * + * @param port 端口号,必须在0-65535范围内 + */ + public NetworkPort(int port) { + testPort(port); + this.port = port; + } - /** - * 验证端口号是否合法 - * - * @param port 待验证的端口号 - * @throws NetworkException 当端口号不在合法范围(0-65535)内时抛出异常 - */ - public static void testPort(int port) { - // 验证端口号范围是否在0-65535之间 - if (!(0 <= port && 65535 >= port)) { - throw new NetworkException( - StringUtil.format("{} 不是正确的端口号", port) - ); - } - } + /** + * 验证端口号是否合法 + * + * @param port 待验证的端口号 + * @throws NetworkException 当端口号不在合法范围(0-65535)内时抛出异常 + */ + public static void testPort(int port) { + // 验证端口号范围是否在0-65535之间 + if (!(0 <= port && 65535 >= port)) { + throw new NetworkException( + StringUtil.format("{} 不是正确的端口号", port) + ); + } + } } diff --git a/src/com/mingliqiye/utils/string/StringUtil.java b/src/com/mingliqiye/utils/string/StringUtil.java index 23c6cef..c9744ab 100644 --- a/src/com/mingliqiye/utils/string/StringUtil.java +++ b/src/com/mingliqiye/utils/string/StringUtil.java @@ -1,7 +1,6 @@ package com.mingliqiye.utils.string; import com.mingliqiye.utils.collection.Lists; - import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -12,203 +11,203 @@ import java.util.List; */ public class StringUtil { - /** - * 将对象转换为字符串表示形式 - * - * @param obj 需要转换的对象,可以为null - * @return 如果对象为null则返回空字符串,否则返回对象的字符串表示 - */ - public static String toString(Object obj) { - // 如果对象为null,返回空字符串;否则调用对象的toString方法 - return obj == null ? "" : obj.toString(); - } + /** + * 将对象转换为字符串表示形式 + * + * @param obj 需要转换的对象,可以为null + * @return 如果对象为null则返回空字符串,否则返回对象的字符串表示 + */ + public static String toString(Object obj) { + // 如果对象为null,返回空字符串;否则调用对象的toString方法 + return obj == null ? "" : obj.toString(); + } - /** - * 格式化字符串,将格式字符串中的占位符{}替换为对应的参数值
- * 示例:输出 {} StringUtil.format("{},{},{}", "666", "{}", "777") - "666,{},777"
- * 示例 StringUtil.format("{},{},{},{}", "666", "{}", "777") - "666,{},777,"
- * 没有实际{} 会替换为 "" 空字符串 - * - * @param format 格式字符串,使用{}作为占位符,如果为null则返回null - * @param args 用于替换占位符的参数数组 - * @return 格式化后的字符串 - */ - public static String format(String format, Object... args) { - if (format == null) { - return null; - } + /** + * 格式化字符串,将格式字符串中的占位符{}替换为对应的参数值
+ * 示例:输出 {} StringUtil.format("{},{},{}", "666", "{}", "777") - "666,{},777"
+ * 示例 StringUtil.format("{},{},{},{}", "666", "{}", "777") - "666,{},777,"
+ * 没有实际{} 会替换为 "" 空字符串 + * + * @param format 格式字符串,使用{}作为占位符,如果为null则返回null + * @param args 用于替换占位符的参数数组 + * @return 格式化后的字符串 + */ + public static String format(String format, Object... args) { + if (format == null) { + return null; + } - StringBuilder sb = new StringBuilder(); - int placeholderCount = 0; - int lastIndex = 0; - int len = format.length(); + StringBuilder sb = new StringBuilder(); + int placeholderCount = 0; + int lastIndex = 0; + int len = format.length(); - for (int i = 0; i < len - 1; i++) { - if (format.charAt(i) == '{' && format.charAt(i + 1) == '}') { - // 添加前面的部分 - sb.append(format, lastIndex, i); - // 替换为 MessageFormat 占位符 {index} - sb.append('{').append(placeholderCount).append('}'); - placeholderCount++; - i++; // 跳过 '}' - lastIndex = i + 1; - } - } + for (int i = 0; i < len - 1; i++) { + if (format.charAt(i) == '{' && format.charAt(i + 1) == '}') { + // 添加前面的部分 + sb.append(format, lastIndex, i); + // 替换为 MessageFormat 占位符 {index} + sb.append('{').append(placeholderCount).append('}'); + placeholderCount++; + i++; // 跳过 '}' + lastIndex = i + 1; + } + } - // 添加剩余部分 - sb.append(format.substring(lastIndex)); + // 添加剩余部分 + sb.append(format.substring(lastIndex)); - // 构造实际参数数组 - Object[] actualArgs; - if (args.length < placeholderCount) { - actualArgs = new String[placeholderCount]; - System.arraycopy(args, 0, actualArgs, 0, args.length); - for (int i = args.length; i < placeholderCount; i++) { - actualArgs[i] = ""; - } - } else { - actualArgs = args; - } + // 构造实际参数数组 + Object[] actualArgs; + if (args.length < placeholderCount) { + actualArgs = new String[placeholderCount]; + System.arraycopy(args, 0, actualArgs, 0, args.length); + for (int i = args.length; i < placeholderCount; i++) { + actualArgs[i] = ""; + } + } else { + actualArgs = args; + } - // 如果没有占位符,直接返回格式化后的字符串 - if (placeholderCount == 0) { - return sb.toString(); - } + // 如果没有占位符,直接返回格式化后的字符串 + if (placeholderCount == 0) { + return sb.toString(); + } - try { - return MessageFormat.format( - sb.toString(), - (Object[]) Lists.toStringList(actualArgs) - ); - } catch (IllegalArgumentException e) { - // 返回原始格式化字符串或抛出自定义异常,视业务需求而定 - return sb.toString(); - } - } + try { + return MessageFormat.format( + sb.toString(), + (Object[]) Lists.toStringList(actualArgs) + ); + } catch (IllegalArgumentException e) { + // 返回原始格式化字符串或抛出自定义异常,视业务需求而定 + return sb.toString(); + } + } - /** - * 判断字符串是否为空 - * - * @param str 待检查的字符串 - * @return 如果字符串为null或空字符串则返回true,否则返回false - */ - public static boolean isEmpty(String str) { - return str == null || str.isEmpty(); - } + /** + * 判断字符串是否为空 + * + * @param str 待检查的字符串 + * @return 如果字符串为null或空字符串则返回true,否则返回false + */ + public static boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } - /** - * 使用指定的分隔符将多个对象连接成一个字符串 - * - * @param spec 用作分隔符的字符串 - * @param objects 要连接的对象数组 - * @return 使用指定分隔符连接后的字符串 - */ - public static String joinOf(String spec, String... objects) { - return join(spec, Arrays.asList(objects)); - } + /** + * 使用指定的分隔符将多个对象连接成一个字符串 + * + * @param spec 用作分隔符的字符串 + * @param objects 要连接的对象数组 + * @return 使用指定分隔符连接后的字符串 + */ + public static String joinOf(String spec, String... objects) { + return join(spec, Arrays.asList(objects)); + } - /** - * 将字符串按照指定分隔符分割成字符串列表,并移除列表开头的空字符串元素 - * - * @param str 待分割的字符串 - * @param separator 用作分割符的字符串 - * @return 分割后的字符串列表,不包含开头的空字符串元素 - */ - public static List split(String str, String separator) { - List data = new ArrayList<>( - Arrays.asList(str.split(separator)) - ); - // 移除列表开头的所有空字符串元素 - while (!data.isEmpty() && data.get(0).isEmpty()) { - data.remove(0); - } - return data; - } + /** + * 将字符串按照指定分隔符分割成字符串列表,并移除列表开头的空字符串元素 + * + * @param str 待分割的字符串 + * @param separator 用作分割符的字符串 + * @return 分割后的字符串列表,不包含开头的空字符串元素 + */ + public static List split(String str, String separator) { + List data = new ArrayList<>( + Arrays.asList(str.split(separator)) + ); + // 移除列表开头的所有空字符串元素 + while (!data.isEmpty() && data.get(0).isEmpty()) { + data.remove(0); + } + return data; + } - /** - * 将列表中的元素按照指定分隔符连接成字符串 - * - * @param

列表元素的类型 - * @param separator 分隔符,用于连接各个元素 - * @param list 待连接的元素列表 - * @param fun 转换函数,用于将列表元素转换为字符串,如果为null则使用toString()方法 - * @return 连接后的字符串,如果列表为空或null则返回空字符串 - */ - public static

String join( - String separator, - List

list, - PRFunction fun - ) { - // 处理空列表情况 - if (list == null || list.isEmpty()) { - return ""; - } + /** + * 将列表中的元素按照指定分隔符连接成字符串 + * + * @param

列表元素的类型 + * @param separator 分隔符,用于连接各个元素 + * @param list 待连接的元素列表 + * @param fun 转换函数,用于将列表元素转换为字符串,如果为null则使用toString()方法 + * @return 连接后的字符串,如果列表为空或null则返回空字符串 + */ + public static

String join( + String separator, + List

list, + PRFunction fun + ) { + // 处理空列表情况 + if (list == null || list.isEmpty()) { + return ""; + } - // 构建结果字符串 - StringBuilder sb = StringUtil.stringBuilder(list.size() * 16); - for (int i = 0; i < list.size(); i++) { - P item = list.get(i); - // 将元素转换为字符串 - String itemStr = fun == null - ? (item == null ? "null" : item.toString()) - : fun.call(item); + // 构建结果字符串 + StringBuilder sb = StringUtil.stringBuilder(list.size() * 16); + for (int i = 0; i < list.size(); i++) { + P item = list.get(i); + // 将元素转换为字符串 + String itemStr = fun == null + ? (item == null ? "null" : item.toString()) + : fun.call(item); - // 第一个元素直接添加,其他元素先添加分隔符再添加元素 - if (i == 0) { - sb.append(itemStr); - } else { - sb.append(separator).append(itemStr); - } - } - return sb.toString(); - } + // 第一个元素直接添加,其他元素先添加分隔符再添加元素 + if (i == 0) { + sb.append(itemStr); + } else { + sb.append(separator).append(itemStr); + } + } + return sb.toString(); + } - /** - * 使用指定分隔符连接字符串列表 - * - * @param separator 分隔符,不能为null - * @param list 字符串列表,不能为null - * @return 连接后的字符串 - * @throws IllegalArgumentException 当separator或list为null时抛出 - */ - public static String join(String separator, List list) { - if (separator == null) { - throw new IllegalArgumentException("Separator cannot be null"); - } - if (list == null) { - throw new IllegalArgumentException("List cannot be null"); - } - return join(separator, list, null); - } + /** + * 使用指定分隔符连接字符串列表 + * + * @param separator 分隔符,不能为null + * @param list 字符串列表,不能为null + * @return 连接后的字符串 + * @throws IllegalArgumentException 当separator或list为null时抛出 + */ + public static String join(String separator, List list) { + if (separator == null) { + throw new IllegalArgumentException("Separator cannot be null"); + } + if (list == null) { + throw new IllegalArgumentException("List cannot be null"); + } + return join(separator, list, null); + } - /** - * 创建一个新的StringBuilder实例 - * - * @param i 指定StringBuilder的初始容量 - * @return 返回一个新的StringBuilder对象,其初始容量为指定的大小 - */ - public static StringBuilder stringBuilder(int i) { - return new StringBuilder(i); - } + /** + * 创建一个新的StringBuilder实例 + * + * @param i 指定StringBuilder的初始容量 + * @return 返回一个新的StringBuilder对象,其初始容量为指定的大小 + */ + public static StringBuilder stringBuilder(int i) { + return new StringBuilder(i); + } - /** - * PRFunction接口表示一个接收参数P并返回结果R的函数式接口 - *

- * 该接口使用@FunctionalInterface注解标记,表明它是一个函数式接口, - * 只包含一个抽象方法call,可用于Lambda表达式和方法引用 - *

- * - * @param

函数接收的参数类型 - * @param 函数返回的结果类型 - */ - @FunctionalInterface - public interface PRFunction { - /** - * 执行函数调用 - * - * @param p 输入参数 - * @return 函数执行结果 - */ - R call(P p); - } + /** + * PRFunction接口表示一个接收参数P并返回结果R的函数式接口 + *

+ * 该接口使用@FunctionalInterface注解标记,表明它是一个函数式接口, + * 只包含一个抽象方法call,可用于Lambda表达式和方法引用 + *

+ * + * @param

函数接收的参数类型 + * @param 函数返回的结果类型 + */ + @FunctionalInterface + public interface PRFunction { + /** + * 执行函数调用 + * + * @param p 输入参数 + * @return 函数执行结果 + */ + R call(P p); + } } diff --git a/src/com/mingliqiye/utils/system/SystemUtil.java b/src/com/mingliqiye/utils/system/SystemUtil.java index 0bd9a19..f3a70bf 100644 --- a/src/com/mingliqiye/utils/system/SystemUtil.java +++ b/src/com/mingliqiye/utils/system/SystemUtil.java @@ -1,7 +1,6 @@ package com.mingliqiye.utils.system; import com.mingliqiye.utils.collection.Lists; - import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; @@ -17,182 +16,182 @@ import java.util.List; */ public class SystemUtil { - private static final String osName = System.getProperties().getProperty( - "os.name" - ); + private static final String osName = System.getProperties().getProperty( + "os.name" + ); - /** - * 判断当前操作系统是否为Windows系统 - * - * @return 如果是Windows系统返回true,否则返回false - */ - public static boolean isWindows() { - return osName != null && osName.startsWith("Windows"); - } + /** + * 判断当前操作系统是否为Windows系统 + * + * @return 如果是Windows系统返回true,否则返回false + */ + public static boolean isWindows() { + return osName != null && osName.startsWith("Windows"); + } - /** - * 判断当前操作系统是否为Mac系统 - * - * @return 如果是Mac系统返回true,否则返回false - */ - public static boolean isMac() { - return osName != null && osName.startsWith("Mac"); - } + /** + * 判断当前操作系统是否为Mac系统 + * + * @return 如果是Mac系统返回true,否则返回false + */ + public static boolean isMac() { + return osName != null && osName.startsWith("Mac"); + } - /** - * 判断当前操作系统是否为Unix/Linux系统 - * - * @return 如果是Unix/Linux系统返回true,否则返回false - */ - public static boolean isUnix() { - if (osName == null) { - return false; - } - return ( - osName.startsWith("Linux") || - osName.startsWith("AIX") || - osName.startsWith("SunOS") - ); - } + /** + * 判断当前操作系统是否为Unix/Linux系统 + * + * @return 如果是Unix/Linux系统返回true,否则返回false + */ + public static boolean isUnix() { + if (osName == null) { + return false; + } + return ( + osName.startsWith("Linux") || + osName.startsWith("AIX") || + osName.startsWith("SunOS") + ); + } - /** - * 获取JDK版本号 - * - * @return JDK版本号字符串 - */ - public static String getJdkVersion() { - return System.getProperty("java.specification.version"); - } + /** + * 获取JDK版本号 + * + * @return JDK版本号字符串 + */ + public static String getJdkVersion() { + return System.getProperty("java.specification.version"); + } - /** - * 获取Java版本号的整数形式 - * - * @return Java版本号的整数形式(如:8、11、17等) - */ - public static Integer getJavaVersionAsInteger() { - String version = getJdkVersion(); - if (version == null || version.isEmpty()) { - throw new IllegalStateException( - "Unable to determine Java version from property 'java.specification.version'" - ); - } + /** + * 获取Java版本号的整数形式 + * + * @return Java版本号的整数形式(如:8、11、17等) + */ + public static Integer getJavaVersionAsInteger() { + String version = getJdkVersion(); + if (version == null || version.isEmpty()) { + throw new IllegalStateException( + "Unable to determine Java version from property 'java.specification.version'" + ); + } - String uversion; - if (version.startsWith("1.")) { - if (version.length() < 3) { - throw new IllegalStateException( - "Invalid Java version format: " + version - ); - } - uversion = version.substring(2, 3); - } else { - if (version.length() < 2) { - throw new IllegalStateException( - "Invalid Java version format: " + version - ); - } - uversion = version.substring(0, 2); - } - return Integer.parseInt(uversion); - } + String uversion; + if (version.startsWith("1.")) { + if (version.length() < 3) { + throw new IllegalStateException( + "Invalid Java version format: " + version + ); + } + uversion = version.substring(2, 3); + } else { + if (version.length() < 2) { + throw new IllegalStateException( + "Invalid Java version format: " + version + ); + } + uversion = version.substring(0, 2); + } + return Integer.parseInt(uversion); + } - /** - * 判断当前JDK版本是否大于8 - * - * @return 如果JDK版本大于8返回true,否则返回false - */ - public static boolean isJdk8Plus() { - return getJavaVersionAsInteger() > 8; - } + /** + * 判断当前JDK版本是否大于8 + * + * @return 如果JDK版本大于8返回true,否则返回false + */ + public static boolean isJdk8Plus() { + return getJavaVersionAsInteger() > 8; + } - /** - * 获取本地IP地址数组 - * - * @return 本地IP地址字符串数组 - * @throws RuntimeException 当获取网络接口信息失败时抛出 - */ - public static String[] getLocalIps() { - try { - List ipList = new ArrayList<>(); - Enumeration interfaces = - NetworkInterface.getNetworkInterfaces(); + /** + * 获取本地IP地址数组 + * + * @return 本地IP地址字符串数组 + * @throws RuntimeException 当获取网络接口信息失败时抛出 + */ + public static String[] getLocalIps() { + try { + List ipList = new ArrayList<>(); + Enumeration interfaces = + NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface networkInterface = interfaces.nextElement(); - // 跳过回环接口和虚拟接口 - if ( - networkInterface.isLoopback() || - networkInterface.isVirtual() || - !networkInterface.isUp() - ) { - continue; - } + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = interfaces.nextElement(); + // 跳过回环接口和虚拟接口 + if ( + networkInterface.isLoopback() || + networkInterface.isVirtual() || + !networkInterface.isUp() + ) { + continue; + } - Enumeration addresses = - networkInterface.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress address = addresses.nextElement(); - // 只获取IPv4地址 - if (address instanceof Inet4Address) { - ipList.add(address.getHostAddress()); - } - } - } + Enumeration addresses = + networkInterface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress address = addresses.nextElement(); + // 只获取IPv4地址 + if (address instanceof Inet4Address) { + ipList.add(address.getHostAddress()); + } + } + } - return ipList.toArray(new String[0]); - } catch (SocketException e) { - throw new RuntimeException("Failed to get local IP addresses", e); - } - } + return ipList.toArray(new String[0]); + } catch (SocketException e) { + throw new RuntimeException("Failed to get local IP addresses", e); + } + } - /** - * 获取本地IP地址列表 - * - * @return 本地IP地址的字符串列表 - */ - public static List getLocalIpsByList() { - return Lists.newArrayList(getLocalIps()); - } + /** + * 获取本地IP地址列表 + * + * @return 本地IP地址的字符串列表 + */ + public static List getLocalIpsByList() { + return Lists.newArrayList(getLocalIps()); + } - /** - * 获取本地回环地址 - * - * @return 回环地址字符串,通常为"127.0.0.1" - */ - public static String[] getLoopbackIps() { - List strings = new ArrayList<>(3); - try { - Enumeration interfaces = - NetworkInterface.getNetworkInterfaces(); + /** + * 获取本地回环地址 + * + * @return 回环地址字符串,通常为"127.0.0.1" + */ + public static String[] getLoopbackIps() { + List strings = new ArrayList<>(3); + try { + Enumeration interfaces = + NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface networkInterface = interfaces.nextElement(); + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = interfaces.nextElement(); - // 只处理回环接口 - if (networkInterface.isLoopback() && networkInterface.isUp()) { - Enumeration addresses = - networkInterface.getInetAddresses(); + // 只处理回环接口 + if (networkInterface.isLoopback() && networkInterface.isUp()) { + Enumeration addresses = + networkInterface.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress address = addresses.nextElement(); - strings.add(address.getHostAddress()); - } - } - } - return strings.toArray(new String[0]); - } catch (SocketException e) { - // 可考虑添加日志记录 - return new String[] { "127.0.0.1" }; - } - } + while (addresses.hasMoreElements()) { + InetAddress address = addresses.nextElement(); + strings.add(address.getHostAddress()); + } + } + } + return strings.toArray(new String[0]); + } catch (SocketException e) { + // 可考虑添加日志记录 + return new String[] { "127.0.0.1" }; + } + } - /** - * 获取本地回环地址IP列表 - * - * @return 本地回环地址IP字符串列表的副本 - */ - public static List getLoopbackIpsByList() { - // 将本地回环地址IP数组转换为列表并返回 - return Lists.newArrayList(getLoopbackIps()); - } + /** + * 获取本地回环地址IP列表 + * + * @return 本地回环地址IP字符串列表的副本 + */ + public static List getLoopbackIpsByList() { + // 将本地回环地址IP数组转换为列表并返回 + return Lists.newArrayList(getLoopbackIps()); + } } diff --git a/src/com/mingliqiye/utils/time/DateTime.java b/src/com/mingliqiye/utils/time/DateTime.java index e21e47f..62b546c 100644 --- a/src/com/mingliqiye/utils/time/DateTime.java +++ b/src/com/mingliqiye/utils/time/DateTime.java @@ -1,14 +1,13 @@ package com.mingliqiye.utils.time; -import lombok.Getter; -import lombok.Setter; -import lombok.var; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Date; +import lombok.Getter; +import lombok.Setter; +import lombok.var; /** * 时间工具类,用于处理日期时间的转换、格式化等操作。 @@ -19,396 +18,396 @@ import java.util.Date; */ public final class DateTime { - @Getter - @Setter - private ZoneId zoneId = ZoneId.systemDefault(); + @Getter + @Setter + private ZoneId zoneId = ZoneId.systemDefault(); - @Getter - private LocalDateTime localDateTime; + @Getter + private LocalDateTime localDateTime; - /** - * 私有构造函数,使用指定的 LocalDateTime 初始化实例。 - * - * @param time LocalDateTime 对象 - */ - private DateTime(LocalDateTime time) { - setLocalDateTime(time); - } + /** + * 私有构造函数,使用指定的 LocalDateTime 初始化实例。 + * + * @param time LocalDateTime 对象 + */ + private DateTime(LocalDateTime time) { + setLocalDateTime(time); + } - /** - * 私有构造函数,使用当前系统时间初始化实例。 - */ - private DateTime() { - setLocalDateTime(LocalDateTime.now()); - } + /** + * 私有构造函数,使用当前系统时间初始化实例。 + */ + private DateTime() { + setLocalDateTime(LocalDateTime.now()); + } - /** - * 获取当前时间的 DateTime 实例。 - * - * @return 返回当前时间的 DateTime 实例 - */ - public static DateTime now() { - return new DateTime(); - } + /** + * 获取当前时间的 DateTime 实例。 + * + * @return 返回当前时间的 DateTime 实例 + */ + public static DateTime now() { + return new DateTime(); + } - /** - * 将 Date 对象转换为 DateTime 实例。 - * - * @param zoneId 时区信息 - * @param date Date 对象 - * @return 返回对应的 DateTime 实例 - */ - public static DateTime of(Date date, ZoneId zoneId) { - return new DateTime(date.toInstant().atZone(zoneId).toLocalDateTime()); - } + /** + * 将 Date 对象转换为 DateTime 实例。 + * + * @param zoneId 时区信息 + * @param date Date 对象 + * @return 返回对应的 DateTime 实例 + */ + public static DateTime of(Date date, ZoneId zoneId) { + return new DateTime(date.toInstant().atZone(zoneId).toLocalDateTime()); + } - /** - * 将 Date 对象转换为 DateTime 实例,使用系统默认时区。 - * - * @param date Date 对象 - * @return 返回对应的 DateTime 实例 - */ - public static DateTime of(Date date) { - return new DateTime( - date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() - ); - } + /** + * 将 Date 对象转换为 DateTime 实例,使用系统默认时区。 + * + * @param date Date 对象 + * @return 返回对应的 DateTime 实例 + */ + public static DateTime of(Date date) { + return new DateTime( + date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() + ); + } - /** - * 解析时间字符串并生成 DateTime 实例。 - * - * @param timestr 时间字符串 - * @param formatter 格式化模板 - * @param fillZero 是否补零到模板长度 - * @return 返回解析后的 DateTime 实例 - */ - public static DateTime parse( - String timestr, - String formatter, - boolean fillZero - ) { - return new DateTime( - LocalDateTime.parse( - fillZero ? getFillZeroByLen(timestr, formatter) : timestr, - DateTimeFormatter.ofPattern(formatter) - ) - ); - } + /** + * 解析时间字符串并生成 DateTime 实例。 + * + * @param timestr 时间字符串 + * @param formatter 格式化模板 + * @param fillZero 是否补零到模板长度 + * @return 返回解析后的 DateTime 实例 + */ + public static DateTime parse( + String timestr, + String formatter, + boolean fillZero + ) { + return new DateTime( + LocalDateTime.parse( + fillZero ? getFillZeroByLen(timestr, formatter) : timestr, + DateTimeFormatter.ofPattern(formatter) + ) + ); + } - /** - * 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例。 - * - * @param timestr 时间字符串 - * @param formatter 格式化模板枚举 - * @param fillZero 是否补零到模板长度 - * @return 返回解析后的 DateTime 实例 - */ - public static DateTime parse( - String timestr, - Formatter formatter, - boolean fillZero - ) { - return parse(timestr, formatter.getValue(), fillZero); - } + /** + * 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例。 + * + * @param timestr 时间字符串 + * @param formatter 格式化模板枚举 + * @param fillZero 是否补零到模板长度 + * @return 返回解析后的 DateTime 实例 + */ + public static DateTime parse( + String timestr, + Formatter formatter, + boolean fillZero + ) { + return parse(timestr, formatter.getValue(), fillZero); + } - /** - * 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例,默认不补零。 - * - * @param timestr 时间字符串 - * @param formatter 格式化模板枚举 - * @return 返回解析后的 DateTime 实例 - */ - public static DateTime parse(String timestr, Formatter formatter) { - return parse(timestr, formatter.getValue()); - } + /** + * 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例,默认不补零。 + * + * @param timestr 时间字符串 + * @param formatter 格式化模板枚举 + * @return 返回解析后的 DateTime 实例 + */ + public static DateTime parse(String timestr, Formatter formatter) { + return parse(timestr, formatter.getValue()); + } - /** - * 解析时间字符串并生成 DateTime 实例,默认不补零。 - * - * @param timestr 时间字符串 - * @param formatter 格式化模板 - * @return 返回解析后的 DateTime 实例 - */ - public static DateTime parse(String timestr, String formatter) { - return parse(timestr, formatter, false); - } + /** + * 解析时间字符串并生成 DateTime 实例,默认不补零。 + * + * @param timestr 时间字符串 + * @param formatter 格式化模板 + * @return 返回解析后的 DateTime 实例 + */ + public static DateTime parse(String timestr, String formatter) { + return parse(timestr, formatter, false); + } - /** - * 补零处理时间字符串以匹配格式化模板长度。 - * - * @param dstr 原始时间字符串 - * @param formats 格式化模板 - * @return 补零后的时间字符串 - */ - private static String getFillZeroByLen(String dstr, String formats) { - if (dstr.length() == formats.length()) { - return dstr; - } - if (formats.length() > dstr.length()) { - if (dstr.length() == 19) { - dstr += "."; - } - var sb = new StringBuilder(dstr); - for (int i = 0; i < formats.length() - dstr.length(); i++) { - sb.append("0"); - } - return sb.toString(); - } - throw new IllegalArgumentException( - String.format( - "Text: '%s' len %s < %s %s", - dstr, - dstr.length(), - formats, - formats.length() - ) - ); - } + /** + * 补零处理时间字符串以匹配格式化模板长度。 + * + * @param dstr 原始时间字符串 + * @param formats 格式化模板 + * @return 补零后的时间字符串 + */ + private static String getFillZeroByLen(String dstr, String formats) { + if (dstr.length() == formats.length()) { + return dstr; + } + if (formats.length() > dstr.length()) { + if (dstr.length() == 19) { + dstr += "."; + } + var sb = new StringBuilder(dstr); + for (int i = 0; i < formats.length() - dstr.length(); i++) { + sb.append("0"); + } + return sb.toString(); + } + throw new IllegalArgumentException( + String.format( + "Text: '%s' len %s < %s %s", + dstr, + dstr.length(), + formats, + formats.length() + ) + ); + } - /** - * 根据年、月、日创建 DateTime 实例 - * - * @param year 年份 - * @param month 月份 (1-12) - * @param day 日期 (1-31) - * @return 返回指定日期的 DateTime 实例(时间部分为 00:00:00) - */ - public static DateTime of(int year, int month, int day) { - return new DateTime(LocalDateTime.of(year, month, day, 0, 0)); - } + /** + * 根据年、月、日创建 DateTime 实例 + * + * @param year 年份 + * @param month 月份 (1-12) + * @param day 日期 (1-31) + * @return 返回指定日期的 DateTime 实例(时间部分为 00:00:00) + */ + public static DateTime of(int year, int month, int day) { + return new DateTime(LocalDateTime.of(year, month, day, 0, 0)); + } - /** - * 根据年、月、日、时、分创建 DateTime 实例 - * - * @param year 年份 - * @param month 月份 (1-12) - * @param day 日期 (1-31) - * @param hour 小时 (0-23) - * @param minute 分钟 (0-59) - * @return 返回指定日期时间的 DateTime 实例(秒部分为 00) - */ - public static DateTime of( - int year, - int month, - int day, - int hour, - int minute - ) { - return new DateTime(LocalDateTime.of(year, month, day, hour, minute)); - } + /** + * 根据年、月、日、时、分创建 DateTime 实例 + * + * @param year 年份 + * @param month 月份 (1-12) + * @param day 日期 (1-31) + * @param hour 小时 (0-23) + * @param minute 分钟 (0-59) + * @return 返回指定日期时间的 DateTime 实例(秒部分为 00) + */ + public static DateTime of( + int year, + int month, + int day, + int hour, + int minute + ) { + return new DateTime(LocalDateTime.of(year, month, day, hour, minute)); + } - /** - * 根据年、月、日、时、分、秒创建 DateTime 实例 - * - * @param year 年份 - * @param month 月份 (1-12) - * @param day 日期 (1-31) - * @param hour 小时 (0-23) - * @param minute 分钟 (0-59) - * @param second 秒 (0-59) - * @return 返回指定日期时间的 DateTime 实例 - */ - public static DateTime of( - int year, - int month, - int day, - int hour, - int minute, - int second - ) { - return new DateTime( - LocalDateTime.of(year, month, day, hour, minute, second) - ); - } + /** + * 根据年、月、日、时、分、秒创建 DateTime 实例 + * + * @param year 年份 + * @param month 月份 (1-12) + * @param day 日期 (1-31) + * @param hour 小时 (0-23) + * @param minute 分钟 (0-59) + * @param second 秒 (0-59) + * @return 返回指定日期时间的 DateTime 实例 + */ + public static DateTime of( + int year, + int month, + int day, + int hour, + int minute, + int second + ) { + return new DateTime( + LocalDateTime.of(year, month, day, hour, minute, second) + ); + } - /** - * 根据年、月、日、时、分、秒、纳秒创建 DateTime 实例 - * - * @param year 年份 - * @param month 月份 (1-12) - * @param day 日期 (1-31) - * @param hour 小时 (0-23) - * @param minute 分钟 (0-59) - * @param second 秒 (0-59) - * @param nano 纳秒 (0-999,999,999) - * @return 返回指定日期时间的 DateTime 实例 - */ - public static DateTime of( - int year, - int month, - int day, - int hour, - int minute, - int second, - int nano - ) { - return new DateTime( - LocalDateTime.of(year, month, day, hour, minute, second, nano) - ); - } + /** + * 根据年、月、日、时、分、秒、纳秒创建 DateTime 实例 + * + * @param year 年份 + * @param month 月份 (1-12) + * @param day 日期 (1-31) + * @param hour 小时 (0-23) + * @param minute 分钟 (0-59) + * @param second 秒 (0-59) + * @param nano 纳秒 (0-999,999,999) + * @return 返回指定日期时间的 DateTime 实例 + */ + public static DateTime of( + int year, + int month, + int day, + int hour, + int minute, + int second, + int nano + ) { + return new DateTime( + LocalDateTime.of(year, month, day, hour, minute, second, nano) + ); + } - /** - * 根据毫秒时间戳创建 DateTime 实例 - * - * @param epochMilli 毫秒时间戳 - * @return 返回对应时间的 DateTime 实例 - */ - public static DateTime of(long epochMilli) { - return new DateTime( - Instant.ofEpochMilli(epochMilli) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime() - ); - } + /** + * 根据毫秒时间戳创建 DateTime 实例 + * + * @param epochMilli 毫秒时间戳 + * @return 返回对应时间的 DateTime 实例 + */ + public static DateTime of(long epochMilli) { + return new DateTime( + Instant.ofEpochMilli(epochMilli) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + ); + } - /** - * 根据毫秒时间戳和时区创建 DateTime 实例 - * - * @param epochMilli 毫秒时间戳 - * @param zoneId 时区信息 - * @return 返回对应时间的 DateTime 实例 - */ - public static DateTime of(long epochMilli, ZoneId zoneId) { - return new DateTime( - Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime() - ); - } + /** + * 根据毫秒时间戳和时区创建 DateTime 实例 + * + * @param epochMilli 毫秒时间戳 + * @param zoneId 时区信息 + * @return 返回对应时间的 DateTime 实例 + */ + public static DateTime of(long epochMilli, ZoneId zoneId) { + return new DateTime( + Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime() + ); + } - /** - * 设置 LocalDateTime 实例。 - * - * @param localDateTime LocalDateTime 对象 - */ - public void setLocalDateTime(LocalDateTime localDateTime) { - this.localDateTime = localDateTime; - } + /** + * 设置 LocalDateTime 实例。 + * + * @param localDateTime LocalDateTime 对象 + */ + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } - /** - * 将当前 DateTime 转换为 Date 对象。 - * - * @return 返回对应的 Date 对象 - */ - public Date toDate() { - return Date.from(localDateTime.atZone(getZoneId()).toInstant()); - } + /** + * 将当前 DateTime 转换为 Date 对象。 + * + * @return 返回对应的 Date 对象 + */ + public Date toDate() { + return Date.from(localDateTime.atZone(getZoneId()).toInstant()); + } - /** - * 获取当前 DateTime 中的 LocalDateTime 实例。 - * - * @return 返回 LocalDateTime 对象 - */ - public LocalDateTime toLocalDateTime() { - return localDateTime; - } + /** + * 获取当前 DateTime 中的 LocalDateTime 实例。 + * + * @return 返回 LocalDateTime 对象 + */ + public LocalDateTime toLocalDateTime() { + return localDateTime; + } - /** - * 在当前时间基础上增加指定的时间偏移量。 - * - * @param dateTimeOffset 时间偏移对象 - * @return 返回修改后的 DateTime 实例 - */ - public DateTime add(DateTimeOffset dateTimeOffset) { - this.localDateTime = this.localDateTime.plus( - dateTimeOffset.getOffset(), - dateTimeOffset.getOffsetType() - ); - return this; - } + /** + * 在当前时间基础上增加指定的时间偏移量。 + * + * @param dateTimeOffset 时间偏移对象 + * @return 返回修改后的 DateTime 实例 + */ + public DateTime add(DateTimeOffset dateTimeOffset) { + this.localDateTime = this.localDateTime.plus( + dateTimeOffset.getOffset(), + dateTimeOffset.getOffsetType() + ); + return this; + } - /** - * 在当前时间基础上减少指定的时间偏移量。 - * - * @param dateTimeOffset 时间偏移对象 - * @return 返回修改后的 DateTime 实例 - */ - public DateTime sub(DateTimeOffset dateTimeOffset) { - this.localDateTime = this.localDateTime.plus( - -dateTimeOffset.getOffset(), - dateTimeOffset.getOffsetType() - ); - return this; - } + /** + * 在当前时间基础上减少指定的时间偏移量。 + * + * @param dateTimeOffset 时间偏移对象 + * @return 返回修改后的 DateTime 实例 + */ + public DateTime sub(DateTimeOffset dateTimeOffset) { + this.localDateTime = this.localDateTime.plus( + -dateTimeOffset.getOffset(), + dateTimeOffset.getOffsetType() + ); + return this; + } - /** - * 使用指定格式化模板将当前时间格式化为字符串。 - * - * @param formatter 格式化模板 - * @return 返回格式化后的时间字符串 - */ - public String format(String formatter) { - return format(formatter, false); - } + /** + * 使用指定格式化模板将当前时间格式化为字符串。 + * + * @param formatter 格式化模板 + * @return 返回格式化后的时间字符串 + */ + public String format(String formatter) { + return format(formatter, false); + } - /** - * 使用 Formatter 枚举将当前时间格式化为字符串。 - * - * @param formatter 格式化模板枚举 - * @return 返回格式化后的时间字符串 - */ - public String format(Formatter formatter) { - return format(formatter.getValue()); - } + /** + * 使用 Formatter 枚举将当前时间格式化为字符串。 + * + * @param formatter 格式化模板枚举 + * @return 返回格式化后的时间字符串 + */ + public String format(Formatter formatter) { + return format(formatter.getValue()); + } - /** - * 使用指定格式化模板将当前时间格式化为字符串,并可选择是否去除末尾多余的零。 - * - * @param formatter 格式化模板 - * @param repcZero 是否去除末尾多余的零 - * @return 返回格式化后的时间字符串 - */ - public String format(String formatter, boolean repcZero) { - var formatted = DateTimeFormatter.ofPattern(formatter).format( - toLocalDateTime() - ); - if (repcZero) { - // 处理小数点后多余的0 - formatted = formatted.replaceAll("(\\.\\d*?)0+\\b", "$1"); - formatted = formatted.replaceAll("\\.$", ""); - } - return formatted; - } + /** + * 使用指定格式化模板将当前时间格式化为字符串,并可选择是否去除末尾多余的零。 + * + * @param formatter 格式化模板 + * @param repcZero 是否去除末尾多余的零 + * @return 返回格式化后的时间字符串 + */ + public String format(String formatter, boolean repcZero) { + var formatted = DateTimeFormatter.ofPattern(formatter).format( + toLocalDateTime() + ); + if (repcZero) { + // 处理小数点后多余的0 + formatted = formatted.replaceAll("(\\.\\d*?)0+\\b", "$1"); + formatted = formatted.replaceAll("\\.$", ""); + } + return formatted; + } - /** - * 使用 Formatter 枚举将当前时间格式化为字符串,并可选择是否去除末尾多余的零。 - * - * @param formatter 格式化模板枚举 - * @param repcZero 是否去除末尾多余的零 - * @return 返回格式化后的时间字符串 - */ - public String format(Formatter formatter, boolean repcZero) { - return format(formatter.getValue(), repcZero); - } + /** + * 使用 Formatter 枚举将当前时间格式化为字符串,并可选择是否去除末尾多余的零。 + * + * @param formatter 格式化模板枚举 + * @param repcZero 是否去除末尾多余的零 + * @return 返回格式化后的时间字符串 + */ + public String format(Formatter formatter, boolean repcZero) { + return format(formatter.getValue(), repcZero); + } - /** - * 返回当前时间的标准字符串表示形式。 - * - * @return 返回标准格式的时间字符串 - */ - @Override - public String toString() { - return String.format( - "DateTime(%s)", - format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true) - ); - } + /** + * 返回当前时间的标准字符串表示形式。 + * + * @return 返回标准格式的时间字符串 + */ + @Override + public String toString() { + return String.format( + "DateTime(%s)", + format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true) + ); + } - /** - * 比较当前DateTime对象与指定对象是否相等 - * - * @param obj 要比较的对象 - * @return 如果对象相等则返回true,否则返回false - */ - @Override - public boolean equals(Object obj) { - // 检查对象类型是否为DateTime - if (obj instanceof DateTime) { - // 比较两个DateTime对象转换为LocalDateTime后的值 - return toLocalDateTime().equals(((DateTime) obj).toLocalDateTime()); - } - return false; - } + /** + * 比较当前DateTime对象与指定对象是否相等 + * + * @param obj 要比较的对象 + * @return 如果对象相等则返回true,否则返回false + */ + @Override + public boolean equals(Object obj) { + // 检查对象类型是否为DateTime + if (obj instanceof DateTime) { + // 比较两个DateTime对象转换为LocalDateTime后的值 + return toLocalDateTime().equals(((DateTime) obj).toLocalDateTime()); + } + return false; + } - public Instant toInstant() { - return localDateTime.atZone(zoneId).toInstant(); - } + public Instant toInstant() { + return localDateTime.atZone(zoneId).toInstant(); + } } diff --git a/src/com/mingliqiye/utils/time/DateTimeOffset.java b/src/com/mingliqiye/utils/time/DateTimeOffset.java index 2b071b8..220f904 100644 --- a/src/com/mingliqiye/utils/time/DateTimeOffset.java +++ b/src/com/mingliqiye/utils/time/DateTimeOffset.java @@ -11,33 +11,33 @@ import lombok.Getter; @Getter public class DateTimeOffset { - private final ChronoUnit offsetType; - private final Long offset; + private final ChronoUnit offsetType; + private final Long offset; - private DateTimeOffset(ChronoUnit offsetType, Long offset) { - this.offsetType = offsetType; - this.offset = offset; - } + private DateTimeOffset(ChronoUnit offsetType, Long offset) { + this.offsetType = offsetType; + this.offset = offset; + } - /** - * 创建一个新的DateTimeOffset实例 - * - * @param offsetType 偏移量的单位类型,指定偏移量的计算单位 - * @param offset 偏移量的数值,可以为正数、负数或零 - * @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息 - */ - public static DateTimeOffset of(ChronoUnit offsetType, Long offset) { - return new DateTimeOffset(offsetType, offset); - } + /** + * 创建一个新的DateTimeOffset实例 + * + * @param offsetType 偏移量的单位类型,指定偏移量的计算单位 + * @param offset 偏移量的数值,可以为正数、负数或零 + * @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息 + */ + public static DateTimeOffset of(ChronoUnit offsetType, Long offset) { + return new DateTimeOffset(offsetType, offset); + } - /** - * 创建一个 DateTimeOffset 实例 - * - * @param offset 偏移量数值 - * @param offsetType 偏移量的时间单位类型 - * @return 返回一个新的 DateTimeOffset 实例 - */ - public static DateTimeOffset of(Long offset, ChronoUnit offsetType) { - return new DateTimeOffset(offsetType, offset); - } + /** + * 创建一个 DateTimeOffset 实例 + * + * @param offset 偏移量数值 + * @param offsetType 偏移量的时间单位类型 + * @return 返回一个新的 DateTimeOffset 实例 + */ + public static DateTimeOffset of(Long offset, ChronoUnit offsetType) { + return new DateTimeOffset(offsetType, offset); + } } diff --git a/src/com/mingliqiye/utils/time/DateTimeUnit.java b/src/com/mingliqiye/utils/time/DateTimeUnit.java index 516f936..c3dc291 100644 --- a/src/com/mingliqiye/utils/time/DateTimeUnit.java +++ b/src/com/mingliqiye/utils/time/DateTimeUnit.java @@ -6,38 +6,38 @@ package com.mingliqiye.utils.time; * @author MingLiPro */ public interface DateTimeUnit { - // 时间单位常量 - String YEAR = "year"; - String MONTH = "month"; - String WEEK = "week"; - String DAY = "day"; - String HOUR = "hour"; - String MINUTE = "minute"; - String SECOND = "second"; - String MILLISECOND = "millisecond"; - String MICROSECOND = "microsecond"; - String NANOSECOND = "nanosecond"; + // 时间单位常量 + String YEAR = "year"; + String MONTH = "month"; + String WEEK = "week"; + String DAY = "day"; + String HOUR = "hour"; + String MINUTE = "minute"; + String SECOND = "second"; + String MILLISECOND = "millisecond"; + String MICROSECOND = "microsecond"; + String NANOSECOND = "nanosecond"; - // 时间单位缩写 - String YEAR_ABBR = "y"; - String MONTH_ABBR = "M"; - String WEEK_ABBR = "w"; - String DAY_ABBR = "d"; - String HOUR_ABBR = "h"; - String MINUTE_ABBR = "m"; - String SECOND_ABBR = "s"; - String MILLISECOND_ABBR = "ms"; - String MICROSECOND_ABBR = "μs"; - String NANOSECOND_ABBR = "ns"; + // 时间单位缩写 + String YEAR_ABBR = "y"; + String MONTH_ABBR = "M"; + String WEEK_ABBR = "w"; + String DAY_ABBR = "d"; + String HOUR_ABBR = "h"; + String MINUTE_ABBR = "m"; + String SECOND_ABBR = "s"; + String MILLISECOND_ABBR = "ms"; + String MICROSECOND_ABBR = "μs"; + String NANOSECOND_ABBR = "ns"; - // 时间单位转换系数(毫秒为基准) - long MILLIS_PER_SECOND = 1000L; - long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; - long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; - long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; - long MILLIS_PER_WEEK = 7 * MILLIS_PER_DAY; + // 时间单位转换系数(毫秒为基准) + long MILLIS_PER_SECOND = 1000L; + long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; + long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; + long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; + long MILLIS_PER_WEEK = 7 * MILLIS_PER_DAY; - // 月份和年的毫秒数仅为近似值 - long MILLIS_PER_MONTH = 30 * MILLIS_PER_DAY; // 近似值 - long MILLIS_PER_YEAR = 365 * MILLIS_PER_DAY; // 近似值 + // 月份和年的毫秒数仅为近似值 + long MILLIS_PER_MONTH = 30 * MILLIS_PER_DAY; // 近似值 + long MILLIS_PER_YEAR = 365 * MILLIS_PER_DAY; // 近似值 } diff --git a/src/com/mingliqiye/utils/time/Formatter.java b/src/com/mingliqiye/utils/time/Formatter.java index e7e0152..b89c452 100644 --- a/src/com/mingliqiye/utils/time/Formatter.java +++ b/src/com/mingliqiye/utils/time/Formatter.java @@ -10,84 +10,84 @@ import lombok.Getter; *

*/ public enum Formatter { - /** - * 标准日期时间格式:yyyy-MM-dd HH:mm:ss - */ - STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"), + /** + * 标准日期时间格式:yyyy-MM-dd HH:mm:ss + */ + STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"), - /** - * 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS - */ - STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"), + /** + * 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS + */ + STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"), - /** - * 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS - */ - STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"), + /** + * 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS + */ + STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"), - /** - * 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS - */ - STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"), + /** + * 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS + */ + STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"), - /** - * 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS - */ - STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"), + /** + * 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS + */ + STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"), - /** - * 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS - */ - STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"), + /** + * 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS + */ + STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"), - /** - * 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS - */ - STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"), + /** + * 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS + */ + STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"), - /** - * 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S - */ - STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"), + /** + * 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S + */ + STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"), - /** - * 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z' - */ - STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), + /** + * 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + */ + STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"), - /** - * 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss - */ - STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"), + /** + * 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss + */ + STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"), - /** - * 标准日期格式:yyyy-MM-dd - */ - STANDARD_DATE("yyyy-MM-dd"), + /** + * 标准日期格式:yyyy-MM-dd + */ + STANDARD_DATE("yyyy-MM-dd"), - /** - * ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSS'000' - */ - ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"), + /** + * ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSS'000' + */ + ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"), - /** - * 紧凑型日期时间格式:yyyyMMddHHmmss - */ - COMPACT_DATETIME("yyyyMMddHHmmss"); + /** + * 紧凑型日期时间格式:yyyyMMddHHmmss + */ + COMPACT_DATETIME("yyyyMMddHHmmss"); - @Getter - private final String value; + @Getter + private final String value; - @Getter - private final int len; + @Getter + private final int len; - /** - * 构造函数 - * - * @param value 格式化模式字符串 - */ - Formatter(String value) { - this.value = value; - this.len = value.length(); - } + /** + * 构造函数 + * + * @param value 格式化模式字符串 + */ + Formatter(String value) { + this.value = value; + this.len = value.length(); + } } diff --git a/src/com/mingliqiye/utils/time/serialization/Jackson.java b/src/com/mingliqiye/utils/time/serialization/Jackson.java index fabbff9..953f794 100644 --- a/src/com/mingliqiye/utils/time/serialization/Jackson.java +++ b/src/com/mingliqiye/utils/time/serialization/Jackson.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.Formatter; - import java.io.IOException; /** @@ -21,168 +20,168 @@ import java.io.IOException; */ public class Jackson { - /** - * yyyy-MM-dd HH:mm:ss.SSSSSSS 的反序列化适配器 - *

- * 将 JSON 字符串按照指定格式解析为 DateTime 对象。 - */ - public static class DateTimeJsonDeserializerM7 - extends DateTimeJsonDeserializer { + /** + * yyyy-MM-dd HH:mm:ss.SSSSSSS 的反序列化适配器 + *

+ * 将 JSON 字符串按照指定格式解析为 DateTime 对象。 + */ + public static class DateTimeJsonDeserializerM7 + extends DateTimeJsonDeserializer { - /** - * 获取当前使用的日期时间格式化器 - * - * @return 返回标准的 7 位毫秒时间格式化器 - */ - @Override - public Formatter getFormatter() { - return Formatter.STANDARD_DATETIME_MILLISECOUND7; - } - } + /** + * 获取当前使用的日期时间格式化器 + * + * @return 返回标准的 7 位毫秒时间格式化器 + */ + @Override + public Formatter getFormatter() { + return Formatter.STANDARD_DATETIME_MILLISECOUND7; + } + } - /** - * 默认日期时间反序列化器 - *

- * 提供基础的日期时间反序列化功能,支持自定义格式化器。 - */ - public static class DateTimeJsonDeserializer - extends JsonDeserializer { + /** + * 默认日期时间反序列化器 + *

+ * 提供基础的日期时间反序列化功能,支持自定义格式化器。 + */ + public static class DateTimeJsonDeserializer + extends JsonDeserializer { - /** - * 获取当前使用的日期时间格式化器 - * - * @return 返回标准的日期时间格式化器 - */ - public Formatter getFormatter() { - return Formatter.STANDARD_DATETIME; - } + /** + * 获取当前使用的日期时间格式化器 + * + * @return 返回标准的日期时间格式化器 + */ + public Formatter getFormatter() { + return Formatter.STANDARD_DATETIME; + } - /** - * 获取格式化器对应的字符串表达式 - * - * @return 格式化器的字符串值 - */ - public String getFormatterString() { - return getFormatter().getValue(); - } + /** + * 获取格式化器对应的字符串表达式 + * + * @return 格式化器的字符串值 + */ + public String getFormatterString() { + return getFormatter().getValue(); + } - /** - * 反序列化方法:将 JSON 解析为 DateTime 对象 - * - * @param p JSON 解析器对象 - * @param ctxt 反序列化上下文 - * @return 解析后的 DateTime 对象,若输入为 NaN 则返回 null - * @throws IOException 当解析过程中发生 IO 异常时抛出 - */ - @Override - public DateTime deserialize(JsonParser p, DeserializationContext ctxt) - throws IOException { - // 如果是 NaN 值则返回 null - if (p.isNaN()) { - return null; - } - // 使用指定格式将字符串解析为 DateTime 对象 - return DateTime.parse( - p.getValueAsString(), - getFormatterString(), - true - ); - } - } + /** + * 反序列化方法:将 JSON 解析为 DateTime 对象 + * + * @param p JSON 解析器对象 + * @param ctxt 反序列化上下文 + * @return 解析后的 DateTime 对象,若输入为 NaN 则返回 null + * @throws IOException 当解析过程中发生 IO 异常时抛出 + */ + @Override + public DateTime deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException { + // 如果是 NaN 值则返回 null + if (p.isNaN()) { + return null; + } + // 使用指定格式将字符串解析为 DateTime 对象 + return DateTime.parse( + p.getValueAsString(), + getFormatterString(), + true + ); + } + } - /** - * yyyy-MM-dd HH:mm:ss.SSSSSSS 的序列化适配器 - *

- * 将 DateTime 对象按指定格式转换为 JSON 字符串。 - */ - public static class DateTimeJsonSerializerM7 - extends DateTimeJsonSerializer { + /** + * yyyy-MM-dd HH:mm:ss.SSSSSSS 的序列化适配器 + *

+ * 将 DateTime 对象按指定格式转换为 JSON 字符串。 + */ + public static class DateTimeJsonSerializerM7 + extends DateTimeJsonSerializer { - /** - * 获取当前使用的日期时间格式化器 - * - * @return 返回标准的 7 位毫秒时间格式化器 - */ - @Override - public Formatter getFormatter() { - return Formatter.STANDARD_DATETIME_MILLISECOUND7; - } - } + /** + * 获取当前使用的日期时间格式化器 + * + * @return 返回标准的 7 位毫秒时间格式化器 + */ + @Override + public Formatter getFormatter() { + return Formatter.STANDARD_DATETIME_MILLISECOUND7; + } + } - /** - * 默认日期时间序列化器 - *

- * 提供基础的日期时间序列化功能,支持自定义格式化器。 - */ - public static class DateTimeJsonSerializer - extends JsonSerializer { + /** + * 默认日期时间序列化器 + *

+ * 提供基础的日期时间序列化功能,支持自定义格式化器。 + */ + public static class DateTimeJsonSerializer + extends JsonSerializer { - /** - * 获取当前使用的日期时间格式化器 - * - * @return 返回标准的日期时间格式化器 - */ - public Formatter getFormatter() { - return Formatter.STANDARD_DATETIME; - } + /** + * 获取当前使用的日期时间格式化器 + * + * @return 返回标准的日期时间格式化器 + */ + public Formatter getFormatter() { + return Formatter.STANDARD_DATETIME; + } - /** - * 获取格式化器对应的字符串表达式 - * - * @return 格式化器的字符串值 - */ - public String getFormatterString() { - return getFormatter().getValue(); - } + /** + * 获取格式化器对应的字符串表达式 + * + * @return 格式化器的字符串值 + */ + public String getFormatterString() { + return getFormatter().getValue(); + } - /** - * 序列化方法:将 DateTime 对象写入 JSON 生成器 - * - * @param value 要序列化的 DateTime 对象 - * @param gen JSON 生成器 - * @param serializers 序列化提供者 - * @throws IOException 当写入过程中发生 IO 异常时抛出 - */ - @Override - public void serialize( - DateTime value, - JsonGenerator gen, - SerializerProvider serializers - ) throws IOException { - // 若值为 null,则直接写入 null - if (value == null) { - gen.writeNull(); - return; - } - // 按照指定格式将 DateTime 写入为字符串 - gen.writeString(value.format(getFormatterString(), true)); - } + /** + * 序列化方法:将 DateTime 对象写入 JSON 生成器 + * + * @param value 要序列化的 DateTime 对象 + * @param gen JSON 生成器 + * @param serializers 序列化提供者 + * @throws IOException 当写入过程中发生 IO 异常时抛出 + */ + @Override + public void serialize( + DateTime value, + JsonGenerator gen, + SerializerProvider serializers + ) throws IOException { + // 若值为 null,则直接写入 null + if (value == null) { + gen.writeNull(); + return; + } + // 按照指定格式将 DateTime 写入为字符串 + gen.writeString(value.format(getFormatterString(), true)); + } - /** - * 带类型信息的序列化方法:用于支持多态类型处理 - * - * @param value 要序列化的 DateTime 对象 - * @param gen JSON 生成器 - * @param serializers 序列化提供者 - * @param typeSer 类型序列化器 - * @throws IOException 当写入过程中发生 IO 异常时抛出 - */ - @Override - public void serializeWithType( - DateTime value, - JsonGenerator gen, - SerializerProvider serializers, - TypeSerializer typeSer - ) throws IOException { - // 写入类型前缀 - WritableTypeId typeId = typeSer.writeTypePrefix( - gen, - typeSer.typeId(value, JsonToken.VALUE_STRING) - ); - // 执行实际序列化 - serialize(value, gen, serializers); - // 写入类型后缀 - typeSer.writeTypeSuffix(gen, typeId); - } - } + /** + * 带类型信息的序列化方法:用于支持多态类型处理 + * + * @param value 要序列化的 DateTime 对象 + * @param gen JSON 生成器 + * @param serializers 序列化提供者 + * @param typeSer 类型序列化器 + * @throws IOException 当写入过程中发生 IO 异常时抛出 + */ + @Override + public void serializeWithType( + DateTime value, + JsonGenerator gen, + SerializerProvider serializers, + TypeSerializer typeSer + ) throws IOException { + // 写入类型前缀 + WritableTypeId typeId = typeSer.writeTypePrefix( + gen, + typeSer.typeId(value, JsonToken.VALUE_STRING) + ); + // 执行实际序列化 + serialize(value, gen, serializers); + // 写入类型后缀 + typeSer.writeTypeSuffix(gen, typeId); + } + } } diff --git a/src/com/mingliqiye/utils/time/typehandlers/DateTimeTypeHandler.java b/src/com/mingliqiye/utils/time/typehandlers/DateTimeTypeHandler.java index 2190679..acf3f08 100644 --- a/src/com/mingliqiye/utils/time/typehandlers/DateTimeTypeHandler.java +++ b/src/com/mingliqiye/utils/time/typehandlers/DateTimeTypeHandler.java @@ -2,13 +2,12 @@ package com.mingliqiye.utils.time.typehandlers; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.Formatter; +import java.sql.*; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; -import java.sql.*; - /** * DateTime类型处理器类 * 用于在MyBatis中处理DateTime类型与数据库VARCHAR类型之间的转换 @@ -17,91 +16,91 @@ import java.sql.*; @MappedJdbcTypes(JdbcType.VARCHAR) public class DateTimeTypeHandler extends BaseTypeHandler { - /** - * 设置非空参数值 - * 将DateTime对象转换为Timestamp并设置到PreparedStatement中 - * - * @param ps PreparedStatement对象 - * @param i 参数索引位置 - * @param parameter DateTime参数值 - * @param jdbcType JDBC类型 - * @throws SQLException SQL异常 - */ - @Override - public void setNonNullParameter( - PreparedStatement ps, - int i, - DateTime parameter, - JdbcType jdbcType - ) throws SQLException { - ps.setTimestamp(i, Timestamp.valueOf(parameter.getLocalDateTime())); - } + /** + * 设置非空参数值 + * 将DateTime对象转换为Timestamp并设置到PreparedStatement中 + * + * @param ps PreparedStatement对象 + * @param i 参数索引位置 + * @param parameter DateTime参数值 + * @param jdbcType JDBC类型 + * @throws SQLException SQL异常 + */ + @Override + public void setNonNullParameter( + PreparedStatement ps, + int i, + DateTime parameter, + JdbcType jdbcType + ) throws SQLException { + ps.setTimestamp(i, Timestamp.valueOf(parameter.getLocalDateTime())); + } - /** - * 从ResultSet中获取可为空的结果值 - * 根据列名获取字符串值并解析为DateTime对象 - * - * @param rs ResultSet对象 - * @param columnName 列名 - * @return DateTime对象,如果值为null则返回null - * @throws SQLException SQL异常 - */ - @Override - public DateTime getNullableResult(ResultSet rs, String columnName) - throws SQLException { - return parse(rs.getString(columnName)); - } + /** + * 从ResultSet中获取可为空的结果值 + * 根据列名获取字符串值并解析为DateTime对象 + * + * @param rs ResultSet对象 + * @param columnName 列名 + * @return DateTime对象,如果值为null则返回null + * @throws SQLException SQL异常 + */ + @Override + public DateTime getNullableResult(ResultSet rs, String columnName) + throws SQLException { + return parse(rs.getString(columnName)); + } - /** - * 从ResultSet中获取可为空的结果值 - * 根据列索引获取字符串值并解析为DateTime对象 - * - * @param rs ResultSet对象 - * @param columnIndex 列索引 - * @return DateTime对象,如果值为null则返回null - * @throws SQLException SQL异常 - */ - @Override - public DateTime getNullableResult(ResultSet rs, int columnIndex) - throws SQLException { - return parse(rs.getString(columnIndex)); - } + /** + * 从ResultSet中获取可为空的结果值 + * 根据列索引获取字符串值并解析为DateTime对象 + * + * @param rs ResultSet对象 + * @param columnIndex 列索引 + * @return DateTime对象,如果值为null则返回null + * @throws SQLException SQL异常 + */ + @Override + public DateTime getNullableResult(ResultSet rs, int columnIndex) + throws SQLException { + return parse(rs.getString(columnIndex)); + } - /** - * 从CallableStatement中获取可为空的结果值 - * 根据列索引获取字符串值并解析为DateTime对象 - * - * @param cs CallableStatement对象 - * @param columnIndex 列索引 - * @return DateTime对象,如果值为null则返回null - * @throws SQLException SQL异常 - */ - @Override - public DateTime getNullableResult(CallableStatement cs, int columnIndex) - throws SQLException { - return parse(cs.getString(columnIndex)); - } + /** + * 从CallableStatement中获取可为空的结果值 + * 根据列索引获取字符串值并解析为DateTime对象 + * + * @param cs CallableStatement对象 + * @param columnIndex 列索引 + * @return DateTime对象,如果值为null则返回null + * @throws SQLException SQL异常 + */ + @Override + public DateTime getNullableResult(CallableStatement cs, int columnIndex) + throws SQLException { + return parse(cs.getString(columnIndex)); + } - /** - * 解析字符串为DateTime对象 - * - * @param s 待解析的字符串 - * @return DateTime对象,如果字符串为null则返回null - */ - public DateTime parse(String s) { - if (s == null) { - return null; - } - return DateTime.parse(s, Formatter.STANDARD_DATETIME_MILLISECOUND7); - } + /** + * 解析字符串为DateTime对象 + * + * @param s 待解析的字符串 + * @return DateTime对象,如果字符串为null则返回null + */ + public DateTime parse(String s) { + if (s == null) { + return null; + } + return DateTime.parse(s, Formatter.STANDARD_DATETIME_MILLISECOUND7); + } - /** - * 格式化DateTime对象为字符串 - * - * @param t DateTime对象 - * @return 格式化后的字符串 - */ - public String format(DateTime t) { - return t.format(Formatter.STANDARD_DATETIME_MILLISECOUND7); - } + /** + * 格式化DateTime对象为字符串 + * + * @param t DateTime对象 + * @return 格式化后的字符串 + */ + public String format(DateTime t) { + return t.format(Formatter.STANDARD_DATETIME_MILLISECOUND7); + } } diff --git a/src/com/mingliqiye/utils/uuid/MysqlUUIDv1.java b/src/com/mingliqiye/utils/uuid/MysqlUUIDv1.java new file mode 100644 index 0000000..8274350 --- /dev/null +++ b/src/com/mingliqiye/utils/uuid/MysqlUUIDv1.java @@ -0,0 +1,66 @@ +package com.mingliqiye.utils.uuid; + +import lombok.var; + +/** + * MySQL UUID格式与标准UUID格式相互转换工具类 + *

+ * MySQL使用不同的字节顺序存储UUID,此类提供了在MySQL格式和标准UUID格式之间转换的方法 + * @author MingLiPro + */ +public class MysqlUUIDv1 { + + /** + * 将MySQL格式的UUID转换为标准UUID格式 + * + * @param uuid MySQL格式的UUID字节数组,长度必须为16字节 + * @return 标准UUID格式的字节数组,长度为16字节 + */ + public static byte[] mysqlToUuid(byte[] uuid) { + var reuuid = new byte[16]; + // 转换时间戳低位部分 + reuuid[4] = uuid[0]; + reuuid[5] = uuid[1]; + reuuid[6] = uuid[2]; + reuuid[7] = uuid[3]; + + // 转换时间戳中位部分 + reuuid[2] = uuid[4]; + reuuid[3] = uuid[5]; + + // 转换时间戳高位部分 + reuuid[0] = uuid[6]; + reuuid[1] = uuid[7]; + + // 复制时钟序列和节点标识部分 + System.arraycopy(uuid, 8, reuuid, 8, 8); + return reuuid; + } + + /** + * 将标准UUID格式转换为MySQL格式的UUID + * + * @param uuid 标准UUID格式的字节数组,长度必须为16字节 + * @return MySQL格式的UUID字节数组,长度为16字节 + */ + public static byte[] uuidToMysql(byte[] uuid) { + var reuuid = new byte[16]; + // 转换时间戳高位部分 + reuuid[6] = uuid[0]; + reuuid[7] = uuid[1]; + + // 转换时间戳中位部分 + reuuid[4] = uuid[2]; + reuuid[5] = uuid[3]; + + // 转换时间戳低位部分 + reuuid[0] = uuid[4]; + reuuid[1] = uuid[5]; + reuuid[2] = uuid[6]; + reuuid[3] = uuid[7]; + + // 复制时钟序列和节点标识部分 + System.arraycopy(uuid, 8, reuuid, 8, 8); + return reuuid; + } +} diff --git a/src/com/mingliqiye/utils/uuid/UUID.java b/src/com/mingliqiye/utils/uuid/UUID.java index 84ed5e1..3db833d 100644 --- a/src/com/mingliqiye/utils/uuid/UUID.java +++ b/src/com/mingliqiye/utils/uuid/UUID.java @@ -4,8 +4,7 @@ import com.github.f4b6a3.uuid.UuidCreator; import com.mingliqiye.utils.string.StringUtil; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.DateTimeOffset; -import com.mingliqiye.utils.time.Formatter; -import lombok.Setter; +import lombok.Data; import java.io.Serializable; import java.nio.ByteBuffer; @@ -19,234 +18,237 @@ import java.util.Objects; * * @author MingLiPro */ -@Setter +@Data public class UUID implements Serializable { - /** - * 内部封装的 java.util.UUID 实例 - */ - private java.util.UUID uuid; + /** + * 内部封装的 java.util.UUID 实例 + */ + private java.util.UUID uuid; - /** - * 构造一个由指定高位和低位组成的 UUID。 - * - * @param msb 高64位 - * @param lsb 低64位 - */ - public UUID(long msb, long lsb) { - uuid = new java.util.UUID(msb, lsb); - } + /** + * 构造一个由指定高位和低位组成的 UUID。 + * + * @param msb 高64位 + * @param lsb 低64位 + */ + public UUID(long msb, long lsb) { + uuid = new java.util.UUID(msb, lsb); + } - /** - * 构造一个基于当前时间的时间戳型 UUID(版本1)。 - */ - public UUID() { - uuid = UuidCreator.getTimeBased(); - } + /** + * 构造一个基于当前时间的时间戳型 UUID(版本1)。 + */ + public UUID() { + uuid = UuidCreator.getTimeBased(); + } - /** - * 使用给定的 java.util.UUID 对象构造一个新的 UUID 实例。 - * - * @param uuid java.util.UUID 实例 - */ - public UUID(java.util.UUID uuid) { - this.uuid = uuid; - } + /** + * 使用给定的 java.util.UUID 对象构造一个新的 UUID 实例。 + * + * @param uuid java.util.UUID 实例 + */ + public UUID(java.util.UUID uuid) { + this.uuid = uuid; + } - /** - * 根据字符串表示的 UUID 构造一个新的 UUID 实例。 - * - * @param uuid 字符串形式的 UUID - */ - public UUID(String uuid) { - this.uuid = java.util.UUID.fromString(uuid); - } + /** + * 根据字符串表示的 UUID 构造一个新的 UUID 实例。 + * + * @param uuid 字符串形式的 UUID + */ + public UUID(String uuid) { + this.uuid = java.util.UUID.fromString(uuid); + } - /** - * 将字节数组转换为 UUID 实例。 - * - * @param bytes 表示 UUID 的 16 字节数据 - * @return 新建的 UUID 实例 - */ - public static UUID of(byte[] bytes) { - ByteBuffer bb = ByteBuffer.wrap(bytes); - long msb = bb.getLong(); - long lsb = bb.getLong(); - return new UUID(msb, lsb); - } + /** + * 将字节数组转换为 UUID 实例。 + * + * @param bytes 表示 UUID 的 16 字节数据 + * @return 新建的 UUID 实例 + */ + public static UUID of(byte[] bytes) { + if (bytes == null) { + return null; + } + ByteBuffer bb = ByteBuffer.wrap(bytes); + long msb = bb.getLong(); + long lsb = bb.getLong(); + return new UUID(msb, lsb); + } - /** - * 将字符串解析为 UUID 实例,如果解析失败则抛出 UUIDException。 - * - * @param data UUID 字符串 - * @return 解析后的 UUID 实例 - * @throws UUIDException 如果解析失败 - */ - public static UUID ofString(String data) { - try { - java.util.UUID uuid1 = java.util.UUID.fromString(data); - UUID uuid = new UUID(); - uuid.setUuid(uuid1); - return uuid; - } catch (Exception e) { - throw new UUIDException(e.getMessage(), e); - } - } + /** + * 将字符串解析为 UUID 实例,如果解析失败则抛出 UUIDException。 + * + * @param data UUID 字符串 + * @return 解析后的 UUID 实例 + * @throws UUIDException 如果解析失败 + */ + public static UUID of(String data) { + if (data == null) { + return null; + } + try { + java.util.UUID uuid1 = java.util.UUID.fromString(data); + UUID uuid = new UUID(); + uuid.setUuid(uuid1); + return uuid; + } catch (Exception e) { + throw new UUIDException(e.getMessage(), e); + } + } - /** - * 将 UUID 转换为 16 字节的字节数组。 - * - * @return 表示该 UUID 的字节数组 - */ - public byte[] toBytes() { - ByteBuffer bb = ByteBuffer.wrap(new byte[16]); - bb.putLong(uuid.getMostSignificantBits()); - bb.putLong(uuid.getLeastSignificantBits()); - return bb.array(); - } + /** + * 将 UUID 转换为 16 字节的字节数组。 + * + * @return 表示该 UUID 的字节数组 + */ + public byte[] toBytes() { + if (this.uuid == null) { + return null; + } + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(uuid.getMostSignificantBits()); + bb.putLong(uuid.getLeastSignificantBits()); + return bb.array(); + } - /** - * 获取内部封装的 java.util.UUID 实例。 - * - * @return java.util.UUID 实例 - */ - public java.util.UUID GetUUID() { - return uuid; - } + /** + * 获取内部封装的 java.util.UUID 实例。 + * + * @return java.util.UUID 实例 + */ + public java.util.UUID GetUUID() { + return uuid; + } - /** - * 将 UUID 转换为字符串表示,默认使用小写格式。 - * - * @return UUID 字符串 - */ - public String toUUIDString() { - return toUUIDString(false); - } + /** + * 将 UUID 转换为字符串表示,默认使用小写格式。 + * + * @return UUID 字符串 + */ + public String toUUIDString() { + return toUUIDString(false); + } - /** - * 将 UUID 转换为字符串表示,并可选择是否使用大写。 - * - * @param u 是否使用大写格式 - * @return UUID 字符串 - * @throws UUIDException 如果 uuid 为 null - */ - public String toUUIDString(boolean u) { - if (uuid == null) { - throw new UUIDException("uuid is null : NullPointerException"); - } - if (u) { - return uuid.toString().toUpperCase(Locale.ROOT); - } - return uuid.toString(); - } + /** + * 将 UUID 转换为字符串表示,并可选择是否使用大写。 + * + * @param u 是否使用大写格式 + * @return UUID 字符串 + * @throws UUIDException 如果 uuid 为 null + */ + public String toUUIDString(boolean u) { + if (uuid == null) { + throw new UUIDException("uuid is null : NullPointerException"); + } + if (u) { + return uuid.toString().toUpperCase(Locale.ROOT); + } + return uuid.toString(); + } - /** - * 计算此 UUID 的哈希码。 - * - * @return 哈希码值 - */ - @Override - public int hashCode() { - return Objects.hash(uuid); - } + /** + * 计算此 UUID 的哈希码。 + * + * @return 哈希码值 + */ + @Override + public int hashCode() { + return Objects.hash(uuid); + } - /** - * 判断两个 UUID 是否相等。 - * - * @param o 比较对象 - * @return 如果相等返回 true,否则返回 false - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UUID uuid = (UUID) o; - return Objects.equals(this.uuid, uuid.uuid); - } + /** + * 判断两个 UUID 是否相等。 + * + * @param o 比较对象 + * @return 如果相等返回 true,否则返回 false + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UUID uuid = (UUID) o; + return Objects.equals(this.uuid, uuid.uuid); + } - /** - * 返回此 UUID 的字符串表示,包含版本信息和时间戳(如果是版本1)。 - * - * @return UUID 的详细字符串表示 - */ - @Override - public String toString() { - if (uuid == null) { - return "UUID(null)"; - } - if (uuid.version() == 1) { - return StringUtil.format( - "UUID(uuid={},time={},mac={},version={})", - toUUIDString(true), - getDateTime().format(Formatter.STANDARD_DATETIME), - extractMACFromUUID(), - uuid.version() - ); - } - return StringUtil.format( - "UUID(uuid={},version={})", - toUUIDString(true), - uuid.version() - ); - } + /** + * 返回此 UUID 的字符串表示,包含版本信息和时间戳(如果是版本1)。 + * + * @return UUID 的详细字符串表示 + */ + @Override + public String toString() { + if (uuid == null) { + return "UUID(null)"; + } + return StringUtil.format( + "UUID(uuid={},version={})", + toUUIDString(true), + uuid.version() + ); + } - /** - * 从时间戳型 UUID 中提取时间戳并转换为 DateTime 对象。 - * - * @return 对应的 DateTime 对象;如果 uuid 为 null,则返回 null - */ - public DateTime getDateTime() { - if (uuid == null) { - return null; - } - return DateTime.of(uuid.timestamp() / 10_000).add( - DateTimeOffset.of(-141427L, ChronoUnit.DAYS) - ); - } + /** + * 从时间戳型 UUID 中提取时间戳并转换为 DateTime 对象。 + * + * @return 对应的 DateTime 对象;如果 uuid 为 null,则返回 null + */ + public DateTime getDateTime() { + if (uuid == null) { + return null; + } + if (uuid.version() != 1) { + return null; + } + return DateTime.of(uuid.timestamp() / 10_000).add( + DateTimeOffset.of(-141427L, ChronoUnit.DAYS) + ); + } - /** - * 从时间戳型 UUID 中提取 MAC 地址,默认使用冒号分隔符。 - * - * @return MAC 地址字符串 - * @throws UUIDException 如果 uuid 为 null - */ - public String extractMACFromUUID() { - return extractMACFromUUID(null); - } + /** + * 从时间戳型 UUID 中提取 MAC 地址,默认使用冒号分隔符。 + * + * @return MAC 地址字符串 + * @throws UUIDException 如果 uuid 为 null + */ + public String extractMACFromUUID() { + return extractMACFromUUID(null); + } - /** - * 从时间戳型 UUID 中提取 MAC 地址,并允许自定义分隔符。 - * - * @param spec 分隔符字符,默认为 ":" - * @return MAC 地址字符串 - * @throws UUIDException 如果 uuid 为 null - */ - public String extractMACFromUUID(String spec) { - if (uuid == null) { - throw new UUIDException("uuid is null : NullPointerException"); - } - if (spec == null) { - spec = ":"; - } - long leastSigBits = uuid.getLeastSignificantBits(); - long macLong = leastSigBits & 0xFFFFFFFFFFFFL; - byte[] macBytes = new byte[6]; - // 提取 MAC 地址的每个字节 - for (int i = 0; i < 6; i++) { - macBytes[5 - i] = (byte) (macLong >> (8 * i)); - } - StringBuilder mac = new StringBuilder(); - // 构造 MAC 地址字符串 - for (int i = 0; i < 6; i++) { - mac.append(String.format("%02X", macBytes[i])); - if (i < 5) { - mac.append(spec); - } - } - return mac.toString(); - } + /** + * 从时间戳型 UUID 中提取 MAC 地址,并允许自定义分隔符。 + * + * @param spec 分隔符字符,默认为 ":" + * @return MAC 地址字符串 + * @throws UUIDException 如果 uuid 为 null + */ + public String extractMACFromUUID(String spec) { + if (uuid == null) { + throw new UUIDException("uuid is null : NullPointerException"); + } + if (spec == null) { + spec = ":"; + } + long leastSigBits = uuid.getLeastSignificantBits(); + long macLong = leastSigBits & 0xFFFFFFFFFFFFL; + byte[] macBytes = new byte[6]; + // 提取 MAC 地址的每个字节 + for (int i = 0; i < 6; i++) { + macBytes[5 - i] = (byte) (macLong >> (8 * i)); + } + StringBuilder mac = new StringBuilder(); + // 构造 MAC 地址字符串 + for (int i = 0; i < 6; i++) { + mac.append(String.format("%02X", macBytes[i])); + if (i < 5) { + mac.append(spec); + } + } + return mac.toString(); + } } diff --git a/src/com/mingliqiye/utils/uuid/UUIDException.java b/src/com/mingliqiye/utils/uuid/UUIDException.java index 49361ad..e13981c 100644 --- a/src/com/mingliqiye/utils/uuid/UUIDException.java +++ b/src/com/mingliqiye/utils/uuid/UUIDException.java @@ -2,11 +2,11 @@ package com.mingliqiye.utils.uuid; public class UUIDException extends RuntimeException { - public UUIDException(String message) { - super(message); - } + public UUIDException(String message) { + super(message); + } - public UUIDException(String message, Throwable cause) { - super(message, cause); - } + public UUIDException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/com/mingliqiye/utils/uuid/serialization/Jackson.java b/src/com/mingliqiye/utils/uuid/serialization/Jackson.java index 7439e4b..1703acc 100644 --- a/src/com/mingliqiye/utils/uuid/serialization/Jackson.java +++ b/src/com/mingliqiye/utils/uuid/serialization/Jackson.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.mingliqiye.utils.uuid.UUID; import com.mingliqiye.utils.uuid.UUIDException; - import java.io.IOException; /** @@ -21,89 +20,89 @@ import java.io.IOException; */ public class Jackson { - /** - * UUID 反序列化器 - *

- * 将 JSON 字符串反序列化为自定义 UUID 对象 - */ - public static class UUIDJsonDeserializer extends JsonDeserializer { + /** + * UUID 反序列化器 + *

+ * 将 JSON 字符串反序列化为自定义 UUID 对象 + */ + public static class UUIDJsonDeserializer extends JsonDeserializer { - /** - * 反序列化方法:将 JSON 解析为 UUID 对象 - * - * @param p JSON 解析器对象 - * @param ctxt 反序列化上下文 - * @return 解析后的 UUID 对象,若输入为 NaN 则返回 null - * @throws IOException 当解析过程中发生 IO 异常时抛出 - */ - @Override - public UUID deserialize(JsonParser p, DeserializationContext ctxt) - throws IOException { - // 如果是 NaN 值则返回 null - if (p.isNaN()) { - return null; - } - // 使用指定字符串值创建新的 UUID 对象 - return new UUID(p.getValueAsString()); - } - } + /** + * 反序列化方法:将 JSON 解析为 UUID 对象 + * + * @param p JSON 解析器对象 + * @param ctxt 反序列化上下文 + * @return 解析后的 UUID 对象,若输入为 NaN 则返回 null + * @throws IOException 当解析过程中发生 IO 异常时抛出 + */ + @Override + public UUID deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException { + // 如果是 NaN 值则返回 null + if (p.isNaN()) { + return null; + } + // 使用指定字符串值创建新的 UUID 对象 + return new UUID(p.getValueAsString()); + } + } - /** - * UUID 序列化器 - *

- * 将自定义 UUID 对象序列化为 JSON 字符串 - */ - public static class UUIDJsonSerializer extends JsonSerializer { + /** + * UUID 序列化器 + *

+ * 将自定义 UUID 对象序列化为 JSON 字符串 + */ + public static class UUIDJsonSerializer extends JsonSerializer { - /** - * 序列化方法:将 UUID 对象写入 JSON 生成器 - * - * @param uuid 要序列化的 UUID 对象 - * @param jsonGenerator JSON 生成器 - * @param serializerProvider 序列化提供者 - * @throws UUIDException 当 UUID 处理过程中发生异常时抛出 - * @throws IOException 当写入过程中发生 IO 异常时抛出 - */ - @Override - public void serialize( - UUID uuid, - JsonGenerator jsonGenerator, - SerializerProvider serializerProvider - ) throws UUIDException, IOException { - // 若值为 null,则直接写入 null - if (uuid == null) { - jsonGenerator.writeNull(); - return; - } - // 将 UUID 写入为字符串 - jsonGenerator.writeString(uuid.toUUIDString()); - } + /** + * 序列化方法:将 UUID 对象写入 JSON 生成器 + * + * @param uuid 要序列化的 UUID 对象 + * @param jsonGenerator JSON 生成器 + * @param serializerProvider 序列化提供者 + * @throws UUIDException 当 UUID 处理过程中发生异常时抛出 + * @throws IOException 当写入过程中发生 IO 异常时抛出 + */ + @Override + public void serialize( + UUID uuid, + JsonGenerator jsonGenerator, + SerializerProvider serializerProvider + ) throws UUIDException, IOException { + // 若值为 null,则直接写入 null + if (uuid == null) { + jsonGenerator.writeNull(); + return; + } + // 将 UUID 写入为字符串 + jsonGenerator.writeString(uuid.toUUIDString()); + } - /** - * 带类型信息的序列化方法:用于支持多态类型处理 - * - * @param value 要序列化的 UUID 对象 - * @param gen JSON 生成器 - * @param serializers 序列化提供者 - * @param typeSer 类型序列化器 - * @throws IOException 当写入过程中发生 IO 异常时抛出 - */ - @Override - public void serializeWithType( - UUID value, - JsonGenerator gen, - SerializerProvider serializers, - TypeSerializer typeSer - ) throws IOException { - // 写入类型前缀 - WritableTypeId typeId = typeSer.writeTypePrefix( - gen, - typeSer.typeId(value, JsonToken.VALUE_STRING) - ); - // 执行实际序列化 - serialize(value, gen, serializers); - // 写入类型后缀 - typeSer.writeTypeSuffix(gen, typeId); - } - } + /** + * 带类型信息的序列化方法:用于支持多态类型处理 + * + * @param value 要序列化的 UUID 对象 + * @param gen JSON 生成器 + * @param serializers 序列化提供者 + * @param typeSer 类型序列化器 + * @throws IOException 当写入过程中发生 IO 异常时抛出 + */ + @Override + public void serializeWithType( + UUID value, + JsonGenerator gen, + SerializerProvider serializers, + TypeSerializer typeSer + ) throws IOException { + // 写入类型前缀 + WritableTypeId typeId = typeSer.writeTypePrefix( + gen, + typeSer.typeId(value, JsonToken.VALUE_STRING) + ); + // 执行实际序列化 + serialize(value, gen, serializers); + // 写入类型后缀 + typeSer.writeTypeSuffix(gen, typeId); + } + } } diff --git a/src/com/mingliqiye/utils/uuid/typehandlers/UUIDBinaryTypeHandler.java b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDBinaryTypeHandler.java index f53a9f9..d70b2d0 100644 --- a/src/com/mingliqiye/utils/uuid/typehandlers/UUIDBinaryTypeHandler.java +++ b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDBinaryTypeHandler.java @@ -6,7 +6,6 @@ import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; -import java.nio.ByteBuffer; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -22,90 +21,64 @@ import java.sql.SQLException; @MappedJdbcTypes(JdbcType.BINARY) public class UUIDBinaryTypeHandler extends BaseTypeHandler { - /** - * 将 UUID 对象转换为二进制字节数组 - * - * @param uuid 要转换的 UUID 对象 - * @return 包含 UUID 数据的 16 字节二进制数组 - */ - public static byte[] UUID_TO_BIN(UUID uuid) { - ByteBuffer bb = ByteBuffer.wrap(new byte[16]); - bb.putLong(uuid.GetUUID().getMostSignificantBits()); - bb.putLong(uuid.GetUUID().getLeastSignificantBits()); - return bb.array(); - } + /** + * 设置非空参数到 PreparedStatement 中 + * + * @param ps PreparedStatement 对象 + * @param i 参数在 SQL 语句中的位置索引 + * @param parameter 要设置的 UUID 参数值 + * @param jdbcType JDBC 类型信息 + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public void setNonNullParameter( + PreparedStatement ps, + int i, + UUID parameter, + JdbcType jdbcType + ) throws SQLException { + ps.setBytes(i, UUIDConverter.UUID_TO_BIN(parameter)); + } - /** - * 将二进制字节数组转换为 UUID 对象 - * - * @param bytes 包含 UUID 数据的二进制字节数组 - * @return 转换后的 UUID 对象,如果输入为 null 则返回 null - */ - public static UUID BIN_TO_UUID(byte[] bytes) { - if (bytes == null) { - return null; - } - return UUID.of(bytes); - } + /** + * 从 ResultSet 中根据列名获取可为空的 UUID 结果 + * + * @param rs ResultSet 对象 + * @param columnName 数据库列名 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(ResultSet rs, String columnName) + throws SQLException { + return UUIDConverter.BIN_TO_UUID(rs.getBytes(columnName)); + } - /** - * 设置非空参数到 PreparedStatement 中 - * - * @param ps PreparedStatement 对象 - * @param i 参数在 SQL 语句中的位置索引 - * @param parameter 要设置的 UUID 参数值 - * @param jdbcType JDBC 类型信息 - * @throws SQLException 当数据库操作发生错误时抛出 - */ - @Override - public void setNonNullParameter( - PreparedStatement ps, - int i, - UUID parameter, - JdbcType jdbcType - ) throws SQLException { - ps.setBytes(i, UUID_TO_BIN(parameter)); - } + /** + * 从 ResultSet 中根据列索引获取可为空的 UUID 结果 + * + * @param rs ResultSet 对象 + * @param columnIndex 数据库列索引 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(ResultSet rs, int columnIndex) + throws SQLException { + return UUIDConverter.BIN_TO_UUID(rs.getBytes(columnIndex)); + } - /** - * 从 ResultSet 中根据列名获取可为空的 UUID 结果 - * - * @param rs ResultSet 对象 - * @param columnName 数据库列名 - * @return 转换后的 UUID 对象,可能为 null - * @throws SQLException 当数据库操作发生错误时抛出 - */ - @Override - public UUID getNullableResult(ResultSet rs, String columnName) - throws SQLException { - return BIN_TO_UUID(rs.getBytes(columnName)); - } - - /** - * 从 ResultSet 中根据列索引获取可为空的 UUID 结果 - * - * @param rs ResultSet 对象 - * @param columnIndex 数据库列索引 - * @return 转换后的 UUID 对象,可能为 null - * @throws SQLException 当数据库操作发生错误时抛出 - */ - @Override - public UUID getNullableResult(ResultSet rs, int columnIndex) - throws SQLException { - return BIN_TO_UUID(rs.getBytes(columnIndex)); - } - - /** - * 从 CallableStatement 中根据参数索引获取可为空的 UUID 结果 - * - * @param cs CallableStatement 对象 - * @param columnIndex 参数索引 - * @return 转换后的 UUID 对象,可能为 null - * @throws SQLException 当数据库操作发生错误时抛出 - */ - @Override - public UUID getNullableResult(CallableStatement cs, int columnIndex) - throws SQLException { - return BIN_TO_UUID(cs.getBytes(columnIndex)); - } + /** + * 从 CallableStatement 中根据参数索引获取可为空的 UUID 结果 + * + * @param cs CallableStatement 对象 + * @param columnIndex 参数索引 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(CallableStatement cs, int columnIndex) + throws SQLException { + return UUIDConverter.BIN_TO_UUID(cs.getBytes(columnIndex)); + } } diff --git a/src/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java new file mode 100644 index 0000000..978424c --- /dev/null +++ b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java @@ -0,0 +1,31 @@ +package com.mingliqiye.utils.uuid.typehandlers; + +import com.mingliqiye.utils.uuid.MysqlUUIDv1; +import com.mingliqiye.utils.uuid.UUID; + +public class UUIDConverter { + + public static String UUID_TO_STR(UUID uuid) { + return uuid.toUUIDString(); + } + + public static UUID STR_TO_UUID(String string) { + return UUID.of(string); + } + + public static byte[] UUID_TO_BIN(UUID uuid) { + return uuid.toBytes(); + } + + public static UUID BIN_TO_UUID(byte[] bytes) { + return UUID.of(bytes); + } + + public static byte[] MYSQL_UUID_TO_BIN(UUID uuid) { + return MysqlUUIDv1.uuidToMysql(uuid.toBytes()); + } + + public static UUID BIN_TO_MYSQL_UUID(byte[] bytes) { + return UUID.of(MysqlUUIDv1.mysqlToUuid(bytes)); + } +} diff --git a/src/com/mingliqiye/utils/uuid/typehandlers/UUIDStringTypeHandler.java b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDStringTypeHandler.java new file mode 100644 index 0000000..f7bffa9 --- /dev/null +++ b/src/com/mingliqiye/utils/uuid/typehandlers/UUIDStringTypeHandler.java @@ -0,0 +1,83 @@ +package com.mingliqiye.utils.uuid.typehandlers; + +import com.mingliqiye.utils.uuid.UUID; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; + +/** + * UUIDBinaryTypeHandler 类用于处理 UUID 类型与数据库 BINARY 类型之间的转换 + * 该类继承自 BaseTypeHandler,专门处理 UUID 对象的序列化和反序列化 + * + * @author MingLiPro + */ +@MappedTypes({ UUID.class }) +@MappedJdbcTypes(JdbcType.VARCHAR) +public class UUIDStringTypeHandler extends BaseTypeHandler { + + /** + * 设置非空参数到 PreparedStatement 中 + * + * @param ps PreparedStatement 对象 + * @param i 参数在 SQL 语句中的位置索引 + * @param parameter 要设置的 UUID 参数值 + * @param jdbcType JDBC 类型信息 + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public void setNonNullParameter( + PreparedStatement ps, + int i, + UUID parameter, + JdbcType jdbcType + ) throws SQLException { + ps.setString(i, UUIDConverter.UUID_TO_STR(parameter)); + } + + /** + * 从 ResultSet 中根据列名获取可为空的 UUID 结果 + * + * @param rs ResultSet 对象 + * @param columnName 数据库列名 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(ResultSet rs, String columnName) + throws SQLException { + return UUIDConverter.STR_TO_UUID(rs.getString(columnName)); + } + + /** + * 从 ResultSet 中根据列索引获取可为空的 UUID 结果 + * + * @param rs ResultSet 对象 + * @param columnIndex 数据库列索引 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(ResultSet rs, int columnIndex) + throws SQLException { + return UUIDConverter.STR_TO_UUID(rs.getString(columnIndex)); + } + + /** + * 从 CallableStatement 中根据参数索引获取可为空的 UUID 结果 + * + * @param cs CallableStatement 对象 + * @param columnIndex 参数索引 + * @return 转换后的 UUID 对象,可能为 null + * @throws SQLException 当数据库操作发生错误时抛出 + */ + @Override + public UUID getNullableResult(CallableStatement cs, int columnIndex) + throws SQLException { + return UUIDConverter.STR_TO_UUID(cs.getString(columnIndex)); + } +}