From fb4e103da8b5af56468c280baf057a4c92602345 Mon Sep 17 00:00:00 2001 From: minglipro Date: Sun, 14 Sep 2025 18:23:34 +0800 Subject: [PATCH] no message --- .gitignore | 2 +- build.gradle.kts | 81 ++-- gradle.properties | 4 +- jdk8/build.gradle.kts | 57 +++ settings.gradle.kts | 3 +- .../com/mingliqiye/utils/aes/AesUtils.java | 133 ------ .../com/mingliqiye/utils/bytes/ByteUtil.java | 65 --- .../mingliqiye/utils/collection/Lists.java | 16 +- .../mingliqiye/utils/jna/FieldStructure.java | 59 --- .../utils/jna/time/WinKernel32.java | 40 -- .../autoconfigure/AutoConfiguration.java | 20 +- .../java/com/mingliqiye/utils/test/Main.java | 32 -- .../com/mingliqiye/utils/time/DateTime.java | 76 ++-- .../mingliqiye/utils/uuid/MysqlUUIDv1.java | 88 ---- .../mingliqiye/utils/uuid/UUIDException.java | 34 -- .../uuid/typehandlers/UUIDConverter.java | 53 --- .../mysql/UUIDBinaryTypeHandler.java | 106 ----- .../pgsql/UUIDStringTypeHandler.java | 106 ----- src/main/kotlin/com/mingliqiye/utils/Main.kt | 3 - .../com/mingliqiye/utils/aes/AesUtils.kt | 123 +++++ .../com/mingliqiye/utils/bytes/ByteUtil.kt | 51 +++ .../mingliqiye/utils/jna/FieldStructure.kt | 60 +++ .../com/mingliqiye/utils/logger/Loggers.kt | 421 ++++++++++++++++++ .../datetime/DateTimeTypeHandler.kt | 102 +++++ .../typehandler/uuid/UUIDTypeHandler.kt | 279 ++++++++++++ .../uuid/mysql/MysqlUUIDBinaryTypeHandler.kt | 119 +++++ .../com/mingliqiye/utils/uuid/MysqlUUIDv1.kt | 53 +++ src/main/resources/META-INF/meta-data | 2 +- 28 files changed, 1375 insertions(+), 813 deletions(-) create mode 100644 jdk8/build.gradle.kts delete mode 100644 src/main/java/com/mingliqiye/utils/aes/AesUtils.java delete mode 100644 src/main/java/com/mingliqiye/utils/bytes/ByteUtil.java delete mode 100644 src/main/java/com/mingliqiye/utils/jna/FieldStructure.java delete mode 100644 src/main/java/com/mingliqiye/utils/jna/time/WinKernel32.java delete mode 100644 src/main/java/com/mingliqiye/utils/test/Main.java delete mode 100644 src/main/java/com/mingliqiye/utils/uuid/MysqlUUIDv1.java delete mode 100644 src/main/java/com/mingliqiye/utils/uuid/UUIDException.java delete mode 100644 src/main/java/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java delete mode 100644 src/main/java/com/mingliqiye/utils/uuid/typehandlers/mysql/UUIDBinaryTypeHandler.java delete mode 100644 src/main/java/com/mingliqiye/utils/uuid/typehandlers/pgsql/UUIDStringTypeHandler.java create mode 100644 src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtil.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/UUIDTypeHandler.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/mysql/MysqlUUIDBinaryTypeHandler.kt create mode 100644 src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt diff --git a/.gitignore b/.gitignore index a0f1509..36c3ab5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ log .idea node_modules *lock* - +.kotlin diff --git a/build.gradle.kts b/build.gradle.kts index 6ff8032..83bc5b6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ * ProjectName mingli-utils * ModuleName mingli-utils * CurrentFile build.gradle.kts - * LastUpdate 2025-09-12 14:06:21 + * LastUpdate 2025-09-13 10:11:22 * UpdateUser MingLiPro */ @@ -59,10 +59,6 @@ sourceSets { } } -configurations { - -} - java { withSourcesJar() toolchain.languageVersion.set(JavaLanguageVersion.of(8)) @@ -81,8 +77,11 @@ dependencies { implementation("com.github.f4b6a3:uuid-creator:6.1.0") implementation("org.mindrot:jbcrypt:0.4") implementation("org.jetbrains:annotations:24.0.0") - implementation("net.java.dev.jna:jna:5.17.0") + compileOnly("net.java.dev.jna:jna:5.17.0") implementation("jakarta.annotation:jakarta.annotation-api:2.1.1") + implementation("org.slf4j:slf4j-api:2.0.17") + implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1") + } @@ -90,26 +89,10 @@ tasks.withType { options.encoding = "UTF-8" } -tasks.register("javaDocJar") { - group = "build" - archiveClassifier.set("javadoc") - dependsOn(tasks.dokkaGfm, tasks.dokkaHtml, tasks.dokkaJavadoc, tasks.dokkaJekyll) - from(buildDir.resolve("dokka/javadoc")) -} -tasks.register("kotlinDocJar") { - group = "build" - archiveClassifier.set("kotlindoc") - dependsOn(tasks.dokkaHtml) - from(buildDir.resolve("dokka/html")) -} -tasks.build { - dependsOn("javaDocJar", "kotlinDocJar") -} + tasks.withType().configureEach { jvmArgs = listOf( - "-Dfile.encoding=UTF-8", - "-Dsun.stdout.encoding=UTF-8", - "-Dsun.stderr.encoding=UTF-8" + "-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8" ) } @@ -142,6 +125,7 @@ tasks.withType { ) } } +val isJdk8Build = project.findProperty("buildForJdk8") == "true" repositories { maven { @@ -150,6 +134,18 @@ repositories { mavenCentral() } +tasks.register("javaDocJar") { + group = "build" + archiveClassifier.set("javadoc") + dependsOn(tasks.dokkaJavadoc) + from(buildDir.resolve("dokka/javadoc")) +} +tasks.register("kotlinDocJar") { + group = "build" + archiveClassifier.set("kotlindoc") + dependsOn(tasks.dokkaHtml) + from(buildDir.resolve("dokka/html")) +} publishing { repositories { maven { @@ -160,39 +156,34 @@ publishing { publications { create("mavenJava") { from(components["java"]) - groupId = GROUPSID - artifactId = ARTIFACTID - version = VERSIONS artifact(tasks.named("javaDocJar")) artifact(tasks.named("kotlinDocJar")) - pom { - name.set(project.name) - url.set("https://github.com/minglipro/mingli-utils") - - licenses { - license { - name.set("Apache-2.0") - url.set("https://opensource.org/licenses/Apache-2.0") - } - } - } + artifactId = ARTIFACTID + java.toolchain.languageVersion.set(JavaLanguageVersion.of(8)) } } } +tasks.build { + dependsOn("javaDocJar", "kotlinDocJar") +} + + + + tasks.processResources { duplicatesStrategy = DuplicatesStrategy.EXCLUDE outputs.upToDateWhen { false } filesMatching("META-INF/meta-data") { expand( - mapOf( - "buildTime" to LocalDateTime.now() - .format( - DateTimeFormatter.ofPattern( - "yyyy-MM-dd HH:mm:ss.SSSSSSS" - ) + project.properties + mapOf( + "buildTime" to LocalDateTime.now().format( + DateTimeFormatter.ofPattern( + "yyyy-MM-dd HH:mm:ss.SSSSSSS" ) - ) + project.properties + + ) + ) ) } } diff --git a/gradle.properties b/gradle.properties index 6445136..224ee49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,10 +16,10 @@ # ProjectName mingli-utils # ModuleName mingli-utils # CurrentFile gradle.properties -# LastUpdate 2025-09-12 14:10:24 +# LastUpdate 2025-09-13 10:14:51 # UpdateUser MingLiPro # JDKVERSIONS=1.8 GROUPSID=com.mingliqiye.utils ARTIFACTID=mingli-utils -VERSIONS=3.2.7 +VERSIONS=3.3.1 diff --git a/jdk8/build.gradle.kts b/jdk8/build.gradle.kts new file mode 100644 index 0000000..9a9e3f6 --- /dev/null +++ b/jdk8/build.gradle.kts @@ -0,0 +1,57 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.jdk8 + * CurrentFile build.gradle.kts + * LastUpdate 2025-09-14 18:19:04 + * UpdateUser MingLiPro + */ +plugins { + id("java-library") + id("maven-publish") +} +val GROUPSID = project.properties["GROUPSID"] as String +val VERSIONS = project.properties["VERSIONS"] as String +val ARTIFACTID = project.properties["ARTIFACTID"] as String +version = VERSIONS +group = GROUPSID + +base.archivesName.set(ARTIFACTID) + + + +publishing { + repositories { + maven { + name = "MavenRepositoryRaw" + url = uri("C:/data/git/maven-repository-raw") + } + } + publications { + create("mavenJava") { + from(components["java"]) + artifactId = "$ARTIFACTID-win-jdk8" + groupId = GROUPSID + version = VERSIONS + } + } +} + +java.toolchain.languageVersion.set(JavaLanguageVersion.of(8)) +dependencies { + api(rootProject) + implementation("com.mingliqiye.utils.jna:WinKernel32Platform:1.0.1") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 50f99da..cb1e4c0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,9 +16,10 @@ * ProjectName mingli-utils * ModuleName mingli-utils * CurrentFile settings.gradle.kts - * LastUpdate 2025-09-09 08:37:33 + * LastUpdate 2025-09-13 02:37:04 * UpdateUser MingLiPro */ +include("jdk8") val ARTIFACTID: String by settings.extra rootProject.name = ARTIFACTID diff --git a/src/main/java/com/mingliqiye/utils/aes/AesUtils.java b/src/main/java/com/mingliqiye/utils/aes/AesUtils.java deleted file mode 100644 index fc98aa0..0000000 --- a/src/main/java/com/mingliqiye/utils/aes/AesUtils.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile AesUtils.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.aes; - -import com.mingliqiye.utils.base64.Base64Utils; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.SecureRandom; -import javax.crypto.Cipher; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -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/main/java/com/mingliqiye/utils/bytes/ByteUtil.java b/src/main/java/com/mingliqiye/utils/bytes/ByteUtil.java deleted file mode 100644 index 190a6d5..0000000 --- a/src/main/java/com/mingliqiye/utils/bytes/ByteUtil.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile ByteUtil.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.bytes; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author MingLiPro - * - * 字节数组处理工具类 - */ -public class ByteUtil { - - public static final byte ESC_ASC = 0x1A; - public static final byte ESC_DESC = 0x1B; - public static final byte ESC_NONE = 0x00; - public static final byte ESC_START = 0x01; - public static final byte ESC_END = 0x02; - public static final byte ESC_ESC = 0x03; - public static final byte ESC_CONTROL = 0x04; - public static final byte ESC_DATA = 0x05; - public static final byte ESC_RESERVED = 0x06; - - /** - * 将字节数组转换为十六进制字符串列表 - *

- * 每个字节都会被转换为两位的十六进制字符串表示形式 - * 例如: 字节值为10的字节会被转换为"0a",值为255的字节会被转换为"ff" - * - * @param bytes 输入的字节数组 - * @return 包含每个字节对应十六进制字符串的列表 - */ - public static List getByteArrayString(byte[] bytes) { - List byteList = new ArrayList<>(bytes.length); - for (byte aByte : bytes) { - byteList.add(aByte); - } - return byteList - .stream() - .map(a -> String.format("%02x", a & 0xFF)) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/com/mingliqiye/utils/collection/Lists.java b/src/main/java/com/mingliqiye/utils/collection/Lists.java index 33bf55d..9385179 100644 --- a/src/main/java/com/mingliqiye/utils/collection/Lists.java +++ b/src/main/java/com/mingliqiye/utils/collection/Lists.java @@ -16,22 +16,20 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile Lists.java - * LastUpdate 2025-09-09 08:37:33 + * LastUpdate 2025-09-13 00:26:11 * UpdateUser MingLiPro */ package com.mingliqiye.utils.collection; -import static com.mingliqiye.utils.collection.Collection.findFirst; - -import com.github.f4b6a3.uuid.util.internal.RandomUtil; import com.mingliqiye.utils.random.RandomInt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.util.*; import java.util.Collection; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * Lists工具类提供了一系列创建List实现的便捷方法。 @@ -457,6 +455,12 @@ public class Lists { return list; } + public static List toList(Iterator iterator) { + List list = newArrayList(10); + ForEach.forEach(iterator, item -> list.add(item)); + return list; + } + public T getFirst(Collection collectors) { return com.mingliqiye.utils.collection.Collection.getFirst(collectors); } diff --git a/src/main/java/com/mingliqiye/utils/jna/FieldStructure.java b/src/main/java/com/mingliqiye/utils/jna/FieldStructure.java deleted file mode 100644 index dbac2d5..0000000 --- a/src/main/java/com/mingliqiye/utils/jna/FieldStructure.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile FieldStructure.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.jna; - -import com.sun.jna.Structure; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; - -/** - * @author MingLiPro - */ -public class FieldStructure extends Structure { - - @Override - protected List getFieldOrder() { - List fieldOrderList = new ArrayList<>(); - for ( - Class cls = getClass(); - !cls.equals(FieldStructure.class); - cls = cls.getSuperclass() - ) { - Field[] fields = cls.getDeclaredFields(); - int modifiers; - for (Field field : fields) { - modifiers = field.getModifiers(); - if ( - Modifier.isStatic(modifiers) || - !Modifier.isPublic(modifiers) - ) { - continue; - } - fieldOrderList.add(field.getName()); - } - } - return fieldOrderList; - } -} diff --git a/src/main/java/com/mingliqiye/utils/jna/time/WinKernel32.java b/src/main/java/com/mingliqiye/utils/jna/time/WinKernel32.java deleted file mode 100644 index b061642..0000000 --- a/src/main/java/com/mingliqiye/utils/jna/time/WinKernel32.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile WinKernel32.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.jna.time; - -import com.sun.jna.Library; -import com.sun.jna.Native; -import com.sun.jna.ptr.LongByReference; - -/** - * @author MingLiPro - */ -public interface WinKernel32 extends Library { - static WinKernel32 load() { - return Native.load("kernel32", WinKernel32.class); - } - - boolean QueryPerformanceCounter(LongByReference lpPerformanceCount); - boolean QueryPerformanceFrequency(LongByReference lpFrequency); - void GetSystemTimePreciseAsFileTime(byte[] lpSystemTimeAsFileTime); -} diff --git a/src/main/java/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java b/src/main/java/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java index b6411b3..38abd3e 100644 --- a/src/main/java/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java +++ b/src/main/java/com/mingliqiye/utils/springboot/autoconfigure/AutoConfiguration.java @@ -16,22 +16,26 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile AutoConfiguration.java - * LastUpdate 2025-09-09 08:37:34 + * LastUpdate 2025-09-13 01:23:09 * UpdateUser MingLiPro */ package com.mingliqiye.utils.springboot.autoconfigure; import com.mingliqiye.utils.collection.ForEach; +import com.mingliqiye.utils.collection.Lists; +import com.mingliqiye.utils.system.SystemUtil; import com.mingliqiye.utils.time.DateTime; import com.mingliqiye.utils.time.Formatter; -import java.io.IOException; -import java.io.InputStream; +import lombok.val; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.ComponentScan; +import java.io.IOException; +import java.io.InputStream; + @org.springframework.boot.autoconfigure.AutoConfiguration @EnableConfigurationProperties(AutoConfiguration.class) @ComponentScan( @@ -80,7 +84,10 @@ public class AutoConfiguration { while ((readlen = inputStream.read(buffer)) != -1) { metaData.append(new String(buffer, 0, readlen)); } - ForEach.forEach(metaData.toString().split("\n"), (s, i) -> { + val da = Lists.toList(metaData.toString().split("\n")); + da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7)); + da.add("jdkRuntime=" + SystemUtil.getJdkVersion()); + ForEach.forEach(da, (s, i) -> { String[] d = s.trim().split("=", 2); if (d.length >= 2) { String content = "| " + d[0] + ": " + d[1]; @@ -100,9 +107,8 @@ public class AutoConfiguration { e.printStackTrace(); } banner2 = bannerBuilder.toString(); - System.out.printf( - banner2, - DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7) + System.out.print( + banner2 ); System.out.println( "---------------------------------------------------------" diff --git a/src/main/java/com/mingliqiye/utils/test/Main.java b/src/main/java/com/mingliqiye/utils/test/Main.java deleted file mode 100644 index dd05dd8..0000000 --- a/src/main/java/com/mingliqiye/utils/test/Main.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile Main.java - * LastUpdate 2025-09-12 12:19:48 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.test; - -import com.mingliqiye.utils.version.VersionUtils; - -public class Main { - - public static void main(String[] args) { - System.out.println(VersionUtils.is("1.3", "1.2.3")); - } -} diff --git a/src/main/java/com/mingliqiye/utils/time/DateTime.java b/src/main/java/com/mingliqiye/utils/time/DateTime.java index 745350f..5713eaa 100644 --- a/src/main/java/com/mingliqiye/utils/time/DateTime.java +++ b/src/main/java/com/mingliqiye/utils/time/DateTime.java @@ -16,14 +16,22 @@ * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile DateTime.java - * LastUpdate 2025-09-09 08:37:33 + * LastUpdate 2025-09-13 10:14:09 * UpdateUser MingLiPro */ package com.mingliqiye.utils.time; -import com.mingliqiye.utils.jna.time.WinKernel32; +import com.mingliqiye.utils.jna.WinKernel32Api; +import com.mingliqiye.utils.jna.WinKernel32ApiFactory; import com.mingliqiye.utils.system.SystemUtil; +import lombok.Getter; +import lombok.Setter; +import lombok.val; +import lombok.var; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; + import java.io.Serializable; import java.time.Instant; import java.time.LocalDateTime; @@ -31,10 +39,10 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.Date; -import lombok.Getter; -import lombok.Setter; -import lombok.var; -import org.jetbrains.annotations.NotNull; + +import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.FILETIME_EPOCH_OFFSET; +import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.NANOS_PER_100NS; +import static com.mingliqiye.utils.logger.Loggers.getMingLiLoggerFactory; /** * 时间类,用于处理日期时间的转换、格式化等操作。 @@ -54,15 +62,38 @@ import org.jetbrains.annotations.NotNull; @Setter public final class DateTime implements Serializable { - private static final WinKernel32 WIN_KERNEL_32; - private static final long FILETIME_EPOCH_OFFSET = -116444736000000000L; - private static final long NANOS_PER_100NS = 100; + private static final WinKernel32Api WIN_KERNEL_32_API; static { - if (!SystemUtil.isJdk8Plus() && SystemUtil.isWindows()) { - WIN_KERNEL_32 = WinKernel32.load(); + if (SystemUtil.getJavaVersionAsInteger() == 8 && SystemUtil.isWindows()) { + + final Logger log = getMingLiLoggerFactory().getLogger( + "mingli-utils DateTime" + ); + val a = WinKernel32ApiFactory.getWinKernel32Apis(); + + if (a.size() > 1) { + log.warn( + "Multiple Size:{} WinKernel32Api implementations found.", + a.size() + ); + a.forEach(api -> + log.warn( + "Found WinKernel32Api: {}", + api.getClass().getName() + ) + ); + } + + if (a.isEmpty()) { + WIN_KERNEL_32_API = null; + log.warn("No WinKernel32Api implementation found. Use Jdk1.8 LocalDateTime"); + } else { + WIN_KERNEL_32_API = a.get(a.size() - 1); + log.info("Found and Use WinKernel32Api: {}", WIN_KERNEL_32_API.getClass().getName()); + } } else { - WIN_KERNEL_32 = null; + WIN_KERNEL_32_API = null; } } @@ -95,26 +126,9 @@ public final class DateTime implements Serializable { * @return 返回当前时间的 DateTime 实例 */ public static DateTime now() { - if (WIN_KERNEL_32 != null) { - byte[] fileTimeBuffer = new byte[8]; - WIN_KERNEL_32.GetSystemTimePreciseAsFileTime(fileTimeBuffer); - long fileTime = - (long) (fileTimeBuffer[0] & 0xFF) | - ((long) (fileTimeBuffer[1] & 0xFF) << 8) | - ((long) (fileTimeBuffer[2] & 0xFF) << 16) | - ((long) (fileTimeBuffer[3] & 0xFF) << 24) | - ((long) (fileTimeBuffer[4] & 0xFF) << 32) | - ((long) (fileTimeBuffer[5] & 0xFF) << 40) | - ((long) (fileTimeBuffer[6] & 0xFF) << 48) | - ((long) (fileTimeBuffer[7] & 0xFF) << 56); - long unixNanos = - (fileTime + FILETIME_EPOCH_OFFSET) * NANOS_PER_100NS; - Instant instant = Instant.ofEpochSecond( - unixNanos / 1_000_000_000L, - unixNanos % 1_000_000_000L - ); + if (WIN_KERNEL_32_API != null) { return DateTime.of( - instant.atZone(ZoneId.systemDefault()).toLocalDateTime() + WIN_KERNEL_32_API.getTime().atZone(ZoneId.systemDefault()).toLocalDateTime() ); } return new DateTime(); diff --git a/src/main/java/com/mingliqiye/utils/uuid/MysqlUUIDv1.java b/src/main/java/com/mingliqiye/utils/uuid/MysqlUUIDv1.java deleted file mode 100644 index 0fb8cbb..0000000 --- a/src/main/java/com/mingliqiye/utils/uuid/MysqlUUIDv1.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile MysqlUUIDv1.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.uuid; - -import lombok.var; - -/** - * MySQL UUID格式与标准UUID格式相互转换工具类 - *

- * MySQL使用不同的字节顺序存储UUID,此类提供了在MySQL格式和标准UUID格式之间转换的方法 - * @author MingLiPro - */ -public class MysqlUUIDv1 { - - /** - * 将标准UUID格式转换为MySQL格式的UUID - * - * @param uuid 标准UUID格式的字节数组,长度必须为16字节 - * @return MySQL格式的UUID字节数组,长度为16字节 - */ - public static byte[] uuidToMysql(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; - } - - /** - * 将MySQL格式的UUID转换为标准UUID格式 - * - * @param uuid MySQL格式的UUID字节数组,长度必须为16字节 - * @return 标准UUID格式的字节数组,长度为16字节 - */ - public static byte[] mysqlToUuid(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/main/java/com/mingliqiye/utils/uuid/UUIDException.java b/src/main/java/com/mingliqiye/utils/uuid/UUIDException.java deleted file mode 100644 index 4e40b64..0000000 --- a/src/main/java/com/mingliqiye/utils/uuid/UUIDException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile UUIDException.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.uuid; - -public class UUIDException extends RuntimeException { - - public UUIDException(String message) { - super(message); - } - - public UUIDException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java b/src/main/java/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java deleted file mode 100644 index 12c3eb9..0000000 --- a/src/main/java/com/mingliqiye/utils/uuid/typehandlers/UUIDConverter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile UUIDConverter.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -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/main/java/com/mingliqiye/utils/uuid/typehandlers/mysql/UUIDBinaryTypeHandler.java b/src/main/java/com/mingliqiye/utils/uuid/typehandlers/mysql/UUIDBinaryTypeHandler.java deleted file mode 100644 index 44f4051..0000000 --- a/src/main/java/com/mingliqiye/utils/uuid/typehandlers/mysql/UUIDBinaryTypeHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile UUIDBinaryTypeHandler.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.uuid.typehandlers.mysql; - -import com.mingliqiye.utils.uuid.UUID; -import com.mingliqiye.utils.uuid.typehandlers.UUIDConverter; -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.BINARY) -public class UUIDBinaryTypeHandler 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.setBytes(i, UUIDConverter.UUID_TO_BIN(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.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 UUIDConverter.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 UUIDConverter.BIN_TO_UUID(cs.getBytes(columnIndex)); - } -} diff --git a/src/main/java/com/mingliqiye/utils/uuid/typehandlers/pgsql/UUIDStringTypeHandler.java b/src/main/java/com/mingliqiye/utils/uuid/typehandlers/pgsql/UUIDStringTypeHandler.java deleted file mode 100644 index 462ec80..0000000 --- a/src/main/java/com/mingliqiye/utils/uuid/typehandlers/pgsql/UUIDStringTypeHandler.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2025 mingliqiye - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ProjectName mingli-utils - * ModuleName mingli-utils.main - * CurrentFile UUIDStringTypeHandler.java - * LastUpdate 2025-09-09 08:37:33 - * UpdateUser MingLiPro - */ - -package com.mingliqiye.utils.uuid.typehandlers.pgsql; - -import com.mingliqiye.utils.uuid.UUID; -import com.mingliqiye.utils.uuid.typehandlers.UUIDConverter; -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)); - } -} diff --git a/src/main/kotlin/com/mingliqiye/utils/Main.kt b/src/main/kotlin/com/mingliqiye/utils/Main.kt index 56beadf..83000f5 100644 --- a/src/main/kotlin/com/mingliqiye/utils/Main.kt +++ b/src/main/kotlin/com/mingliqiye/utils/Main.kt @@ -24,12 +24,9 @@ package com.mingliqiye.utils -import com.mingliqiye.utils.path.OsPath import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration fun main() { AutoConfiguration.printBanner() - val path = OsPath.getCwd() - println(path.toAbsolutePath()) } diff --git a/src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt b/src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt new file mode 100644 index 0000000..7e026a5 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile AesUtils.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ + + +@file:JvmName("AesUtils") + +package com.mingliqiye.utils.aes + +import com.mingliqiye.utils.base64.Base64Utils +import java.nio.charset.StandardCharsets +import java.security.GeneralSecurityException +import java.security.MessageDigest +import java.security.SecureRandom +import javax.crypto.Cipher +import javax.crypto.spec.GCMParameterSpec +import javax.crypto.spec.SecretKeySpec + +const val ALGORITHM = "AES" +const val TRANSFORMATION = "AES/GCM/NoPadding" +const val GCM_IV_LENGTH = 12 +const val GCM_TAG_LENGTH = 16 +val SECURE_RANDOM = SecureRandom() + + +/** + * AES加密方法(使用GCM模式) + * @param sSrc 待加密的字符串 + * @param sKey 加密密钥 + * @return 加密后的字符串,格式为 IV:EncryptedData+Tag(均为Base64编码) + * @throws GeneralSecurityException 加密错误 + */ +@Throws(GeneralSecurityException::class) +fun encrypt(sSrc: String, sKey: String?): String? { + if (sKey == null) { + return null + } + + // 生成密钥 + val secretKeySpec = createSecretKey(sKey) + + // 生成安全随机IV + val iv = ByteArray(GCM_IV_LENGTH) + SECURE_RANDOM.nextBytes(iv) + + // 初始化加密器 + val cipher = Cipher.getInstance(TRANSFORMATION) + val gcmParameterSpec = GCMParameterSpec( + GCM_TAG_LENGTH * 8, iv + ) + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec) + + val encrypted = cipher.doFinal( + sSrc.toByteArray(StandardCharsets.UTF_8) + ) + return Base64Utils.encode( + "${Base64Utils.encode(iv)}:${Base64Utils.encode(encrypted)}".toByteArray() + ) +} + +/** + * AES解密方法(使用GCM模式) + * @param sSrc 待解密的字符串,格式为 IV:EncryptedData+Tag(均为Base64编码) + * @param sKey 解密密钥 + * @return 解密后的原始字符串 + */ +fun decrypt(sSrc: String, sKey: String): String? { + try { + // 分割IV和加密数据 + val sSrcs = String(Base64Utils.decode(sSrc)) + val parts: Array = sSrcs.split(":".toRegex(), limit = 2).toTypedArray() + if (parts.size != 2) { + return null + } + val iv = Base64Utils.decode(parts[0]) + val encryptedData = Base64Utils.decode(parts[1]) + if (iv.size != GCM_IV_LENGTH) { + return null + } + val secretKeySpec = createSecretKey(sKey) + val cipher = Cipher.getInstance(TRANSFORMATION) + val gcmParameterSpec = GCMParameterSpec( + GCM_TAG_LENGTH * 8, iv + ) + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec) + val original = cipher.doFinal(encryptedData) + return String(original, StandardCharsets.UTF_8) + } catch (e: Exception) { + return null + } +} + +/** + * 创建AES密钥,支持任意长度的密钥 + * @param sKey 字符串密钥 + * @return SecretKeySpec对象 + * @throws Exception 可能抛出的异常 + */ +@Throws(GeneralSecurityException::class) +private fun createSecretKey(sKey: String): SecretKeySpec { + val key = sKey.toByteArray(StandardCharsets.UTF_8) + val md = MessageDigest.getInstance("MD5") + val digest = md.digest(key) + return SecretKeySpec(digest, ALGORITHM) +} diff --git a/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtil.kt b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtil.kt new file mode 100644 index 0000000..95db281 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtil.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile ByteUtil.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ +@file:JvmName("ByteUtil") + +package com.mingliqiye.utils.bytes + +import com.mingliqiye.utils.collection.Lists +import com.mingliqiye.utils.stream.SuperStream + +const val ESC_ASC: Byte = 0x10 +const val ESC_DESC: Byte = 0x1B +const val ESC_NONE: Byte = 0x00 +const val ESC_START: Byte = 0x01 +const val ESC_END: Byte = 0x02 +const val ESC_ESC: Byte = 0x03 +const val ESC_CONTROL: Byte = 0x04 +const val ESC_DATA: Byte = 0x05 +const val ESC_RESERVED: Byte = 0x06 + + +/** + * 将字节数组转换为十六进制字符串列表 + * + * @param bytes 输入的字节数组 + * @return 包含每个字节对应十六进制字符串的列表 + */ +fun getByteArrayString(bytes: ByteArray): MutableList { + return SuperStream.of(Lists.toList(bytes)) + .map { a -> String.format("%02x", a!!.toInt() and 0xFF) } + .collect(SuperStream.Collectors.toList()) +} + diff --git a/src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt b/src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt new file mode 100644 index 0000000..0a5b2bc --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile FieldStructure.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.jna + +import com.sun.jna.Structure +import java.lang.reflect.Modifier + +/** + * JNA结构体基类,自动处理字段顺序 + * 该类继承自JNA的Structure类,通过反射自动获取子类的公共非静态字段, + * 并按声明顺序返回字段名列表,用于JNA结构体的字段映射。 + */ +class FieldStructure : Structure() { + /** + * 获取结构体字段顺序列表 + * 通过反射遍历当前类及其父类的所有声明字段,过滤出公共非静态字段, + * 按照字段在类中声明的顺序返回字段名列表。 + * + * @return 包含字段名的列表,按声明顺序排列 + */ + override fun getFieldOrder(): MutableList { + val fieldOrderList: MutableList = ArrayList() + var cls: Class<*> = javaClass + while (cls != FieldStructure::class.java) { + val fields = cls.getDeclaredFields() + var modifiers: Int + for (field in fields) { + modifiers = field.modifiers + if (Modifier.isStatic(modifiers) || + !Modifier.isPublic(modifiers) + ) { + continue + } + fieldOrderList.add(field.name) + } + cls = cls.getSuperclass() + } + return fieldOrderList + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt b/src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt new file mode 100644 index 0000000..8fcf2ef --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt @@ -0,0 +1,421 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile Loggers.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ + +@file:JvmName("Loggers") + +package com.mingliqiye.utils.logger + + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.slf4j.Marker +import java.util.* + +enum class MingLiLoggerLevel { + TRACE, + DEBUG, + INFO, + WARN, + ERROR +} + +class MingLiLogger : Logger { + override fun getName(): String { + return "MingLiLogger" + } + + override fun isTraceEnabled(): Boolean { + return true + } + + override fun trace(msg: String?) { + msg?.let { toPrintln(it, MingLiLoggerLevel.TRACE) } + } + + override fun trace(format: String?, arg: Any?) { + format?.let { + val message = format1(it, arg) + toPrintln(message, MingLiLoggerLevel.TRACE) + } + } + + override fun trace(format: String?, arg1: Any?, arg2: Any?) { + format?.let { + val message = format2(it, arg1, arg2) + toPrintln(message, MingLiLoggerLevel.TRACE) + } + } + + override fun trace(format: String?, vararg arguments: Any?) { + format?.let { + val message = formatArray(it, arguments) + toPrintln(message, MingLiLoggerLevel.TRACE) + } + } + + override fun trace(msg: String?, t: Throwable?) { + msg?.let { + val message = if (t != null) "$it: ${t.message}" else it + toPrintln(message, MingLiLoggerLevel.TRACE) + } + } + + override fun isTraceEnabled(marker: Marker?): Boolean { + return true + } + + override fun trace(marker: Marker?, msg: String?) { + trace(msg) + } + + override fun trace(marker: Marker?, format: String?, arg: Any?) { + trace(format, arg) + } + + override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { + trace(format, arg1, arg2) + } + + override fun trace(marker: Marker?, format: String?, vararg arguments: Any?) { + trace(format, *arguments) + } + + override fun trace(marker: Marker?, msg: String?, t: Throwable?) { + trace(msg, t) + } + + override fun isDebugEnabled(): Boolean { + return true + } + + override fun debug(msg: String?) { + msg?.let { toPrintln(it, MingLiLoggerLevel.DEBUG) } + } + + override fun debug(format: String?, arg: Any?) { + format?.let { + val message = format1(it, arg) + toPrintln(message, MingLiLoggerLevel.DEBUG) + } + } + + override fun debug(format: String?, arg1: Any?, arg2: Any?) { + format?.let { + val message = format2(it, arg1, arg2) + toPrintln(message, MingLiLoggerLevel.DEBUG) + } + } + + override fun debug(format: String?, vararg arguments: Any?) { + format?.let { + val message = formatArray(it, arguments) + toPrintln(message, MingLiLoggerLevel.DEBUG) + } + } + + override fun debug(msg: String?, t: Throwable?) { + msg?.let { + val message = if (t != null) "$it: ${t.message}" else it + toPrintln(message, MingLiLoggerLevel.DEBUG) + } + } + + override fun isDebugEnabled(marker: Marker?): Boolean { + return true + } + + override fun debug(marker: Marker?, msg: String?) { + debug(msg) + } + + override fun debug(marker: Marker?, format: String?, arg: Any?) { + debug(format, arg) + } + + override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { + debug(format, arg1, arg2) + } + + override fun debug(marker: Marker?, format: String?, vararg arguments: Any?) { + debug(format, *arguments) + } + + override fun debug(marker: Marker?, msg: String?, t: Throwable?) { + debug(msg, t) + } + + override fun isInfoEnabled(): Boolean { + return true + } + + override fun info(msg: String?) { + msg?.let { toPrintln(it, MingLiLoggerLevel.INFO) } + } + + override fun info(format: String?, arg: Any?) { + format?.let { + val message = format1(it, arg) + toPrintln(message, MingLiLoggerLevel.INFO) + } + } + + override fun info(format: String?, arg1: Any?, arg2: Any?) { + format?.let { + val message = format2(it, arg1, arg2) + toPrintln(message, MingLiLoggerLevel.INFO) + } + } + + override fun info(format: String?, vararg arguments: Any?) { + format?.let { + val message = formatArray(it, arguments) + toPrintln(message, MingLiLoggerLevel.INFO) + } + } + + override fun info(msg: String?, t: Throwable?) { + msg?.let { + val message = if (t != null) "$it: ${t.message}" else it + toPrintln(message, MingLiLoggerLevel.INFO) + } + } + + override fun isInfoEnabled(marker: Marker?): Boolean { + return true + } + + override fun info(marker: Marker?, msg: String?) { + info(msg) + } + + override fun info(marker: Marker?, format: String?, arg: Any?) { + info(format, arg) + } + + override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { + info(format, arg1, arg2) + } + + override fun info(marker: Marker?, format: String?, vararg arguments: Any?) { + info(format, *arguments) + } + + override fun info(marker: Marker?, msg: String?, t: Throwable?) { + info(msg, t) + } + + override fun isWarnEnabled(): Boolean { + return true + } + + override fun warn(msg: String?) { + msg?.let { toPrintln(it, MingLiLoggerLevel.WARN) } + } + + override fun warn(format: String?, arg: Any?) { + format?.let { + val message = format1(it, arg) + toPrintln(message, MingLiLoggerLevel.WARN) + } + } + + override fun warn(format: String?, vararg arguments: Any?) { + format?.let { + val message = formatArray(it, arguments) + toPrintln(message, MingLiLoggerLevel.WARN) + } + } + + override fun warn(format: String?, arg1: Any?, arg2: Any?) { + format?.let { + val message = format2(it, arg1, arg2) + toPrintln(message, MingLiLoggerLevel.WARN) + } + } + + override fun warn(msg: String?, t: Throwable?) { + msg?.let { + val message = if (t != null) "$it: ${t.message}" else it + toPrintln(message, MingLiLoggerLevel.WARN) + } + } + + override fun isWarnEnabled(marker: Marker?): Boolean { + return true + } + + override fun warn(marker: Marker?, msg: String?) { + warn(msg) + } + + override fun warn(marker: Marker?, format: String?, arg: Any?) { + warn(format, arg) + } + + override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { + warn(format, arg1, arg2) + } + + override fun warn(marker: Marker?, format: String?, vararg arguments: Any?) { + warn(format, *arguments) + } + + override fun warn(marker: Marker?, msg: String?, t: Throwable?) { + warn(msg, t) + } + + override fun isErrorEnabled(): Boolean { + return true + } + + override fun error(msg: String?) { + msg?.let { toPrintln(it, MingLiLoggerLevel.ERROR) } + } + + override fun error(format: String?, arg: Any?) { + format?.let { + val message = format1(it, arg) + toPrintln(message, MingLiLoggerLevel.ERROR) + } + } + + override fun error(format: String?, arg1: Any?, arg2: Any?) { + format?.let { + val message = format2(it, arg1, arg2) + toPrintln(message, MingLiLoggerLevel.ERROR) + } + } + + override fun error(format: String?, vararg arguments: Any?) { + format?.let { + val message = formatArray(it, arguments) + toPrintln(message, MingLiLoggerLevel.ERROR) + } + } + + override fun error(msg: String?, t: Throwable?) { + msg?.let { + val message = if (t != null) "$it: ${t.message}" else it + toPrintln(message, MingLiLoggerLevel.ERROR) + } + } + + override fun isErrorEnabled(marker: Marker?): Boolean { + return true + } + + override fun error(marker: Marker?, msg: String?) { + error(msg) + } + + override fun error(marker: Marker?, format: String?, arg: Any?) { + error(format, arg) + } + + override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { + error(format, arg1, arg2) + } + + override fun error(marker: Marker?, format: String?, vararg arguments: Any?) { + error(format, *arguments) + } + + override fun error(marker: Marker?, msg: String?, t: Throwable?) { + error(msg, t) + } + + fun toPrintln(message: String, level: MingLiLoggerLevel) { + when (level) { + MingLiLoggerLevel.TRACE -> println("[TRACE] $message") + MingLiLoggerLevel.DEBUG -> println("[DEBUG] $message") + MingLiLoggerLevel.INFO -> println("[INFO] $message") + MingLiLoggerLevel.WARN -> println("[WARN] $message") + MingLiLoggerLevel.ERROR -> println("[ERROR] $message") + } + } + + private fun format1(format: String, arg: Any?): String { + return if (format.contains("{}")) { + format.replaceFirst("{}", arg?.toString() ?: "null") + } else { + "$format $arg" + } + } + + private fun format2(format: String, arg1: Any?, arg2: Any?): String { + return format.replaceFirst("{}", arg1?.toString() ?: "null") + .replaceFirst("{}", arg2?.toString() ?: "null") + } + + private fun formatArray(format: String, arguments: Array): String { + var result = format + for (arg in arguments) { + result = result.replaceFirst("{}", arg?.toString() ?: "null") + } + return result + } +} + +class MingLiLoggerFactory { + private var hasSLF4JImplementation: Boolean? = null + + // 线程安全的延迟初始化 + private fun checkSLF4JImplementation(): Boolean { + if (hasSLF4JImplementation == null) { + synchronized(this) { + if (hasSLF4JImplementation == null) { + hasSLF4JImplementation = try { + // 更可靠的检测方式 + ServiceLoader.load( + Class.forName("org.slf4j.spi.SLF4JServiceProvider") + ).iterator().hasNext() + } catch (e: ClassNotFoundException) { + false + } catch (e: NoClassDefFoundError) { + false + } + } + } + } + return hasSLF4JImplementation ?: false + } + + fun getLogger(name: String): Logger { + return if (checkSLF4JImplementation()) { + LoggerFactory.getLogger(name) + } else { + MingLiLogger() + } + } + + fun getLogger(clazz: Class<*>): Logger { + return if (checkSLF4JImplementation()) { + LoggerFactory.getLogger(clazz) + } else { + MingLiLogger() + } + } +} + +val mingLiLoggerFactory = MingLiLoggerFactory() + + diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt new file mode 100644 index 0000000..1a35a28 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/datetime/DateTimeTypeHandler.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile DateTimeTypeHandler.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ +@file:JvmName("DateTimeConvertor") + +package com.mingliqiye.utils.mybatis.typehandler.datetime + +import com.mingliqiye.utils.time.DateTime +import org.apache.ibatis.type.BaseTypeHandler +import org.apache.ibatis.type.JdbcType +import org.apache.ibatis.type.MappedTypes +import java.sql.CallableStatement +import java.sql.PreparedStatement +import java.sql.ResultSet +import java.sql.SQLException +import java.time.LocalDateTime + +/** + * 将LocalDateTime对象转换为DateTime对象 + * + * @param localDateTime LocalDateTime对象 + * @return DateTime对象,如果localDateTime为null则返回null + */ +fun toDateTime(localDateTime: LocalDateTime?): DateTime? { + return localDateTime?.let { DateTime.of(it) } +} + +/** + * 将DateTime对象转换为LocalDateTime对象 + * + * @param dateTime DateTime对象 + * @return LocalDateTime对象,如果dateTime为null则返回null + */ +fun toLocalDateTime(dateTime: DateTime?): LocalDateTime? { + return dateTime?.toLocalDateTime() +} + +/** + * DateTime类型处理器,用于在数据库和Java对象之间转换DateTime类型 + * @author MingLiQiye + * @date 2025/9/12 + */ +@MappedTypes(DateTime::class) +class DateTimeTypeHandler : BaseTypeHandler() { + + @Throws(SQLException::class) + override fun setNonNullParameter( + ps: PreparedStatement, + i: Int, + parameter: DateTime, // 移除了 ?,因为这是 non-null 方法 + jdbcType: JdbcType + ) { + // 使用 setObject 允许传入 null,由数据库处理 + ps.setObject(i, toLocalDateTime(parameter)) + } + + @Throws(SQLException::class) + override fun getNullableResult(rs: ResultSet, columnName: String): DateTime? { + // 安全类型转换和空检查 + return when (val value = rs.getObject(columnName)) { + is LocalDateTime -> toDateTime(value) + null -> null + else -> throw SQLException("Expected LocalDateTime for column '$columnName', but got ${value.javaClass.name}") + } + } + + @Throws(SQLException::class) + override fun getNullableResult(rs: ResultSet, columnIndex: Int): DateTime? { + return when (val value = rs.getObject(columnIndex)) { + is LocalDateTime -> toDateTime(value) + null -> null + else -> throw SQLException("Expected LocalDateTime at column index $columnIndex, but got ${value.javaClass.name}") + } + } + + @Throws(SQLException::class) + override fun getNullableResult(cs: CallableStatement, columnIndex: Int): DateTime? { + return when (val value = cs.getObject(columnIndex)) { + is LocalDateTime -> toDateTime(value) + null -> null + else -> throw SQLException("Expected LocalDateTime at column index $columnIndex, but got ${value.javaClass.name}") + } + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/UUIDTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/UUIDTypeHandler.kt new file mode 100644 index 0000000..9b369ab --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/UUIDTypeHandler.kt @@ -0,0 +1,279 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile UUIDTypeHandler.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ +@file:JvmName("UUIDConvertor") + +package com.mingliqiye.utils.mybatis.typehandler.uuid + +import com.mingliqiye.utils.uuid.UUID +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.CallableStatement +import java.sql.PreparedStatement +import java.sql.ResultSet +import java.util.UUID as JUUID + + +/** + * 将字节数组转换为UUID对象 + * + * @param byteArray 字节数组 + * @return UUID对象,如果字节数组为null则返回null + */ +fun byteArraytoUUID(byteArray: ByteArray?): UUID? { + return byteArray?.let { UUID.of(it) } +} + +/** + * 将UUID对象转换为字节数组 + * + * @param uuid UUID对象 + * @return 字节数组,如果UUID为null则返回null + */ +fun uuidToByteArray(uuid: UUID?): ByteArray? { + return uuid?.toBytes() +} + +/** + * 将字符串转换为UUID对象 + * + * @param str 字符串 + * @return UUID对象,如果字符串为null则返回null + */ +fun stringToUUID(str: String?): UUID? { + return str?.let { UUID.of(it) } +} + +/** + * 将UUID对象转换为字符串 + * + * @param uuid UUID对象 + * @return 字符串,如果UUID为null则返回null + */ +fun uuidToString(uuid: UUID?): String? { + return uuid?.getString() +} + +/** + * 将java UUID转换为UUID对象 + * + * @param uuid JUUID java UUID + * @return UUID对象,如果字符串为null则返回null + */ +fun juuidToUUID(uuid: JUUID?): UUID? { + return uuid?.let { UUID(it) } +} + +/** + * 将UUID对象转换为java UUID + * + * @param uuid UUID对象 + * @return java UUID,如果UUID为null则返回null + */ +fun uuidToJuuid(uuid: UUID?): JUUID? { + return uuid?.getUuid() +} + + +/** + * JDBC类型转换 UUID BINARY + * @author MingLiQiye + * @date 2025/9/12 + */ +@MappedTypes(UUID::class) +@MappedJdbcTypes(JdbcType.BINARY) +class UUIDBinaryTypeHandler : BaseTypeHandler() { + /** + * 设置非空参数到PreparedStatement中 + * + * @param ps PreparedStatement对象 + * @param i 参数索引 + * @param parameter UUID参数值 + * @param jdbcType JDBC类型 + */ + override fun setNonNullParameter( + ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType + ) { + ps.setBytes(i, uuidToByteArray(parameter)) + } + + /** + * 从ResultSet中根据列名获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnName 列名 + * @return UUID对象或null + */ + override fun getNullableResult( + rs: ResultSet, columnName: String + ): UUID? { + return byteArraytoUUID(rs.getBytes(columnName)) + } + + /** + * 从ResultSet中根据列索引获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? { + return byteArraytoUUID(rs.getBytes(columnIndex)) + } + + /** + * 从CallableStatement中根据列索引获取可空的UUID结果 + * + * @param cs CallableStatement对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult( + cs: CallableStatement, columnIndex: Int + ): UUID? { + return byteArraytoUUID(cs.getBytes(columnIndex)) + } +} + +/** + * JDBC类型转换 UUID String + * @author MingLiQiye + * @date 2025/9/12 + */ +@MappedTypes(UUID::class) +@MappedJdbcTypes(JdbcType.VARCHAR) +class UUIDStringTypeHandler : BaseTypeHandler() { + /** + * 设置非空参数到PreparedStatement中 + * + * @param ps PreparedStatement对象 + * @param i 参数索引 + * @param parameter UUID参数值 + * @param jdbcType JDBC类型 + */ + override fun setNonNullParameter( + ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType + ) { + ps.setString(i, uuidToString(parameter)) + } + + /** + * 从ResultSet中根据列名获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnName 列名 + * @return UUID对象或null + */ + override fun getNullableResult( + rs: ResultSet, columnName: String + ): UUID? { + return stringToUUID(rs.getString(columnName)) + } + + /** + * 从ResultSet中根据列索引获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? { + return stringToUUID(rs.getString(columnIndex)) + + } + + /** + * 从CallableStatement中根据列索引获取可空的UUID结果 + * + * @param cs CallableStatement对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult( + cs: CallableStatement, columnIndex: Int + ): UUID? { + return stringToUUID(cs.getString(columnIndex)) + } + +} + +/** + * JDBC类型转换 UUID java UUID + * @author MingLiQiye + * @date 2025/9/12 + */ +@MappedTypes(UUID::class) +@MappedJdbcTypes(JdbcType.OTHER) +class UUIDTypeHandler : BaseTypeHandler() { + /** + * 设置非空参数到PreparedStatement中 + * + * @param ps PreparedStatement对象 + * @param i 参数索引 + * @param parameter UUID参数值 + * @param jdbcType JDBC类型 + */ + override fun setNonNullParameter( + ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType + ) { + ps.setObject(i, parameter.getUuid()) + } + + /** + * 从ResultSet中根据列名获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnName 列名 + * @return UUID对象或null + */ + override fun getNullableResult( + rs: ResultSet, + columnName: String + ): UUID? { + return juuidToUUID(rs.getObject(columnName, JUUID::class.java) as JUUID) + } + + /** + * 从ResultSet中根据列索引获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? { + return juuidToUUID(rs.getObject(columnIndex, JUUID::class.java) as JUUID) + } + + /** + * 从CallableStatement中根据列索引获取可空的UUID结果 + * + * @param cs CallableStatement对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult( + cs: CallableStatement, columnIndex: Int + ): UUID? { + return juuidToUUID(cs.getObject(columnIndex, JUUID::class.java) as JUUID) + } +} diff --git a/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/mysql/MysqlUUIDBinaryTypeHandler.kt b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/mysql/MysqlUUIDBinaryTypeHandler.kt new file mode 100644 index 0000000..7270599 --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/mybatis/typehandler/uuid/mysql/MysqlUUIDBinaryTypeHandler.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MysqlUUIDBinaryTypeHandler.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ + +package com.mingliqiye.utils.mybatis.typehandler.uuid.mysql + +import com.mingliqiye.utils.uuid.UUID +import com.mingliqiye.utils.uuid.mysqlToUuid +import com.mingliqiye.utils.uuid.uuidToMysql +import org.apache.ibatis.type.BaseTypeHandler +import org.apache.ibatis.type.JdbcType +import org.apache.ibatis.type.MappedTypes +import java.sql.CallableStatement +import java.sql.PreparedStatement +import java.sql.ResultSet + +/** + * JDBC类型转换 UUID + * @author MingLiQiye + * @date 2025/9/12 + */ +@MappedTypes(UUID::class) +class MysqlUUIDBinaryTypeHandler : BaseTypeHandler() { + + /** + * 将字节数组转换为UUID对象 + * + * @param byteArray 字节数组 + * @return UUID对象,如果字节数组为null则返回null + */ + private fun toUUID(byteArray: ByteArray?): UUID? { + return byteArray?.let { UUID.of(mysqlToUuid(it)) } + } + + /** + * 将UUID对象转换为字节数组 + * + * @param uuid UUID对象 + * @return 字节数组,如果UUID为null则返回null + */ + fun toByteArray(uuid: UUID?): ByteArray? { + return uuid?.let { uuidToMysql(it.toBytes()) } + } + + /** + * 设置非空参数到PreparedStatement中 + * + * @param ps PreparedStatement对象 + * @param i 参数索引 + * @param parameter UUID参数值 + * @param jdbcType JDBC类型 + */ + override fun setNonNullParameter( + ps: PreparedStatement, + i: Int, + parameter: UUID, + jdbcType: JdbcType + ) { + ps.setBytes(i, toByteArray(parameter)) + } + + /** + * 从ResultSet中根据列名获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnName 列名 + * @return UUID对象或null + */ + override fun getNullableResult( + rs: ResultSet, + columnName: String + ): UUID? { + return toUUID(rs.getBytes(columnName)) + } + + /** + * 从ResultSet中根据列索引获取可空的UUID结果 + * + * @param rs ResultSet对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? { + return toUUID(rs.getBytes(columnIndex)) + } + + /** + * 从CallableStatement中根据列索引获取可空的UUID结果 + * + * @param cs CallableStatement对象 + * @param columnIndex 列索引 + * @return UUID对象或null + */ + override fun getNullableResult( + cs: CallableStatement, + columnIndex: Int + ): UUID? { + return toUUID(cs.getBytes(columnIndex)) + } + +} diff --git a/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt b/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt new file mode 100644 index 0000000..4ddf00a --- /dev/null +++ b/src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2025 mingliqiye + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ProjectName mingli-utils + * ModuleName mingli-utils.main + * CurrentFile MysqlUUIDv1.kt + * LastUpdate 2025-09-14 18:19:29 + * UpdateUser MingLiPro + */ +@file:JvmName("MysqlUUIDv1") + +package com.mingliqiye.utils.uuid + + +fun uuidToMysql(uuid: ByteArray): ByteArray { + val reuuid = ByteArray(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 +} + +fun mysqlToUuid(uuid: ByteArray): ByteArray { + val reuuid = ByteArray(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/main/resources/META-INF/meta-data b/src/main/resources/META-INF/meta-data index ed435d7..f65167e 100644 --- a/src/main/resources/META-INF/meta-data +++ b/src/main/resources/META-INF/meta-data @@ -4,4 +4,4 @@ artifactId=$ARTIFACTID version=$VERSIONS buildJdkVersion=$JDKVERSIONS author=MingLiPro -website=mingliqiye.com +website=https://mingli-utils.mingliqiye.com