generated from mingliqiye/lib-tem
Compare commits
3 Commits
d991b4077b
...
01bfb052d0
| Author | SHA1 | Date | |
|---|---|---|---|
| 01bfb052d0 | |||
| 1fab0b02be | |||
| fb4e103da8 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -44,4 +44,4 @@ log
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
*lock*
|
*lock*
|
||||||
|
.kotlin
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils
|
* ModuleName mingli-utils
|
||||||
* CurrentFile build.gradle.kts
|
* CurrentFile build.gradle.kts
|
||||||
* LastUpdate 2025-09-12 14:06:21
|
* LastUpdate 2025-09-13 10:11:22
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -59,10 +59,6 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
@ -81,8 +77,11 @@ dependencies {
|
|||||||
implementation("com.github.f4b6a3:uuid-creator:6.1.0")
|
implementation("com.github.f4b6a3:uuid-creator:6.1.0")
|
||||||
implementation("org.mindrot:jbcrypt:0.4")
|
implementation("org.mindrot:jbcrypt:0.4")
|
||||||
implementation("org.jetbrains:annotations:24.0.0")
|
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("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<JavaCompile> {
|
|||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Jar>("javaDocJar") {
|
|
||||||
group = "build"
|
|
||||||
archiveClassifier.set("javadoc")
|
|
||||||
dependsOn(tasks.dokkaGfm, tasks.dokkaHtml, tasks.dokkaJavadoc, tasks.dokkaJekyll)
|
|
||||||
from(buildDir.resolve("dokka/javadoc"))
|
|
||||||
}
|
|
||||||
tasks.register<Jar>("kotlinDocJar") {
|
|
||||||
group = "build"
|
|
||||||
archiveClassifier.set("kotlindoc")
|
|
||||||
dependsOn(tasks.dokkaHtml)
|
|
||||||
from(buildDir.resolve("dokka/html"))
|
|
||||||
}
|
|
||||||
tasks.build {
|
|
||||||
dependsOn("javaDocJar", "kotlinDocJar")
|
|
||||||
}
|
|
||||||
tasks.withType<JavaExec>().configureEach {
|
tasks.withType<JavaExec>().configureEach {
|
||||||
jvmArgs = listOf(
|
jvmArgs = listOf(
|
||||||
"-Dfile.encoding=UTF-8",
|
"-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8"
|
||||||
"-Dsun.stdout.encoding=UTF-8",
|
|
||||||
"-Dsun.stderr.encoding=UTF-8"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +125,7 @@ tasks.withType<org.gradle.jvm.tasks.Jar> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val isJdk8Build = project.findProperty("buildForJdk8") == "true"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
@ -150,6 +134,18 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register<Jar>("javaDocJar") {
|
||||||
|
group = "build"
|
||||||
|
archiveClassifier.set("javadoc")
|
||||||
|
dependsOn(tasks.dokkaJavadoc)
|
||||||
|
from(buildDir.resolve("dokka/javadoc"))
|
||||||
|
}
|
||||||
|
tasks.register<Jar>("kotlinDocJar") {
|
||||||
|
group = "build"
|
||||||
|
archiveClassifier.set("kotlindoc")
|
||||||
|
dependsOn(tasks.dokkaHtml)
|
||||||
|
from(buildDir.resolve("dokka/html"))
|
||||||
|
}
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
@ -160,39 +156,34 @@ publishing {
|
|||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
groupId = GROUPSID
|
|
||||||
artifactId = ARTIFACTID
|
|
||||||
version = VERSIONS
|
|
||||||
artifact(tasks.named("javaDocJar"))
|
artifact(tasks.named("javaDocJar"))
|
||||||
artifact(tasks.named("kotlinDocJar"))
|
artifact(tasks.named("kotlinDocJar"))
|
||||||
pom {
|
artifactId = ARTIFACTID
|
||||||
name.set(project.name)
|
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
url.set("https://github.com/minglipro/mingli-utils")
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name.set("Apache-2.0")
|
|
||||||
url.set("https://opensource.org/licenses/Apache-2.0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
dependsOn("javaDocJar", "kotlinDocJar")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
outputs.upToDateWhen { false }
|
outputs.upToDateWhen { false }
|
||||||
filesMatching("META-INF/meta-data") {
|
filesMatching("META-INF/meta-data") {
|
||||||
expand(
|
expand(
|
||||||
mapOf(
|
project.properties + mapOf(
|
||||||
"buildTime" to LocalDateTime.now()
|
"buildTime" to LocalDateTime.now().format(
|
||||||
.format(
|
DateTimeFormatter.ofPattern(
|
||||||
DateTimeFormatter.ofPattern(
|
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
|
||||||
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
) + project.properties
|
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,10 +16,10 @@
|
|||||||
# ProjectName mingli-utils
|
# ProjectName mingli-utils
|
||||||
# ModuleName mingli-utils
|
# ModuleName mingli-utils
|
||||||
# CurrentFile gradle.properties
|
# CurrentFile gradle.properties
|
||||||
# LastUpdate 2025-09-12 14:10:24
|
# LastUpdate 2025-09-13 10:14:51
|
||||||
# UpdateUser MingLiPro
|
# UpdateUser MingLiPro
|
||||||
#
|
#
|
||||||
JDKVERSIONS=1.8
|
JDKVERSIONS=1.8
|
||||||
GROUPSID=com.mingliqiye.utils
|
GROUPSID=com.mingliqiye.utils
|
||||||
ARTIFACTID=mingli-utils
|
ARTIFACTID=mingli-utils
|
||||||
VERSIONS=3.2.7
|
VERSIONS=3.3.1
|
||||||
|
|||||||
57
jdk8/build.gradle.kts
Normal file
57
jdk8/build.gradle.kts
Normal file
@ -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<MavenPublication>("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")
|
||||||
|
}
|
||||||
@ -16,9 +16,10 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils
|
* ModuleName mingli-utils
|
||||||
* CurrentFile settings.gradle.kts
|
* CurrentFile settings.gradle.kts
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
* LastUpdate 2025-09-13 02:37:04
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
include("jdk8")
|
||||||
val ARTIFACTID: String by settings.extra
|
val ARTIFACTID: String by settings.extra
|
||||||
rootProject.name = ARTIFACTID
|
rootProject.name = ARTIFACTID
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,198 +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 Base64Utils.java
|
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base64;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base64工具类,提供对字节数组、文件和字符串的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编码。
|
|
||||||
*
|
|
||||||
* @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 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 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字符串进行解码,出错时返回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 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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String encodeBytes(byte[] bytes) {
|
|
||||||
return encodeBytes(bytes, 0, bytes.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,270 +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 Factory.java
|
|
||||||
* LastUpdate 2025-09-09 08:39:07
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类似于SpringBoot的Bean管理器
|
|
||||||
*
|
|
||||||
* @author MingLiPro
|
|
||||||
*/
|
|
||||||
public class Factory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储所有已注册的Bean实例,键为Bean名称,值为Bean实例
|
|
||||||
*/
|
|
||||||
public static final ConcurrentMap<String, Object> BEANS =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储按类型查找的Bean实例,键为Bean的Class对象,值为Bean实例
|
|
||||||
*/
|
|
||||||
private static final ConcurrentMap<Class<?>, Object> TYPE_BEANS =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 私有构造函数,防止外部实例化该类
|
|
||||||
*/
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 扫描指定包路径下的所有类文件,并注册其中带有@ComponentBean注解的类为Bean
|
|
||||||
*
|
|
||||||
* @param basePackage 要扫描的基础包名
|
|
||||||
* @throws RuntimeException 如果在扫描过程中发生异常
|
|
||||||
*/
|
|
||||||
public static void scan(String basePackage) {
|
|
||||||
try {
|
|
||||||
String path = basePackage.replace('.', '/');
|
|
||||||
ClassLoader classLoader =
|
|
||||||
Thread.currentThread().getContextClassLoader();
|
|
||||||
Enumeration<URL> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
TYPE_BEANS.put(clazz, instance);
|
|
||||||
|
|
||||||
for (Class<?> interfaceClass : clazz.getInterfaces()) {
|
|
||||||
TYPE_BEANS.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据类型和名称查找对应的依赖实例
|
|
||||||
*
|
|
||||||
* @param type 依赖的类型
|
|
||||||
* @param name 依赖的名称(可为空)
|
|
||||||
* @return 找到的依赖实例,未找到则返回null
|
|
||||||
*/
|
|
||||||
private static Object findDependency(Class<?> type, String name) {
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
return BEANS.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object dependency = TYPE_BEANS.get(type);
|
|
||||||
if (dependency != null) {
|
|
||||||
return dependency;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Class<?> interfaceType : TYPE_BEANS.keySet()) {
|
|
||||||
if (type.isAssignableFrom(interfaceType)) {
|
|
||||||
return TYPE_BEANS.get(interfaceType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
TYPE_BEANS.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);
|
|
||||||
TYPE_BEANS.put(object.getClass(), object);
|
|
||||||
try {
|
|
||||||
injectDependencies();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据类型获取对应的Bean实例
|
|
||||||
*
|
|
||||||
* @param objclass Bean的类型
|
|
||||||
* @param <T> Bean的泛型类型
|
|
||||||
* @return 对应类型的Bean实例,未找到则返回null
|
|
||||||
*/
|
|
||||||
public static <T> T get(Class<T> objclass) {
|
|
||||||
return objclass.cast(TYPE_BEANS.get(objclass));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据名称和类型获取对应的Bean实例
|
|
||||||
*
|
|
||||||
* @param name Bean的名称
|
|
||||||
* @param objclass Bean的类型
|
|
||||||
* @param <T> Bean的泛型类型
|
|
||||||
* @return 对应名称和类型的Bean实例,未找到则返回null
|
|
||||||
*/
|
|
||||||
public static <T> T get(String name, Class<T> objclass) {
|
|
||||||
return objclass.cast(BEANS.get(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据名称获取对应的Bean实例
|
|
||||||
*
|
|
||||||
* @param name Bean的名称
|
|
||||||
* @return 对应名称的Bean实例,未找到则返回null
|
|
||||||
*/
|
|
||||||
public static Object get(String name) {
|
|
||||||
return BEANS.get(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,37 +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 ComponentBean.java
|
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.bean.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author MingLiPro
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
public @interface ComponentBean {
|
|
||||||
String value() default "";
|
|
||||||
}
|
|
||||||
@ -1,97 +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 SpringBeanUtil.java
|
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.bean.springboot;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring Bean工具类
|
|
||||||
* 实现ApplicationContextAware接口,并加入Component注解,让spring扫描到该bean
|
|
||||||
* 该类用于在普通Java类中注入bean,普通Java类中用@Autowired是无法注入bean的
|
|
||||||
* <p>
|
|
||||||
* 需要放入扫描类中
|
|
||||||
*
|
|
||||||
* @author MingLiPro
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class SpringBeanUtil implements ApplicationContextAware {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取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 clazz bean的Class类型
|
|
||||||
* @param <T> 泛型类型
|
|
||||||
* @return 指定类型的bean实例
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(Class<T> clazz) {
|
|
||||||
return getApplicationContext().getBean(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过bean名称和类型获取指定的Bean实例
|
|
||||||
*
|
|
||||||
* @param name bean名称
|
|
||||||
* @param clazz bean的Class类型
|
|
||||||
* @param <T> 泛型类型
|
|
||||||
* @return 指定名称和类型的bean实例
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(String name, Class<T> 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 {
|
|
||||||
SpringBeanUtil.applicationContext = applicationContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字节数组转换为十六进制字符串列表
|
|
||||||
* <p>
|
|
||||||
* 每个字节都会被转换为两位的十六进制字符串表示形式
|
|
||||||
* 例如: 字节值为10的字节会被转换为"0a",值为255的字节会被转换为"ff"
|
|
||||||
*
|
|
||||||
* @param bytes 输入的字节数组
|
|
||||||
* @return 包含每个字节对应十六进制字符串的列表
|
|
||||||
*/
|
|
||||||
public static List<String> getByteArrayString(byte[] bytes) {
|
|
||||||
List<Byte> 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,80 +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 CloneUtil.java
|
|
||||||
* LastUpdate 2025-09-09 09:32:17
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.clone;
|
|
||||||
|
|
||||||
import com.mingliqiye.utils.json.JsonApi;
|
|
||||||
import com.mingliqiye.utils.json.JsonException;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class CloneUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对指定的可序列化对象进行深拷贝
|
|
||||||
*
|
|
||||||
* @param object 需要进行深拷贝的对象,必须实现Serializable接口
|
|
||||||
* @param <T> 对象的类型,必须实现Serializable接口
|
|
||||||
* @return 深拷贝后的新对象,与原对象内容相同但内存地址不同
|
|
||||||
* @throws RuntimeException 当序列化或反序列化过程中发生IO异常或类未找到异常时抛出
|
|
||||||
*/
|
|
||||||
public static <T extends Serializable> T deepClone(T object) {
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(bao);
|
|
||||||
oos.writeObject(object);
|
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(
|
|
||||||
bao.toByteArray()
|
|
||||||
);
|
|
||||||
ObjectInputStream ois = new ObjectInputStream(bis);
|
|
||||||
return (T) ois.readObject();
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 深度克隆对象,使用JSON序列化和反序列化实现
|
|
||||||
*
|
|
||||||
* @param <T> 对象类型参数
|
|
||||||
* @param object 需要克隆的对象实例
|
|
||||||
* @param jsonApi JSON序列化接口实现
|
|
||||||
* @return 克隆后的对象实例
|
|
||||||
*/
|
|
||||||
public static <T> T deepJsonClone(T object, JsonApi jsonApi) {
|
|
||||||
if (object == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonApi == null) {
|
|
||||||
throw new IllegalArgumentException("jsonApi cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return (T) jsonApi.convert(object, object.getClass());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new JsonException(
|
|
||||||
"Failed to deep clone object using JSON",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,22 +16,20 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile Lists.java
|
* CurrentFile Lists.java
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
* LastUpdate 2025-09-13 00:26:11
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.collection;
|
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 com.mingliqiye.utils.random.RandomInt;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists工具类提供了一系列创建List实现的便捷方法。
|
* Lists工具类提供了一系列创建List实现的便捷方法。
|
||||||
@ -457,6 +455,12 @@ public class Lists {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> toList(Iterator<T> iterator) {
|
||||||
|
List<T> list = newArrayList(10);
|
||||||
|
ForEach.forEach(iterator, item -> list.add(item));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T getFirst(Collection<T> collectors) {
|
public <T> T getFirst(Collection<T> collectors) {
|
||||||
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
|
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,13 +16,16 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile Range.java
|
* CurrentFile Range.java
|
||||||
* LastUpdate 2025-09-12 17:12:29
|
* LastUpdate 2025-09-14 20:23:26
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.iterator;
|
package com.mingliqiye.utils.iterator;
|
||||||
|
|
||||||
|
import kotlin.ranges.ClosedRange;
|
||||||
|
import kotlin.ranges.OpenEndRange;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -35,7 +38,8 @@ import java.util.Iterator;
|
|||||||
* @since 3.2.6
|
* @since 3.2.6
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class Range implements Iterable<Integer> {
|
public class Range
|
||||||
|
implements Iterable<Integer>, ClosedRange<Integer>, OpenEndRange<Integer> {
|
||||||
|
|
||||||
private final int start;
|
private final int start;
|
||||||
private final int end;
|
private final int end;
|
||||||
@ -183,4 +187,35 @@ public class Range implements Iterable<Integer> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return current < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Integer getEndInclusive() {
|
||||||
|
val va = end - step;
|
||||||
|
return Math.max(va, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull Integer integer) {
|
||||||
|
if (step == 0) return false;
|
||||||
|
if (step > 0) {
|
||||||
|
if (integer < start || integer > end) return false;
|
||||||
|
} else {
|
||||||
|
if (integer > start || integer < end) return false;
|
||||||
|
}
|
||||||
|
return (integer - start) % step == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Integer getEndExclusive() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public @NotNull Integer getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<String> getFieldOrder() {
|
|
||||||
List<String> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
@ -16,22 +16,26 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile AutoConfiguration.java
|
* CurrentFile AutoConfiguration.java
|
||||||
* LastUpdate 2025-09-09 08:37:34
|
* LastUpdate 2025-09-13 01:23:09
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.springboot.autoconfigure;
|
package com.mingliqiye.utils.springboot.autoconfigure;
|
||||||
|
|
||||||
import com.mingliqiye.utils.collection.ForEach;
|
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.DateTime;
|
||||||
import com.mingliqiye.utils.time.Formatter;
|
import com.mingliqiye.utils.time.Formatter;
|
||||||
import java.io.IOException;
|
import lombok.val;
|
||||||
import java.io.InputStream;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
@org.springframework.boot.autoconfigure.AutoConfiguration
|
@org.springframework.boot.autoconfigure.AutoConfiguration
|
||||||
@EnableConfigurationProperties(AutoConfiguration.class)
|
@EnableConfigurationProperties(AutoConfiguration.class)
|
||||||
@ComponentScan(
|
@ComponentScan(
|
||||||
@ -80,7 +84,10 @@ public class AutoConfiguration {
|
|||||||
while ((readlen = inputStream.read(buffer)) != -1) {
|
while ((readlen = inputStream.read(buffer)) != -1) {
|
||||||
metaData.append(new String(buffer, 0, readlen));
|
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);
|
String[] d = s.trim().split("=", 2);
|
||||||
if (d.length >= 2) {
|
if (d.length >= 2) {
|
||||||
String content = "| " + d[0] + ": " + d[1];
|
String content = "| " + d[0] + ": " + d[1];
|
||||||
@ -100,9 +107,8 @@ public class AutoConfiguration {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
banner2 = bannerBuilder.toString();
|
banner2 = bannerBuilder.toString();
|
||||||
System.out.printf(
|
System.out.print(
|
||||||
banner2,
|
banner2
|
||||||
DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7)
|
|
||||||
);
|
);
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"---------------------------------------------------------"
|
"---------------------------------------------------------"
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile SuperStream.java
|
* CurrentFile SuperStream.java
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
* LastUpdate 2025-09-14 20:16:59
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -25,12 +25,13 @@ package com.mingliqiye.utils.stream;
|
|||||||
import com.mingliqiye.utils.collection.Lists;
|
import com.mingliqiye.utils.collection.Lists;
|
||||||
import com.mingliqiye.utils.collection.Maps;
|
import com.mingliqiye.utils.collection.Maps;
|
||||||
import com.mingliqiye.utils.stream.interfaces.Getable;
|
import com.mingliqiye.utils.stream.interfaces.Getable;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.stream.*;
|
import java.util.stream.*;
|
||||||
import lombok.val;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义的 SuperStream 实现类,用于对集合进行流式操作。
|
* 自定义的 SuperStream 实现类,用于对集合进行流式操作。
|
||||||
|
|||||||
@ -1,271 +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 StringUtil.java
|
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.string;
|
|
||||||
|
|
||||||
import com.mingliqiye.utils.collection.Lists;
|
|
||||||
import com.mingliqiye.utils.functions.P1RFunction;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化字符串,将格式字符串中的占位符{}替换为对应的参数值<br>
|
|
||||||
* 示例:输出 {} StringUtil.format("{},{},{}", "666", "{}", "777") - "666,{},777"<br>
|
|
||||||
* 示例 StringUtil.format("{},{},{},{}", "666", "{}", "777") - "666,{},777,"<br>
|
|
||||||
* 没有实际{} 会替换为 "" 空字符串
|
|
||||||
*
|
|
||||||
* @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();
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
// 构造实际参数数组
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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<String> split(String str, String separator) {
|
|
||||||
List<String> data = new ArrayList<>(
|
|
||||||
Arrays.asList(str.split(separator))
|
|
||||||
);
|
|
||||||
// 移除列表开头的所有空字符串元素
|
|
||||||
while (!data.isEmpty() && data.get(0).isEmpty()) {
|
|
||||||
data.remove(0);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将列表中的元素按照指定分隔符连接成字符串
|
|
||||||
*
|
|
||||||
* @param <P> 列表元素的类型
|
|
||||||
* @param separator 分隔符,用于连接各个元素
|
|
||||||
* @param list 待连接的元素列表
|
|
||||||
* @param fun 转换函数,用于将列表元素转换为字符串,如果为null则使用toString()方法
|
|
||||||
* @return 连接后的字符串,如果列表为空或null则返回空字符串
|
|
||||||
*/
|
|
||||||
public static <P> String join(
|
|
||||||
String separator,
|
|
||||||
List<P> list,
|
|
||||||
P1RFunction<P, String> 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);
|
|
||||||
|
|
||||||
// 第一个元素直接添加,其他元素先添加分隔符再添加元素
|
|
||||||
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<String> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串转换为Unicode编码格式
|
|
||||||
*
|
|
||||||
* @param str 待转换的字符串
|
|
||||||
* @return 转换后的Unicode编码字符串,每个字符都以\\u开头的十六进制形式表示
|
|
||||||
*/
|
|
||||||
public static String stringToUnicode(String str) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
char[] c = str.toCharArray();
|
|
||||||
for (char value : c) {
|
|
||||||
sb.append(stringToUnicode(value));
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符转换为Unicode转义字符串
|
|
||||||
*
|
|
||||||
* @param c 需要转换的字符
|
|
||||||
* @return 返回格式为"\\uXXXX"的Unicode转义字符串,其中XXXX为字符的十六进制Unicode码点
|
|
||||||
*/
|
|
||||||
public static String stringToUnicode(char c) {
|
|
||||||
return "\\u" + String.format("%04x", (int) c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将整数转换为Unicode字符串表示形式
|
|
||||||
*
|
|
||||||
* @param c 要转换的整数,表示Unicode码点
|
|
||||||
* @return 返回格式为"\\uXXXX"的Unicode字符串,其中XXXX是参数c的十六进制表示
|
|
||||||
*/
|
|
||||||
public static String stringToUnicode(Integer c) {
|
|
||||||
return "\\u" + Integer.toHexString(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Unicode编码字符串转换为普通字符串
|
|
||||||
* 该函数接收一个包含Unicode转义序列的字符串,将其解析并转换为对应的字符序列
|
|
||||||
*
|
|
||||||
* @param unicode 包含Unicode转义序列的字符串,格式如"\\uXXXX",其中XXXX为十六进制数
|
|
||||||
* @return 转换后的普通字符串,包含对应的Unicode字符
|
|
||||||
*/
|
|
||||||
public static String unicodeToString(String unicode) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
// 按照Unicode转义符分割字符串,得到包含十六进制编码的数组
|
|
||||||
String[] hex = unicode.split("\\\\u");
|
|
||||||
// 从索引1开始遍历,因为分割后的第一个元素是转义符前面的内容(可能为空)
|
|
||||||
for (int i = 1; i < hex.length; i++) {
|
|
||||||
// 将十六进制字符串转换为整数,作为字符的Unicode码点
|
|
||||||
int index = Integer.parseInt(hex[i], 16);
|
|
||||||
// 将Unicode码点转换为对应字符并添加到结果中
|
|
||||||
sb.append((char) index);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,14 +16,22 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile DateTime.java
|
* CurrentFile DateTime.java
|
||||||
* LastUpdate 2025-09-09 08:37:33
|
* LastUpdate 2025-09-13 10:14:09
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.time;
|
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 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.io.Serializable;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -31,10 +39,10 @@ import java.time.ZoneId;
|
|||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.FILETIME_EPOCH_OFFSET;
|
||||||
import lombok.var;
|
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.NANOS_PER_100NS;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import static com.mingliqiye.utils.logger.Loggers.getMingLiLoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 时间类,用于处理日期时间的转换、格式化等操作。
|
* 时间类,用于处理日期时间的转换、格式化等操作。
|
||||||
@ -54,15 +62,38 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
@Setter
|
@Setter
|
||||||
public final class DateTime implements Serializable {
|
public final class DateTime implements Serializable {
|
||||||
|
|
||||||
private static final WinKernel32 WIN_KERNEL_32;
|
private static final WinKernel32Api WIN_KERNEL_32_API;
|
||||||
private static final long FILETIME_EPOCH_OFFSET = -116444736000000000L;
|
|
||||||
private static final long NANOS_PER_100NS = 100;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
if (!SystemUtil.isJdk8Plus() && SystemUtil.isWindows()) {
|
if (SystemUtil.getJavaVersionAsInteger() == 8 && SystemUtil.isWindows()) {
|
||||||
WIN_KERNEL_32 = WinKernel32.load();
|
|
||||||
|
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 {
|
} else {
|
||||||
WIN_KERNEL_32 = null;
|
WIN_KERNEL_32_API = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,26 +126,9 @@ public final class DateTime implements Serializable {
|
|||||||
* @return 返回当前时间的 DateTime 实例
|
* @return 返回当前时间的 DateTime 实例
|
||||||
*/
|
*/
|
||||||
public static DateTime now() {
|
public static DateTime now() {
|
||||||
if (WIN_KERNEL_32 != null) {
|
if (WIN_KERNEL_32_API != 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
|
|
||||||
);
|
|
||||||
return DateTime.of(
|
return DateTime.of(
|
||||||
instant.atZone(ZoneId.systemDefault()).toLocalDateTime()
|
WIN_KERNEL_32_API.getTime().atZone(ZoneId.systemDefault()).toLocalDateTime()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new DateTime();
|
return new DateTime();
|
||||||
|
|||||||
@ -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格式相互转换工具类
|
|
||||||
* <p>
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<UUID> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置非空参数到 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<UUID> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置非空参数到 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile Main.kt
|
* CurrentFile Main.kt
|
||||||
* LastUpdate 2025-09-12 17:11:48
|
* LastUpdate 2025-09-14 20:08:44
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -24,12 +24,11 @@
|
|||||||
|
|
||||||
package com.mingliqiye.utils
|
package com.mingliqiye.utils
|
||||||
|
|
||||||
import com.mingliqiye.utils.path.OsPath
|
|
||||||
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
||||||
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
AutoConfiguration.printBanner()
|
AutoConfiguration.printBanner()
|
||||||
val path = OsPath.getCwd()
|
|
||||||
println(path.toAbsolutePath())
|
0..10
|
||||||
}
|
}
|
||||||
|
|||||||
124
src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt
Normal file
124
src/main/kotlin/com/mingliqiye/utils/aes/AesUtils.kt
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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:43:04
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@file:JvmName("AesUtils")
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.aes
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.base64.decode
|
||||||
|
import com.mingliqiye.utils.base64.encode
|
||||||
|
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 encode(
|
||||||
|
"${encode(iv)}:${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(decode(sSrc))
|
||||||
|
val parts: Array<String?> = sSrcs.split(":".toRegex(), limit = 2).toTypedArray()
|
||||||
|
if (parts.size != 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val iv = decode(parts[0]!!)
|
||||||
|
val encryptedData = 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(Exception::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)
|
||||||
|
}
|
||||||
160
src/main/kotlin/com/mingliqiye/utils/base64/Base64Utils.kt
Normal file
160
src/main/kotlin/com/mingliqiye/utils/base64/Base64Utils.kt
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* 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 Base64Utils.kt
|
||||||
|
* LastUpdate 2025-09-14 18:44:22
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
@file:JvmName("Base64Utils")
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.base64
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
val BASE_64_ENCODER: Base64.Encoder = Base64.getEncoder()
|
||||||
|
val BASE_64_DECODER: Base64.Decoder = Base64.getDecoder()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组编码为Base64字符串
|
||||||
|
*
|
||||||
|
* @param bytes 需要编码的字节数组
|
||||||
|
* @return 编码后的Base64字符串
|
||||||
|
*/
|
||||||
|
fun encode(bytes: ByteArray): String {
|
||||||
|
return BASE_64_ENCODER.encodeToString(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Base64字符串解码为字节数组
|
||||||
|
*
|
||||||
|
* @param string 需要解码的Base64字符串
|
||||||
|
* @return 解码后的字节数组
|
||||||
|
*/
|
||||||
|
fun decode(string: String): ByteArray {
|
||||||
|
return BASE_64_DECODER.decode(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件内容编码为Base64字符串
|
||||||
|
*
|
||||||
|
* @param file 需要编码的文件
|
||||||
|
* @return 文件内容的Base64编码字符串
|
||||||
|
* @throws IOException 当文件读取失败时抛出
|
||||||
|
*/
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun encode(file: File): String {
|
||||||
|
return encode(file.readBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Base64字符串解码并写入文件
|
||||||
|
*
|
||||||
|
* @param file 目标文件
|
||||||
|
* @param string 需要解码的Base64字符串
|
||||||
|
* @throws IOException 当文件写入失败时抛出
|
||||||
|
*/
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun decode(file: File, string: String) {
|
||||||
|
file.writeBytes(decode(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地将文件内容编码为Base64字符串,出现异常时返回null
|
||||||
|
*
|
||||||
|
* @param file 需要编码的文件
|
||||||
|
* @return 文件内容的Base64编码字符串,失败时返回null
|
||||||
|
*/
|
||||||
|
fun encodeSafe(file: File): String? {
|
||||||
|
return try {
|
||||||
|
encode(file)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地将Base64字符串解码并写入文件,返回操作是否成功
|
||||||
|
*
|
||||||
|
* @param file 目标文件
|
||||||
|
* @param string 需要解码的Base64字符串
|
||||||
|
* @return 操作成功返回true,失败返回false
|
||||||
|
*/
|
||||||
|
fun decodeSafe(file: File, string: String): Boolean {
|
||||||
|
return try {
|
||||||
|
decode(file, string)
|
||||||
|
true
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将路径对应的文件内容编码为Base64字符串
|
||||||
|
*
|
||||||
|
* @param path 需要编码的文件路径
|
||||||
|
* @return 文件内容的Base64编码字符串
|
||||||
|
* @throws IOException 当文件读取失败时抛出
|
||||||
|
*/
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun encode(path: Path): String {
|
||||||
|
return encode(path.toFile().readBytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Base64字符串解码并写入路径指定的文件
|
||||||
|
*
|
||||||
|
* @param path 目标文件路径
|
||||||
|
* @param string 需要解码的Base64字符串
|
||||||
|
* @throws IOException 当文件写入失败时抛出
|
||||||
|
*/
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun decode(path: Path, string: String) {
|
||||||
|
path.toFile().writeBytes(decode(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地将路径对应的文件内容编码为Base64字符串,出现异常时返回null
|
||||||
|
*
|
||||||
|
* @param path 需要编码的文件路径
|
||||||
|
* @return 文件内容的Base64编码字符串,失败时返回null
|
||||||
|
*/
|
||||||
|
fun encodeSafe(path: Path): String? {
|
||||||
|
return try {
|
||||||
|
encode(path)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地将Base64字符串解码并写入路径指定的文件,返回操作是否成功
|
||||||
|
*
|
||||||
|
* @param path 目标文件路径
|
||||||
|
* @param string 需要解码的Base64字符串
|
||||||
|
* @return 操作成功返回true,失败返回false
|
||||||
|
*/
|
||||||
|
fun decodeSafe(path: Path, string: String): Boolean {
|
||||||
|
return try {
|
||||||
|
decode(path, string)
|
||||||
|
true
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
241
src/main/kotlin/com/mingliqiye/utils/bean/Factory.kt
Normal file
241
src/main/kotlin/com/mingliqiye/utils/bean/Factory.kt
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* 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 Factory.kt
|
||||||
|
* LastUpdate 2025-09-14 19:09:28
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
@file:JvmName("Factory")
|
||||||
|
|
||||||
|
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.net.URL
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储所有已注册的Bean实例,键为Bean名称,值为Bean实例
|
||||||
|
*/
|
||||||
|
private val BEANS: ConcurrentHashMap<String, Any> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储按类型查找的Bean实例,键为Bean的Class对象,值为Bean实例
|
||||||
|
*/
|
||||||
|
private val TYPE_BEANS: ConcurrentHashMap<KClass<*>, Any> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动扫描指定类所在包下的所有类并注册为Bean
|
||||||
|
*
|
||||||
|
* @param c 指定的类,用于获取其所在的包
|
||||||
|
* @throws IllegalArgumentException 如果传入的类为null或位于默认包中
|
||||||
|
*/
|
||||||
|
fun autoScan(c: Class<*>?) {
|
||||||
|
if (c == null) {
|
||||||
|
throw IllegalArgumentException("Class cannot be null")
|
||||||
|
}
|
||||||
|
val pkg = c.`package`
|
||||||
|
if (pkg == null) {
|
||||||
|
throw IllegalArgumentException("Class is in the default package")
|
||||||
|
}
|
||||||
|
scan(pkg.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描指定包路径下的所有类文件,并注册其中带有@ComponentBean注解的类为Bean
|
||||||
|
*
|
||||||
|
* @param basePackage 要扫描的基础包名
|
||||||
|
* @throws RuntimeException 如果在扫描过程中发生异常
|
||||||
|
*/
|
||||||
|
fun scan(basePackage: String) {
|
||||||
|
try {
|
||||||
|
val path = basePackage.replace('.', '/')
|
||||||
|
val classLoader = Thread.currentThread().contextClassLoader
|
||||||
|
val resources: Enumeration<URL> = classLoader.getResources(path)
|
||||||
|
while (resources.hasMoreElements()) {
|
||||||
|
val resource = resources.nextElement()
|
||||||
|
val file = File(resource.toURI())
|
||||||
|
scanDirectory(file, basePackage)
|
||||||
|
}
|
||||||
|
injectDependencies()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归扫描目录中的所有类文件,并注册符合条件的类为Bean
|
||||||
|
*
|
||||||
|
* @param directory 当前要扫描的目录
|
||||||
|
* @param packageName 当前目录对应的包名
|
||||||
|
* @throws Exception 如果在扫描或类加载过程中发生异常
|
||||||
|
*/
|
||||||
|
private fun scanDirectory(directory: File, packageName: String) {
|
||||||
|
val files = directory.listFiles() ?: return
|
||||||
|
|
||||||
|
for (file in files) {
|
||||||
|
if (file.isDirectory) {
|
||||||
|
scanDirectory(file, "$packageName.${file.name}")
|
||||||
|
} else if (file.name.endsWith(".class")) {
|
||||||
|
val className = packageName + '.' + file.name.replace(".class", "")
|
||||||
|
registerComponent(Class.forName(className))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个带有@ComponentBean注解的类为Bean实例
|
||||||
|
*
|
||||||
|
* @param clazz 要注册的类
|
||||||
|
* @throws Exception 如果在实例化类或处理注解时发生异常
|
||||||
|
*/
|
||||||
|
private fun registerComponent(clazz: Class<*>) {
|
||||||
|
if (clazz.isAnnotationPresent(ComponentBean::class.java)) {
|
||||||
|
val component = clazz.getAnnotation(ComponentBean::class.java)
|
||||||
|
val name = component.value.ifEmpty { clazz.name }
|
||||||
|
val instance = clazz.getDeclaredConstructor().newInstance()
|
||||||
|
BEANS[name] = instance
|
||||||
|
val kClass = clazz.kotlin
|
||||||
|
TYPE_BEANS[kClass] = instance
|
||||||
|
|
||||||
|
for (interfaceClass in clazz.interfaces) {
|
||||||
|
TYPE_BEANS.putIfAbsent(interfaceClass.kotlin, instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对所有已注册的Bean进行依赖注入处理
|
||||||
|
*
|
||||||
|
* @throws Exception 如果在注入过程中发生异常
|
||||||
|
*/
|
||||||
|
private fun injectDependencies() {
|
||||||
|
for (bean in BEANS.values) {
|
||||||
|
for (field in bean.javaClass.declaredFields) {
|
||||||
|
if (field.isAnnotationPresent(InjectBean::class.java)) {
|
||||||
|
val inject = field.getAnnotation(InjectBean::class.java)
|
||||||
|
val dependency = findDependency(field.type, inject.value)
|
||||||
|
if (dependency == null) {
|
||||||
|
throw IllegalStateException(
|
||||||
|
"No suitable dependency found for field " + field.name + " in class " + bean.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
field.isAccessible = true
|
||||||
|
field.set(bean, dependency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型和名称查找对应的依赖实例
|
||||||
|
*
|
||||||
|
* @param type 依赖的类型
|
||||||
|
* @param name 依赖的名称(可为空)
|
||||||
|
* @return 找到的依赖实例,未找到则返回null
|
||||||
|
*/
|
||||||
|
private fun findDependency(type: Class<*>, name: String): Any? {
|
||||||
|
if (name.isNotEmpty()) {
|
||||||
|
return BEANS[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
val dependency = TYPE_BEANS[type.kotlin]
|
||||||
|
if (dependency != null) {
|
||||||
|
return dependency
|
||||||
|
}
|
||||||
|
|
||||||
|
for (interfaceType in TYPE_BEANS.keys) {
|
||||||
|
if (type.isAssignableFrom(interfaceType.java)) {
|
||||||
|
return TYPE_BEANS[interfaceType]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个对象添加到Bean容器中,使用其类名作为键
|
||||||
|
*
|
||||||
|
* @param obj 要添加的对象
|
||||||
|
* @throws RuntimeException 如果在注入依赖时发生异常
|
||||||
|
*/
|
||||||
|
fun add(obj: Any) {
|
||||||
|
val clazz = obj.javaClass
|
||||||
|
val name = clazz.name
|
||||||
|
BEANS[name] = obj
|
||||||
|
TYPE_BEANS[clazz.kotlin] = obj
|
||||||
|
try {
|
||||||
|
injectDependencies()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个对象以指定名称添加到Bean容器中
|
||||||
|
*
|
||||||
|
* @param name Bean的名称
|
||||||
|
* @param obj 要添加的对象
|
||||||
|
* @throws RuntimeException 如果在注入依赖时发生异常
|
||||||
|
*/
|
||||||
|
fun add(name: String, obj: Any) {
|
||||||
|
BEANS[name] = obj
|
||||||
|
TYPE_BEANS[obj.javaClass.kotlin] = obj
|
||||||
|
try {
|
||||||
|
injectDependencies()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型获取对应的Bean实例
|
||||||
|
*
|
||||||
|
* @param objclass Bean的类型
|
||||||
|
* @param T Bean的泛型类型
|
||||||
|
* @return 对应类型的Bean实例,未找到则返回null
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : Any> get(objclass: KClass<T>): T? {
|
||||||
|
return TYPE_BEANS[objclass] as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据名称和类型获取对应的Bean实例
|
||||||
|
*
|
||||||
|
* @param name Bean的名称
|
||||||
|
* @param objclass Bean的类型
|
||||||
|
* @param T Bean的泛型类型
|
||||||
|
* @return 对应名称和类型的Bean实例,未找到则返回null
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : Any> get(name: String, objclass: KClass<T>): T? {
|
||||||
|
return BEANS[name] as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据名称获取对应的Bean实例
|
||||||
|
*
|
||||||
|
* @param name Bean的名称
|
||||||
|
* @return 对应名称的Bean实例,未找到则返回null
|
||||||
|
*/
|
||||||
|
fun get(name: String): Any? {
|
||||||
|
return BEANS[name]
|
||||||
|
}
|
||||||
@ -15,23 +15,29 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile InjectBean.java
|
* CurrentFile ComponentBean.kt
|
||||||
* LastUpdate 2025-09-09 08:37:34
|
* LastUpdate 2025-09-14 18:48:59
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.bean.annotation;
|
package com.mingliqiye.utils.bean.annotation
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import kotlin.annotation.AnnotationRetention.RUNTIME
|
||||||
import java.lang.annotation.Retention;
|
import kotlin.annotation.AnnotationTarget.CLASS
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import kotlin.annotation.AnnotationTarget.FIELD
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 组件bean注解
|
||||||
* @author MingLiPro
|
* @author MingLiPro
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target(CLASS)
|
||||||
public @interface InjectBean {
|
annotation class ComponentBean(val value: String = "")
|
||||||
String value() default "";
|
|
||||||
}
|
/**
|
||||||
|
* 注入bean注解
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target(FIELD)
|
||||||
|
annotation class InjectBean(val value: String = "")
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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 SpringBeanUtils.kt
|
||||||
|
* LastUpdate 2025-09-14 20:01:26
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.bean.annotation.springboot
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException
|
||||||
|
import org.springframework.context.ApplicationContext
|
||||||
|
import org.springframework.context.ApplicationContextAware
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Bean工具类,用于获取Spring容器中的Bean实例
|
||||||
|
* 实现ApplicationContextAware接口以获取Spring的应用上下文
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
class SpringBeanUtils : ApplicationContextAware {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private var applicationContext: ApplicationContext? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Bean名称获取Bean实例
|
||||||
|
*
|
||||||
|
* @param name Bean的名称
|
||||||
|
* @return 指定名称的Bean实例
|
||||||
|
* @throws BeansException 当获取Bean失败时抛出
|
||||||
|
* @throws ClassCastException 当类型转换失败时抛出
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@Throws(BeansException::class, ClassCastException::class)
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T> getBean(name: String): T {
|
||||||
|
return applicationContext!!.getBean(name) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Bean类型获取Bean实例
|
||||||
|
*
|
||||||
|
* @param clazz Bean的类型
|
||||||
|
* @return 指定类型的Bean实例
|
||||||
|
* @throws BeansException 当获取Bean失败时抛出
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@Throws(BeansException::class)
|
||||||
|
fun <T> getBean(clazz: Class<T>): T {
|
||||||
|
return applicationContext!!.getBean(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Bean名称和类型获取Bean实例
|
||||||
|
*
|
||||||
|
* @param name Bean的名称
|
||||||
|
* @param clazz Bean的类型
|
||||||
|
* @return 指定名称和类型的Bean实例
|
||||||
|
* @throws BeansException 当获取Bean失败时抛出
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@Throws(BeansException::class)
|
||||||
|
fun <T> getBean(name: String, clazz: Class<T>): T {
|
||||||
|
return applicationContext!!.getBean<T>(name, clazz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Spring的应用上下文
|
||||||
|
*
|
||||||
|
* @param applicationContext Spring的应用上下文
|
||||||
|
* @throws BeansException 当设置应用上下文失败时抛出
|
||||||
|
*/
|
||||||
|
@Throws(BeansException::class)
|
||||||
|
override fun setApplicationContext(applicationContext: ApplicationContext) {
|
||||||
|
SpringBeanUtils.applicationContext = applicationContext
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt
Normal file
49
src/main/kotlin/com/mingliqiye/utils/bytes/ByteUtils.kt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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 ByteUtils.kt
|
||||||
|
* LastUpdate 2025-09-14 19:28:38
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
@file:JvmName("ByteUtils")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组转换为十六进制字符串列表
|
||||||
|
* @return 包含每个字节对应十六进制字符串的列表
|
||||||
|
*/
|
||||||
|
fun ByteArray.getByteArrayString(): MutableList<String> {
|
||||||
|
return Lists.toList(this)!!.stream()
|
||||||
|
.map { a -> String.format("0X%02X", a!!.toInt() and 0xFF) }
|
||||||
|
.collect(SuperStream.Collectors.toList())
|
||||||
|
}
|
||||||
|
|
||||||
63
src/main/kotlin/com/mingliqiye/utils/clone/CloneUtil.kt
Normal file
63
src/main/kotlin/com/mingliqiye/utils/clone/CloneUtil.kt
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 CloneUtil.kt
|
||||||
|
* LastUpdate 2025-09-14 19:53:41
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
@file:JvmName("CloneUtils")
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.clone
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.json.JsonApi
|
||||||
|
import com.mingliqiye.utils.json.JsonException
|
||||||
|
import java.io.*
|
||||||
|
|
||||||
|
|
||||||
|
inline fun <reified T> Serializable.deepClone(): T {
|
||||||
|
return deepClone(this) as T
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> T.deepJsonClone(jsonApi: JsonApi): T {
|
||||||
|
try {
|
||||||
|
return jsonApi.convert(this, this!!.javaClass) as T
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw JsonException(
|
||||||
|
"Failed to deep clone object using JSON",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : Serializable?> deepClone(obj: T): T {
|
||||||
|
try {
|
||||||
|
val bao = ByteArrayOutputStream()
|
||||||
|
val oos = ObjectOutputStream(bao)
|
||||||
|
oos.writeObject(obj)
|
||||||
|
val bis = ByteArrayInputStream(
|
||||||
|
bao.toByteArray()
|
||||||
|
)
|
||||||
|
val ois = ObjectInputStream(bis)
|
||||||
|
return ois.readObject() as T
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt
Normal file
60
src/main/kotlin/com/mingliqiye/utils/jna/FieldStructure.kt
Normal file
@ -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<String> {
|
||||||
|
val fieldOrderList: MutableList<String> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
421
src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt
Normal file
421
src/main/kotlin/com/mingliqiye/utils/logger/Loggers.kt
Normal file
@ -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<out Any?>): 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()
|
||||||
|
|
||||||
|
|
||||||
@ -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<DateTime>() {
|
||||||
|
|
||||||
|
@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}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<UUID>() {
|
||||||
|
/**
|
||||||
|
* 设置非空参数到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<UUID>() {
|
||||||
|
/**
|
||||||
|
* 设置非空参数到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<UUID>() {
|
||||||
|
/**
|
||||||
|
* 设置非空参数到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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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>() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组转换为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))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
174
src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt
Normal file
174
src/main/kotlin/com/mingliqiye/utils/string/StringUtils.kt
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* 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 StringUtils.kt
|
||||||
|
* LastUpdate 2025-09-14 21:46:14
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
@file:JvmName("StringUtils")
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.string
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.logger.mingLiLoggerFactory
|
||||||
|
|
||||||
|
|
||||||
|
val log = mingLiLoggerFactory.getLogger("StringUtils")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断`字符串`是否为空
|
||||||
|
*
|
||||||
|
* @param str 待判断的字符串
|
||||||
|
* @return `true`: 空 `false`: 非空
|
||||||
|
*/
|
||||||
|
fun isEmpty(str: String?): Boolean {
|
||||||
|
return str?.isEmpty() != null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化字符串,将字符串中的占位符{}替换为对应的参数值
|
||||||
|
*
|
||||||
|
* `Kotlin`语言给我老老实实用`$`啊
|
||||||
|
*
|
||||||
|
* @param str 需要格式化的字符串,包含{}占位符 \\{} 代表一个{}
|
||||||
|
* @param args 要替换占位符的参数列表
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
fun format(str: String, vararg args: Any?): String {
|
||||||
|
var argIndex = 0
|
||||||
|
val result = StringBuilder()
|
||||||
|
var lastIndex = 0
|
||||||
|
|
||||||
|
// 匹配所有非转义的 {}
|
||||||
|
val pattern = Regex("(?<!\\\\)\\{}")
|
||||||
|
val matches = pattern.findAll(str)
|
||||||
|
|
||||||
|
for (match in matches) {
|
||||||
|
// 添加匹配前的文本
|
||||||
|
result.append(str, lastIndex, match.range.first)
|
||||||
|
|
||||||
|
// 替换占位符
|
||||||
|
if (argIndex < args.size) {
|
||||||
|
result.append(args[argIndex].toString())
|
||||||
|
argIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = match.range.last + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加剩余文本
|
||||||
|
if (lastIndex < str.length) {
|
||||||
|
result.append(str, lastIndex, str.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理转义的 \\{}(替换为 {})
|
||||||
|
val finalResult = result.toString().replace("\\{}", "{}")
|
||||||
|
|
||||||
|
// 检查参数数量
|
||||||
|
val placeholderCount = matches.count()
|
||||||
|
if (argIndex != args.size) {
|
||||||
|
log.warn("Placeholder count: $placeholderCount, Argument count: ${args.size}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalResult
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串转换为Unicode编码格式
|
||||||
|
*
|
||||||
|
* @param str 待转换的字符串
|
||||||
|
* @return 转换后的Unicode编码字符串,每个字符都以\\u开头的十六进制形式表示
|
||||||
|
*/
|
||||||
|
fun stringToUnicode(str: String): String {
|
||||||
|
val sb = java.lang.StringBuilder()
|
||||||
|
val c = str.toCharArray()
|
||||||
|
for (value in c) {
|
||||||
|
sb.append(stringToUnicode(value))
|
||||||
|
}
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符转换为Unicode转义字符串
|
||||||
|
*
|
||||||
|
* @param c 需要转换的字符
|
||||||
|
* @return 返回格式为"\\uXXXX"的Unicode转义字符串,其中XXXX为字符的十六进制Unicode码点
|
||||||
|
*/
|
||||||
|
fun stringToUnicode(c: Char): String {
|
||||||
|
return "\\u" + String.format("%04x", c.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将整数转换为Unicode字符串表示形式
|
||||||
|
*
|
||||||
|
* @param c 要转换的整数,表示Unicode码点
|
||||||
|
* @return 返回格式为"\\uXXXX"的Unicode字符串,其中XXXX是参数c的十六进制表示
|
||||||
|
*/
|
||||||
|
fun stringToUnicode(c: Int): String {
|
||||||
|
return "\\u" + Integer.toHexString(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Unicode编码字符串转换为普通字符串
|
||||||
|
*
|
||||||
|
* 该函数接收一个包含Unicode转义序列的字符串,将其解析并转换为对应的字符序列
|
||||||
|
*
|
||||||
|
* @param unicode 包含Unicode转义序列的字符串,格式如"\\uXXXX",其中XXXX为十六进制数
|
||||||
|
* @return 转换后的普通字符串,包含对应的Unicode字符
|
||||||
|
*/
|
||||||
|
fun unicodeToString(unicode: String): String {
|
||||||
|
val sb = java.lang.StringBuilder()
|
||||||
|
// 按照Unicode转义符分割字符串,得到包含十六进制编码的数组
|
||||||
|
val hex: Array<String?> = unicode.split("\\\\u".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
// 从索引1开始遍历,因为分割后的第一个元素是转义符前面的内容(可能为空)
|
||||||
|
for (i in 1..<hex.size) {
|
||||||
|
// 将十六进制字符串转换为整数,作为字符的Unicode码点
|
||||||
|
val index = hex[i]!!.toInt(16)
|
||||||
|
// 将Unicode码点转换为对应字符并添加到结果中
|
||||||
|
sb.append(index.toChar())
|
||||||
|
}
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定初始容量的StringBuilder实例
|
||||||
|
*
|
||||||
|
* @param i StringBuilder的初始容量
|
||||||
|
* @return 指定初始容量的StringBuilder实例
|
||||||
|
*/
|
||||||
|
fun stringBuilder(i: Int): java.lang.StringBuilder {
|
||||||
|
return StringBuilder(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据当前字符串创建一个StringBuilder实例
|
||||||
|
*
|
||||||
|
* @return 包含当前字符串内容的StringBuilder实例
|
||||||
|
*/
|
||||||
|
fun String.stringBuilder(): java.lang.StringBuilder {
|
||||||
|
return StringBuilder(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun split(str: String, separator: String): List<String> {
|
||||||
|
return str.split(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<String>.join(separator: String): String {
|
||||||
|
return this.joinToString(separator)
|
||||||
|
}
|
||||||
|
|
||||||
53
src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt
Normal file
53
src/main/kotlin/com/mingliqiye/utils/uuid/MysqlUUIDv1.kt
Normal file
@ -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
|
||||||
|
}
|
||||||
@ -16,10 +16,9 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile UUID.kt
|
* CurrentFile UUID.kt
|
||||||
* LastUpdate 2025-09-12 16:57:52
|
* LastUpdate 2025-09-14 19:55:47
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.uuid
|
package com.mingliqiye.utils.uuid
|
||||||
|
|
||||||
import com.github.f4b6a3.uuid.UuidCreator
|
import com.github.f4b6a3.uuid.UuidCreator
|
||||||
@ -84,6 +83,16 @@ class UUID : Serializable {
|
|||||||
return UUID(uuid)
|
return UUID(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从Java的UUID
|
||||||
|
* @param uuid 字符串
|
||||||
|
* @return UUID
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun of(uuid: JUUID): UUID {
|
||||||
|
return UUID(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从字节码转换到UUID
|
* 从字节码转换到UUID
|
||||||
* @param array 16字节
|
* @param array 16字节
|
||||||
@ -93,6 +102,10 @@ class UUID : Serializable {
|
|||||||
fun of(array: ByteArray): UUID {
|
fun of(array: ByteArray): UUID {
|
||||||
return UUID(array)
|
return UUID(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JUUID.toMlUUID(): UUID {
|
||||||
|
return of(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(msb: Long, lsb: Long) {
|
internal constructor(msb: Long, lsb: Long) {
|
||||||
@ -108,10 +121,11 @@ class UUID : Serializable {
|
|||||||
this.uuid = JUUID(bb.getLong(), bb.getLong())
|
this.uuid = JUUID(bb.getLong(), bb.getLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(uuid: String) {
|
constructor(uuid: String) {
|
||||||
this.uuid = JUUID.fromString(uuid)
|
this.uuid = JUUID.fromString(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取对应的字节码
|
* 获取对应的字节码
|
||||||
* @return 字节码
|
* @return 字节码
|
||||||
@ -242,3 +256,5 @@ class UUID : Serializable {
|
|||||||
return uuid.hashCode()
|
return uuid.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,4 +4,4 @@ artifactId=$ARTIFACTID
|
|||||||
version=$VERSIONS
|
version=$VERSIONS
|
||||||
buildJdkVersion=$JDKVERSIONS
|
buildJdkVersion=$JDKVERSIONS
|
||||||
author=MingLiPro
|
author=MingLiPro
|
||||||
website=mingliqiye.com
|
website=https://mingli-utils.mingliqiye.com
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user