generated from mingliqiye/lib-tem
Compare commits
No commits in common. "master" and "Auto-Releases-3.3.2-67a1256682" have entirely different histories.
master
...
Auto-Relea
1
.gitignore
vendored
1
.gitignore
vendored
@ -45,4 +45,3 @@ log
|
|||||||
node_modules
|
node_modules
|
||||||
*lock*
|
*lock*
|
||||||
.kotlin
|
.kotlin
|
||||||
secret.gpg
|
|
||||||
|
|||||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/prettierrc",
|
||||||
|
"plugins": [
|
||||||
|
"prettier-plugin-java"
|
||||||
|
],
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": true
|
||||||
|
}
|
||||||
25
NOTICE
25
NOTICE
@ -1,25 +0,0 @@
|
|||||||
mingli-utils
|
|
||||||
Copyright 2025 mingliqiye
|
|
||||||
|
|
||||||
This product includes software developed by third parties.
|
|
||||||
The original copyright notices and licenses are reproduced below.
|
|
||||||
|
|
||||||
------------------------------------------------------------
|
|
||||||
|
|
||||||
https://github.com/jeremyh/jBCrypt (org.mindrot:jbcrypt@0.4)
|
|
||||||
|
|
||||||
Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
------------------------------------------------------------
|
|
||||||
167
README.md
Normal file
167
README.md
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
# mingli-utils
|
||||||
|
|
||||||
|
一个功能丰富的Java工具类库,提供字符串处理、时间处理、文件操作、网络工具、哈希计算等常用工具方法。
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
mingli-utils 是一个 Java 工具类库,提供各种常用的工具方法,旨在简化开发流程,减少重复代码。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- JDK 版本: Java 8
|
||||||
|
- 构建工具: Gradle (Kotlin DSL)
|
||||||
|
- 依赖库:
|
||||||
|
- Lombok 1.18.38: 用于简化 Java Bean 代码
|
||||||
|
- Jackson Databind 2.19.2: 用于 JSON 序列化
|
||||||
|
- MyBatis 3.5.19: 持久层框架
|
||||||
|
- Spring Boot Starter 2.7.14: Spring Boot基础依赖
|
||||||
|
- Bouncy Castle 1.81: 加密算法库
|
||||||
|
- UUID Creator 6.1.0: UUID生成工具
|
||||||
|
- jBCrypt 0.4: BCrypt加密实现
|
||||||
|
- JetBrains Annotations 24.0.0: 注解库
|
||||||
|
|
||||||
|
## 主要功能模块
|
||||||
|
|
||||||
|
### 字符串处理 (StringUtil)
|
||||||
|
|
||||||
|
提供常用的字符串操作方法:
|
||||||
|
|
||||||
|
- `toString()`: 对象转字符串
|
||||||
|
- `format()`: 格式化字符串
|
||||||
|
- `isEmpty()`: 判断字符串是否为空
|
||||||
|
- `join()`: 连接字符串
|
||||||
|
- `split()`: 分割字符串
|
||||||
|
|
||||||
|
### 集合工具 (Lists)
|
||||||
|
|
||||||
|
提供创建各种List实现的便捷方法:
|
||||||
|
|
||||||
|
- `newArrayList()`: 创建ArrayList实例
|
||||||
|
- `newLinkedList()`: 创建LinkedList实例
|
||||||
|
- `newVector()`: 创建Vector实例
|
||||||
|
|
||||||
|
### 时间处理 (time)
|
||||||
|
|
||||||
|
提供时间相关功能:
|
||||||
|
|
||||||
|
- `DateTime`: 时间处理类,封装了LocalDateTime的操作
|
||||||
|
- `DateTimeOffset`: 时间偏移量处理
|
||||||
|
- `Formatter`: 常用时间格式枚举
|
||||||
|
- `DateTimeUnit`: 时间单位常量定义
|
||||||
|
|
||||||
|
### 文件操作 (FileUtil)
|
||||||
|
|
||||||
|
提供文件读写等操作:
|
||||||
|
|
||||||
|
- `readFileToString()`: 读取文件内容为字符串
|
||||||
|
- `writeStringToFile()`: 将字符串写入文件
|
||||||
|
- `readLines()`: 读取文件内容为字符串列表(按行分割)
|
||||||
|
- `writeLines()`: 将字符串列表写入文件(每行一个元素)
|
||||||
|
- `copyFile()`: 复制文件
|
||||||
|
- `deleteFile()`: 删除文件
|
||||||
|
- `exists()`: 检查文件是否存在
|
||||||
|
- `getFileSize()`: 获取文件大小
|
||||||
|
|
||||||
|
### 网络工具 (network)
|
||||||
|
|
||||||
|
提供网络地址处理功能:
|
||||||
|
|
||||||
|
- `NetworkEndpoint`: 网络端点(IP+端口)封装
|
||||||
|
- `NetworkAddress`: 网络地址处理(支持IPv4/IPv6)
|
||||||
|
- `NetworkPort`: 网络端口处理
|
||||||
|
|
||||||
|
### 哈希工具 (HashUtils)
|
||||||
|
|
||||||
|
提供哈希计算功能:
|
||||||
|
|
||||||
|
- `calculateFileHash()`: 计算文件哈希值
|
||||||
|
- `bcrypt()`: BCrypt加密
|
||||||
|
- `checkBcrypt()`: 验证BCrypt哈希
|
||||||
|
|
||||||
|
### 系统工具 (SystemUtil)
|
||||||
|
|
||||||
|
提供系统相关工具方法:
|
||||||
|
|
||||||
|
- `isWindows()/isMac()/isUnix()`: 操作系统类型判断
|
||||||
|
- `getJdkVersion()`: 获取JDK版本
|
||||||
|
- `getLocalIps()`: 获取本地IP地址
|
||||||
|
|
||||||
|
### UUID工具 (uuid)
|
||||||
|
|
||||||
|
提供UUID处理功能:
|
||||||
|
|
||||||
|
- `UUID`: UUID封装类,支持时间戳型UUID
|
||||||
|
|
||||||
|
### 并发工具 (concurrent)
|
||||||
|
|
||||||
|
提供线程安全的数据结构:
|
||||||
|
|
||||||
|
- `IsChanged`: 基于CAS操作的线程安全包装类
|
||||||
|
|
||||||
|
### 函数式工具 (functions)
|
||||||
|
|
||||||
|
提供函数式编程支持:
|
||||||
|
|
||||||
|
- `Debouncer`: 防抖器实现
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 字符串格式化
|
||||||
|
String message =
|
||||||
|
StringUtil.format("Hello {}, you are {} years old", "张三", 25);
|
||||||
|
|
||||||
|
// 创建列表
|
||||||
|
List<String> fruits = Lists.newArrayList("苹果", "香蕉", "橙子");
|
||||||
|
|
||||||
|
// 连接字符串
|
||||||
|
String result = StringUtil.join(", ", fruits);
|
||||||
|
|
||||||
|
// 时间处理
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
String formatted = now.format(Formatter.STANDARD_DATETIME);
|
||||||
|
|
||||||
|
// 文件操作
|
||||||
|
FileUtil.
|
||||||
|
|
||||||
|
writeStringToFile("example.txt","Hello World");
|
||||||
|
|
||||||
|
String content = FileUtil.readFileToString("example.txt");
|
||||||
|
|
||||||
|
// 网络地址处理
|
||||||
|
NetworkEndpoint endpoint = NetworkEndpoint.of("127.0.0.1", 8080);
|
||||||
|
InetSocketAddress address = endpoint.toInetSocketAddress();
|
||||||
|
|
||||||
|
// 哈希计算
|
||||||
|
String hash = HashUtils.bcrypt("password");
|
||||||
|
boolean matches = HashUtils.checkBcrypt("password", hash);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建和运行
|
||||||
|
|
||||||
|
使用以下命令构建项目:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew build
|
||||||
|
```
|
||||||
|
|
||||||
|
发布到本地Maven仓库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew publishToMavenLocal
|
||||||
|
```
|
||||||
|
|
||||||
|
## 项目配置
|
||||||
|
|
||||||
|
项目在 `gradle.properties` 中定义了以下配置:
|
||||||
|
|
||||||
|
```properties
|
||||||
|
JDKVERSIONS=1.8
|
||||||
|
GROUPSID=com.mingliqiye.utils
|
||||||
|
ARTIFACTID=mingli-utils
|
||||||
|
VERSIONS=1.0.4
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
本项目采用Apache 2.0许可证,详细信息请查看 [LICENSE](LICENSE) 文件。
|
||||||
@ -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-21 15:36:59
|
* LastUpdate 2025-09-13 10:11:22
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -26,12 +26,12 @@ import java.time.format.DateTimeFormatter
|
|||||||
plugins {
|
plugins {
|
||||||
idea
|
idea
|
||||||
java
|
java
|
||||||
signing
|
id("java-library")
|
||||||
`java-library`
|
id("maven-publish")
|
||||||
`maven-publish`
|
|
||||||
kotlin("jvm") version "2.2.20"
|
kotlin("jvm") version "2.2.20"
|
||||||
id("org.jetbrains.dokka") version "2.0.0"
|
id("org.jetbrains.dokka") version "2.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
val GROUPSID = project.properties["GROUPSID"] as String
|
val GROUPSID = project.properties["GROUPSID"] as String
|
||||||
val VERSIONS = project.properties["VERSIONS"] as String
|
val VERSIONS = project.properties["VERSIONS"] as String
|
||||||
val ARTIFACTID = project.properties["ARTIFACTID"] as String
|
val ARTIFACTID = project.properties["ARTIFACTID"] as String
|
||||||
@ -65,21 +65,23 @@ java {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
annotationProcessor("org.jetbrains:annotations:24.0.0")
|
||||||
implementation("org.slf4j:slf4j-api:2.0.17")
|
annotationProcessor("org.projectlombok:lombok:1.18.38")
|
||||||
|
|
||||||
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
|
|
||||||
// https://github.com/jeremyh/jBCrypt
|
|
||||||
implementation("org.mindrot:jbcrypt:0.4")
|
|
||||||
|
|
||||||
compileOnly("org.springframework.boot:spring-boot-starter:2.7.14")
|
compileOnly("org.springframework.boot:spring-boot-starter:2.7.14")
|
||||||
compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2")
|
compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2")
|
||||||
compileOnly("com.google.code.gson:gson:2.13.1")
|
compileOnly("com.google.code.gson:gson:2.13.1")
|
||||||
compileOnly("org.mybatis:mybatis:3.5.19")
|
compileOnly("org.mybatis:mybatis:3.5.19")
|
||||||
compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58")
|
compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58")
|
||||||
|
compileOnly("org.projectlombok:lombok:1.18.38")
|
||||||
compileOnly("com.baomidou:mybatis-plus-core:3.0.1")
|
implementation("org.bouncycastle:bcprov-jdk18on:1.81")
|
||||||
|
implementation("com.github.f4b6a3:uuid-creator:6.1.0")
|
||||||
|
implementation("org.mindrot:jbcrypt:0.4")
|
||||||
|
implementation("org.jetbrains:annotations:24.0.0")
|
||||||
compileOnly("net.java.dev.jna:jna:5.17.0")
|
compileOnly("net.java.dev.jna:jna:5.17.0")
|
||||||
|
implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
|
||||||
|
implementation("org.slf4j:slf4j-api:2.0.17")
|
||||||
|
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -94,14 +96,13 @@ tasks.withType<JavaExec>().configureEach {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.withType<org.gradle.jvm.tasks.Jar> {
|
tasks.withType<org.gradle.jvm.tasks.Jar> {
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
from("LICENSE") { into("META-INF") }
|
|
||||||
from("NOTICE") { into("META-INF") }
|
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
mapOf(
|
mapOf(
|
||||||
"Main-Class" to "com.mingliqiye.utils.main.Main",
|
"Main-Class" to "com.mingliqiye.utils.Main",
|
||||||
"Specification-Title" to ARTIFACTID,
|
"Specification-Title" to ARTIFACTID,
|
||||||
"Specification-Version" to VERSIONS,
|
"Specification-Version" to VERSIONS,
|
||||||
"Specification-Vendor" to "minglipro",
|
"Specification-Vendor" to "minglipro",
|
||||||
@ -128,20 +129,21 @@ val isJdk8Build = project.findProperty("buildForJdk8") == "true"
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://maven.aliyun.com/repository/public/")
|
url = uri("https://maven.aliyun.com/repository/public/")
|
||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Jar>("javaDocJar") {
|
tasks.register<Jar>("javaDocJar") {
|
||||||
group = "build"
|
group = "build"
|
||||||
archiveClassifier.set("javadoc")
|
archiveClassifier.set("javadoc")
|
||||||
dependsOn("dokkaJavadoc")
|
dependsOn(tasks.dokkaJavadoc)
|
||||||
from(buildDir.resolve("dokka/javadoc"))
|
from(buildDir.resolve("dokka/javadoc"))
|
||||||
}
|
}
|
||||||
tasks.register<Jar>("kotlinDocJar") {
|
tasks.register<Jar>("kotlinDocJar") {
|
||||||
group = "build"
|
group = "build"
|
||||||
archiveClassifier.set("kotlindoc")
|
archiveClassifier.set("kotlindoc")
|
||||||
dependsOn("dokkaHtml")
|
dependsOn(tasks.dokkaHtml)
|
||||||
from(buildDir.resolve("dokka/html"))
|
from(buildDir.resolve("dokka/html"))
|
||||||
}
|
}
|
||||||
publishing {
|
publishing {
|
||||||
@ -150,10 +152,6 @@ publishing {
|
|||||||
name = "MavenRepositoryRaw"
|
name = "MavenRepositoryRaw"
|
||||||
url = uri("C:/data/git/maven-repository-raw")
|
url = uri("C:/data/git/maven-repository-raw")
|
||||||
}
|
}
|
||||||
maven {
|
|
||||||
name = "OSSRepository"
|
|
||||||
url = uri("C:/data/git/maven-repository-raw-utils")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
@ -162,34 +160,8 @@ publishing {
|
|||||||
artifact(tasks.named("kotlinDocJar"))
|
artifact(tasks.named("kotlinDocJar"))
|
||||||
artifactId = ARTIFACTID
|
artifactId = ARTIFACTID
|
||||||
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
pom {
|
|
||||||
name = "mingli-utils"
|
|
||||||
url = "https://mingli-utils.mingliqiye.com"
|
|
||||||
description = "A Java/kotlin Utils"
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name = "The Apache License, Version 2.0"
|
|
||||||
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id = "minglipro"
|
|
||||||
name = "mingli"
|
|
||||||
email = "minglipro@163.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm {
|
|
||||||
connection = "scm:git:https://git.mingliqiye.com/minglipro/mingli-utils.git"
|
|
||||||
developerConnection = "scm:git:https://git.mingliqiye.com:minglipro/mingli-utils.git"
|
|
||||||
url = "https://git.mingliqiye.com/minglipro/mingli-utils"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signing {
|
|
||||||
sign(publishing.publications)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.build {
|
tasks.build {
|
||||||
@ -209,6 +181,7 @@ tasks.processResources {
|
|||||||
DateTimeFormatter.ofPattern(
|
DateTimeFormatter.ofPattern(
|
||||||
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
|
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
|
||||||
)
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -16,13 +16,10 @@
|
|||||||
# ProjectName mingli-utils
|
# ProjectName mingli-utils
|
||||||
# ModuleName mingli-utils
|
# ModuleName mingli-utils
|
||||||
# CurrentFile gradle.properties
|
# CurrentFile gradle.properties
|
||||||
# LastUpdate 2025-09-21 15:38:52
|
# LastUpdate 2025-09-14 22:10:29
|
||||||
# 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=4.1.9
|
VERSIONS=3.3.2
|
||||||
signing.keyId=B22AA93B
|
|
||||||
signing.password=
|
|
||||||
signing.secretKeyRingFile=secret.gpg
|
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -16,12 +16,12 @@
|
|||||||
# ProjectName mingli-utils
|
# ProjectName mingli-utils
|
||||||
# ModuleName mingli-utils
|
# ModuleName mingli-utils
|
||||||
# CurrentFile gradle-wrapper.properties
|
# CurrentFile gradle-wrapper.properties
|
||||||
# LastUpdate 2025-09-15 22:32:50
|
# LastUpdate 2025-09-09 08:37:34
|
||||||
# UpdateUser MingLiPro
|
# UpdateUser MingLiPro
|
||||||
#
|
#
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
distributionUrl=https\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.14-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
2
gradlew
vendored
2
gradlew
vendored
@ -18,7 +18,7 @@
|
|||||||
# ProjectName mingli-utils
|
# ProjectName mingli-utils
|
||||||
# ModuleName mingli-utils
|
# ModuleName mingli-utils
|
||||||
# CurrentFile gradlew
|
# CurrentFile gradlew
|
||||||
# LastUpdate 2025-09-15 22:32:50
|
# LastUpdate 2025-09-09 08:37:33
|
||||||
# UpdateUser MingLiPro
|
# UpdateUser MingLiPro
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|||||||
@ -16,16 +16,12 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.jdk8
|
* ModuleName mingli-utils.jdk8
|
||||||
* CurrentFile build.gradle.kts
|
* CurrentFile build.gradle.kts
|
||||||
* LastUpdate 2025-09-21 15:39:12
|
* LastUpdate 2025-09-14 18:19:04
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java-library")
|
id("java-library")
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
signing
|
|
||||||
kotlin("jvm") version "2.2.20"
|
|
||||||
id("org.jetbrains.dokka") version "2.0.0"
|
|
||||||
}
|
}
|
||||||
val GROUPSID = project.properties["GROUPSID"] as String
|
val GROUPSID = project.properties["GROUPSID"] as String
|
||||||
val VERSIONS = project.properties["VERSIONS"] as String
|
val VERSIONS = project.properties["VERSIONS"] as String
|
||||||
@ -43,44 +39,15 @@ publishing {
|
|||||||
name = "MavenRepositoryRaw"
|
name = "MavenRepositoryRaw"
|
||||||
url = uri("C:/data/git/maven-repository-raw")
|
url = uri("C:/data/git/maven-repository-raw")
|
||||||
}
|
}
|
||||||
maven {
|
|
||||||
name = "OSSRepository"
|
|
||||||
url = uri("C:/data/git/maven-repository-raw-utils")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
artifactId = "$ARTIFACTID-win-jdk8"
|
artifactId = "$ARTIFACTID-win-jdk8"
|
||||||
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
groupId = GROUPSID
|
||||||
pom {
|
version = VERSIONS
|
||||||
name = "mingli-utils-win-jdk8"
|
|
||||||
url = "https://mingli-utils.mingliqiye.com"
|
|
||||||
description = "A Java/kotlin Utils"
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name = "The Apache License, Version 2.0"
|
|
||||||
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id = "minglipro"
|
|
||||||
name = "mingli"
|
|
||||||
email = "minglipro@163.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm {
|
|
||||||
connection = "scm:git:https://git.mingliqiye.com/minglipro/mingli-utils.git"
|
|
||||||
developerConnection = "scm:git:https://git.mingliqiye.com:minglipro/mingli-utils.git"
|
|
||||||
url = "https://git.mingliqiye.com/minglipro/mingli-utils"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signing {
|
|
||||||
sign(publishing.publications)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
|
|||||||
@ -1,23 +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.jdk8
|
|
||||||
# CurrentFile gradle.properties
|
|
||||||
# LastUpdate 2025-09-16 12:14:37
|
|
||||||
# UpdateUser MingLiPro
|
|
||||||
#
|
|
||||||
|
|
||||||
signing.secretKeyRingFile=../secret.gpg
|
|
||||||
1
lombok.config
Normal file
1
lombok.config
Normal file
@ -0,0 +1 @@
|
|||||||
|
lombok.addLombokGeneratedAnnotation = false
|
||||||
14
package.json
Normal file
14
package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "maven-repository",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "gradle build-jar",
|
||||||
|
"buildw": "gradlew build-jar",
|
||||||
|
"format": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\"",
|
||||||
|
"f": "prettier --write \"**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,astro,json,java}\""
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier-plugin-java": "^2.7.1",
|
||||||
|
"prettier": "^3.6.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils
|
* ModuleName mingli-utils
|
||||||
* CurrentFile settings.gradle.kts
|
* CurrentFile settings.gradle.kts
|
||||||
* LastUpdate 2025-09-16 12:32:52
|
* LastUpdate 2025-09-13 02:37:04
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
347
src/main/java/com/mingliqiye/utils/collection/Collection.java
Normal file
347
src/main/java/com/mingliqiye/utils/collection/Collection.java
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/*
|
||||||
|
* 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 Collection.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.collection;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.stream.SuperStream;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合工具类,提供对列表和数组的常用操作方法。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class Collection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取集合的第一个元素。
|
||||||
|
*
|
||||||
|
* @param collection 集合
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 第一个元素;如果集合为空或为null则返回 null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getFirst(@Nullable java.util.Collection<T> collection) {
|
||||||
|
if (collection == null || collection.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于List类型,直接获取第一个元素
|
||||||
|
if (collection instanceof List) {
|
||||||
|
return ((List<T>) collection).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于其他Collection类型,使用迭代器获取第一个元素
|
||||||
|
return collection.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数组的第一个元素。
|
||||||
|
*
|
||||||
|
* @param list 数组,不能为空
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 第一个元素;如果数组为空则返回 null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getFirst(@NotNull T[] list) {
|
||||||
|
if (list.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return list[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取集合的最后一个元素。
|
||||||
|
*
|
||||||
|
* @param collection 集合
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 最后一个元素;如果集合为空或为null则返回 null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getLast(@Nullable java.util.Collection<T> collection) {
|
||||||
|
if (collection == null || collection.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于List类型,直接获取最后一个元素
|
||||||
|
if (collection instanceof List) {
|
||||||
|
List<T> list = (List<T>) collection;
|
||||||
|
return list.get(list.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于其他Collection类型,需要遍历到最后一个元素
|
||||||
|
T lastElement = null;
|
||||||
|
for (T element : collection) {
|
||||||
|
lastElement = element;
|
||||||
|
}
|
||||||
|
return lastElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数组的最后一个元素。
|
||||||
|
*
|
||||||
|
* @param list 数组,不能为空
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 最后一个元素;如果数组为空则返回 null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getLast(@NotNull T[] list) {
|
||||||
|
if (list.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return list[list.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取列表中指定索引的元素,如果索引超出范围则返回默认值。
|
||||||
|
*
|
||||||
|
* @param list 列表
|
||||||
|
* @param index 索引
|
||||||
|
* @param defaultValue 默认值
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 指定索引的元素或默认值
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getOrDefault(
|
||||||
|
@NotNull java.util.Collection<T> list,
|
||||||
|
int index,
|
||||||
|
@Nullable T defaultValue
|
||||||
|
) {
|
||||||
|
if (index < 0 || index >= list.size()) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return SuperStream.of(list).get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取集合中指定索引的元素。
|
||||||
|
* 如果索引超出范围则返回null。
|
||||||
|
*
|
||||||
|
* @param list 集合
|
||||||
|
* @param index 索引
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 指定索引的元素,如果索引超出范围则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T get(@NotNull java.util.Collection<T> list, int index) {
|
||||||
|
return getOrDefault(list, index, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数组中指定索引的元素,如果索引超出范围则返回默认值。
|
||||||
|
*
|
||||||
|
* @param array 数组
|
||||||
|
* @param index 索引
|
||||||
|
* @param defaultValue 默认值
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 指定索引的元素或默认值
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T getOrDefault(
|
||||||
|
@NotNull T[] array,
|
||||||
|
int index,
|
||||||
|
@Nullable T defaultValue
|
||||||
|
) {
|
||||||
|
if (index < 0 || index >= array.length) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return array[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取列表的安全子列表,自动处理边界情况。
|
||||||
|
*
|
||||||
|
* @param list 原始列表
|
||||||
|
* @param fromIndex 起始索引(包含)
|
||||||
|
* @param toIndex 结束索引(不包含)
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 子列表
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T> List<T> safeSubList(
|
||||||
|
@NotNull List<T> list,
|
||||||
|
int fromIndex,
|
||||||
|
int toIndex
|
||||||
|
) {
|
||||||
|
int size = list.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调整边界
|
||||||
|
fromIndex = Math.max(0, fromIndex);
|
||||||
|
toIndex = Math.min(size, toIndex);
|
||||||
|
if (fromIndex >= toIndex) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.subList(fromIndex, toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断列表是否为空或null。
|
||||||
|
*
|
||||||
|
* @param list 待检查的列表
|
||||||
|
* @return 如果列表为null或空则返回true,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(@Nullable List<?> list) {
|
||||||
|
return list == null || list.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断数组是否为空或null。
|
||||||
|
*
|
||||||
|
* @param array 待检查的数组
|
||||||
|
* @return 如果数组为null或空则返回true,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean isEmpty(@Nullable Object[] array) {
|
||||||
|
return array == null || array.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找列表中第一个满足条件的元素。
|
||||||
|
*
|
||||||
|
* @param list 列表
|
||||||
|
* @param predicate 条件谓词
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 第一个满足条件的元素,如果没有则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T findFirst(
|
||||||
|
@NotNull List<T> list,
|
||||||
|
@NotNull Predicate<T> predicate
|
||||||
|
) {
|
||||||
|
for (T item : list) {
|
||||||
|
if (predicate.test(item)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找数组中第一个满足条件的元素。
|
||||||
|
*
|
||||||
|
* @param array 数组
|
||||||
|
* @param predicate 条件谓词
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 第一个满足条件的元素,如果没有则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T findFirst(
|
||||||
|
@NotNull T[] array,
|
||||||
|
@NotNull Predicate<T> predicate
|
||||||
|
) {
|
||||||
|
for (T item : array) {
|
||||||
|
if (predicate.test(item)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤列表中满足条件的元素。
|
||||||
|
*
|
||||||
|
* @param list 原始列表
|
||||||
|
* @param predicate 条件谓词
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 包含满足条件元素的新列表
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T> List<T> filter(
|
||||||
|
@NotNull List<T> list,
|
||||||
|
@NotNull Predicate<T> predicate
|
||||||
|
) {
|
||||||
|
List<T> result = new ArrayList<>();
|
||||||
|
for (T item : list) {
|
||||||
|
if (predicate.test(item)) {
|
||||||
|
result.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤数组中满足条件的元素。
|
||||||
|
*
|
||||||
|
* @param array 原始数组
|
||||||
|
* @param predicate 条件谓词
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 包含满足条件元素的新列表
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T> List<T> filter(
|
||||||
|
@NotNull T[] array,
|
||||||
|
@NotNull Predicate<T> predicate
|
||||||
|
) {
|
||||||
|
return filter(Arrays.asList(array), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将列表转换为数组。
|
||||||
|
*
|
||||||
|
* @param list 列表
|
||||||
|
* @param clazz 元素类型class
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 转换后的数组
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@NotNull
|
||||||
|
public static <T> T[] toArray(
|
||||||
|
@NotNull List<T> list,
|
||||||
|
@NotNull Class<T> clazz
|
||||||
|
) {
|
||||||
|
T[] array = (T[]) java.lang.reflect.Array.newInstance(
|
||||||
|
clazz,
|
||||||
|
list.size()
|
||||||
|
);
|
||||||
|
return list.toArray(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将集合转换为列表。
|
||||||
|
*
|
||||||
|
* @param collection 集合
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 转换后的列表
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static <T> List<T> toList(
|
||||||
|
@NotNull java.util.Collection<T> collection
|
||||||
|
) {
|
||||||
|
return new ArrayList<>(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> SuperStream<T> toSuperStream(
|
||||||
|
@NotNull java.util.Collection<T> list
|
||||||
|
) {
|
||||||
|
return SuperStream.of(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
579
src/main/java/com/mingliqiye/utils/collection/ForEach.java
Normal file
579
src/main/java/com/mingliqiye/utils/collection/ForEach.java
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
/*
|
||||||
|
* 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 ForEach.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.collection;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.functions.P1Function;
|
||||||
|
import com.mingliqiye.utils.functions.P2Function;
|
||||||
|
import com.mingliqiye.utils.functions.P3Function;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集合和映射的增强遍历功能
|
||||||
|
* ListsAMaps 工具类提供对集合和映射的增强遍历功能。
|
||||||
|
* 包含多个重载的 forEach 方法,支持带索引的遍历操作。<br>
|
||||||
|
*
|
||||||
|
* 不可终止的遍历 可以使用 ForEachBreaked 类
|
||||||
|
*
|
||||||
|
* @since 3.0.4
|
||||||
|
*
|
||||||
|
* @see com.mingliqiye.utils.collection.ForEachBreaked
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class ForEach {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的可迭代对象执行指定的操作,操作包含元素值和索引。
|
||||||
|
* 根据可迭代对象类型选择最优的遍历方式以提高性能。
|
||||||
|
*
|
||||||
|
* @param iterable 要遍历的可迭代对象
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param <T> 可迭代对象中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterable<T> iterable,
|
||||||
|
P2Function<? super T, Integer> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果集合或操作为空,则直接返回
|
||||||
|
if (iterable == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果集合实现了 RandomAccess 接口(如 ArrayList),使用索引访问优化性能
|
||||||
|
if (iterable instanceof RandomAccess && iterable instanceof List) {
|
||||||
|
List<T> list = (List<T>) iterable;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
action.call(list.get(i), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是普通 List,使用迭代器遍历并手动维护索引
|
||||||
|
else if (iterable instanceof List) {
|
||||||
|
int index = 0;
|
||||||
|
Iterator<T> it = iterable.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
action.call(it.next(), index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 其他类型的集合使用增强 for 循环,并手动维护索引
|
||||||
|
else {
|
||||||
|
int index = 0;
|
||||||
|
for (T element : iterable) {
|
||||||
|
action.call(element, index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的可迭代对象执行指定的操作,仅处理元素值。
|
||||||
|
* 根据可迭代对象是否实现 RandomAccess 接口选择最优的遍历方式。
|
||||||
|
*
|
||||||
|
* @param iterable 要遍历的可迭代对象
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param <T> 可迭代对象中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterable<T> iterable,
|
||||||
|
P1Function<? super T> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果集合或操作为空,则直接返回
|
||||||
|
if (iterable == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果集合实现了 RandomAccess 接口,使用索引访问提升性能
|
||||||
|
if (iterable instanceof RandomAccess) {
|
||||||
|
List<T> list = (List<T>) iterable;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
action.call(list.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 否则使用增强 for 循环进行遍历
|
||||||
|
else {
|
||||||
|
for (T element : iterable) {
|
||||||
|
action.call(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的迭代器执行指定的操作,仅处理元素值。
|
||||||
|
* @param iterator 要遍历的迭代器
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param <T> 迭代器中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterator<T> iterator,
|
||||||
|
P2Function<? super T, Integer> action
|
||||||
|
) {
|
||||||
|
if (iterator == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
action.call(iterator.next(), index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的迭代器执行指定的操作,处理元素值和索引。
|
||||||
|
* @param iterator 要遍历的迭代器
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param <T> 迭代器中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterator<T> iterator,
|
||||||
|
P1Function<? super T> action
|
||||||
|
) {
|
||||||
|
if (iterator == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
action.call(iterator.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的映射执行指定的操作,操作包含键、值和索引。
|
||||||
|
* 根据映射类型选择不同的遍历策略。
|
||||||
|
*
|
||||||
|
* @param map 要遍历的映射
|
||||||
|
* @param action 要对每个键值对执行的操作,接收键、值和索引作为参数
|
||||||
|
* @param <K> 映射中键的类型
|
||||||
|
* @param <V> 映射中值的类型
|
||||||
|
*/
|
||||||
|
public static <K, V> void forEach(
|
||||||
|
Map<K, V> map,
|
||||||
|
P3Function<? super K, ? super V, Integer> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果映射或操作为空,则直接返回
|
||||||
|
if (map == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 TreeMap 的条目集合并传递索引
|
||||||
|
if (map instanceof TreeMap) {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 遍历 ConcurrentMap 或 LinkedHashMap 的条目集合并传递索引
|
||||||
|
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 遍历其他类型映射的条目集合并传递索引
|
||||||
|
else {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的映射执行指定的操作,仅处理键和值。
|
||||||
|
* 根据映射类型选择不同的遍历策略。
|
||||||
|
*
|
||||||
|
* @param map 要遍历的映射
|
||||||
|
* @param action 要对每个键值对执行的操作,接收键和值作为参数
|
||||||
|
* @param <K> 映射中键的类型
|
||||||
|
* @param <V> 映射中值的类型
|
||||||
|
*/
|
||||||
|
public static <K, V> void forEach(
|
||||||
|
Map<K, V> map,
|
||||||
|
P2Function<? super K, ? super V> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果映射或操作为空,则直接返回
|
||||||
|
if (map == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 TreeMap 的条目集合
|
||||||
|
if (map instanceof TreeMap) {
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
action.call(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是 ConcurrentMap 或 LinkedHashMap,使用其内置的 forEach 方法
|
||||||
|
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
|
||||||
|
forEach(map.entrySet(), i -> action.call(i.getKey(), i.getValue()));
|
||||||
|
}
|
||||||
|
// 遍历其他类型映射的条目集合
|
||||||
|
else {
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
action.call(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的可变参数数组
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
P2Function<? super T, Integer> action,
|
||||||
|
T... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.newArrayList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
T[] objects,
|
||||||
|
P2Function<? super T, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的数组
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(T[] objects, P1Function<? super T> action) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的可变参数数组
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(P1Function<? super T> action, T... objects) {
|
||||||
|
forEach(Lists.toList(objects), (t, i) -> action.call(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
int[] objects,
|
||||||
|
P2Function<Integer, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Integer, Integer> action,
|
||||||
|
int... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Integer> action, int... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的字节数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
byte[] objects,
|
||||||
|
P2Function<Byte, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的字节可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Byte, Integer> action,
|
||||||
|
byte... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的字节可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Byte> action, byte... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的短整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
short[] objects,
|
||||||
|
P2Function<Short, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的短整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Short, Integer> action,
|
||||||
|
short... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的短整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Short> action, short... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的长整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
long[] objects,
|
||||||
|
P2Function<Long, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的长整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Long, Integer> action,
|
||||||
|
long... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的长整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Long> action, long... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的浮点数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
float[] objects,
|
||||||
|
P2Function<Float, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Float, Integer> action,
|
||||||
|
float... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Float> action, float... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的双精度浮点数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
double[] objects,
|
||||||
|
P2Function<Double, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的双精度浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Double, Integer> action,
|
||||||
|
double... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的双精度浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Double> action, double... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的字符数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
char[] objects,
|
||||||
|
P2Function<Character, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的字符可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Character, Integer> action,
|
||||||
|
char... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的字符可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(P1Function<Character> action, char... objects) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的布尔数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
boolean[] objects,
|
||||||
|
P2Function<Character, Integer> action
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数
|
||||||
|
* @param objects 要遍历的布尔可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2Function<Boolean, Integer> action,
|
||||||
|
boolean... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数
|
||||||
|
* @param objects 要遍历的布尔可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1Function<Boolean> action,
|
||||||
|
boolean... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,656 @@
|
|||||||
|
/*
|
||||||
|
* 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 ForEachBreaked.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.collection;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.functions.P1RFunction;
|
||||||
|
import com.mingliqiye.utils.functions.P2RFunction;
|
||||||
|
import com.mingliqiye.utils.functions.P3RFunction;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ForEachBreaked 工具类提供对集合和映射的增强遍历功能,支持在遍历过程中中断操作。
|
||||||
|
* 包含多个重载的 forEach 方法,支持带索引的遍历操作,并且可以在满足条件时提前终止遍历。
|
||||||
|
* <br>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* return null; // 提前下一次遍历 = continue;
|
||||||
|
* <p>
|
||||||
|
* return true; // 提前终止遍历 = break;
|
||||||
|
* <p>
|
||||||
|
* return false; // 继续下一次遍历
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
* @since 3.0.4
|
||||||
|
*/
|
||||||
|
public class ForEachBreaked {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的集合执行指定的操作,操作包含元素值和索引。
|
||||||
|
* 根据集合类型选择最优的遍历方式以提高性能。
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param collection 要遍历的集合,可以是 List 或其他 Collection 实现
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 集合中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Collection<T> collection,
|
||||||
|
P2RFunction<? super T, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果集合或操作为空,则直接返回
|
||||||
|
if (collection == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果集合实现了 RandomAccess 接口(如 ArrayList),使用索引访问优化性能
|
||||||
|
if (collection instanceof RandomAccess && collection instanceof List) {
|
||||||
|
List<T> list = (List<T>) collection;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
if (action.call(list.get(i), i)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是普通 List,使用迭代器遍历并手动维护索引
|
||||||
|
else if (collection instanceof List) {
|
||||||
|
int index = 0;
|
||||||
|
Iterator<T> it = collection.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (action.call(it.next(), index)) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 其他类型的集合使用增强 for 循环,并手动维护索引
|
||||||
|
else {
|
||||||
|
int index = 0;
|
||||||
|
for (T element : collection) {
|
||||||
|
if (action.call(element, index)) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的集合执行指定的操作,仅处理元素值。
|
||||||
|
* 根据集合是否实现 RandomAccess 接口选择最优的遍历方式。
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param collection 要遍历的集合
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 集合中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Collection<T> collection,
|
||||||
|
P1RFunction<? super T, Boolean> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果集合或操作为空,则直接返回
|
||||||
|
if (collection == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果集合实现了 RandomAccess 接口,使用索引访问提升性能
|
||||||
|
if (collection instanceof RandomAccess) {
|
||||||
|
List<T> list = (List<T>) collection;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
if (action.call(list.get(i))) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 否则使用增强 for 循环进行遍历
|
||||||
|
else {
|
||||||
|
for (T element : collection) {
|
||||||
|
if (action.call(element)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的映射执行指定的操作,操作包含键、值和索引。
|
||||||
|
* 根据映射类型选择不同的遍历策略。
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param map 要遍历的映射
|
||||||
|
* @param action 要对每个键值对执行的操作,接收键、值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <K> 映射中键的类型
|
||||||
|
* @param <V> 映射中值的类型
|
||||||
|
*/
|
||||||
|
public static <K, V> void forEach(
|
||||||
|
Map<K, V> map,
|
||||||
|
P3RFunction<? super K, ? super V, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果映射或操作为空,则直接返回
|
||||||
|
if (map == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 TreeMap 的条目集合并传递索引
|
||||||
|
if (map instanceof TreeMap) {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index)
|
||||||
|
) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 遍历 ConcurrentMap 或 LinkedHashMap 的条目集合并传递索引
|
||||||
|
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index)
|
||||||
|
) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 遍历其他类型映射的条目集合并传递索引
|
||||||
|
else {
|
||||||
|
int index = 0;
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (
|
||||||
|
action.call(entry.getKey(), entry.getValue(), index)
|
||||||
|
) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对给定的映射执行指定的操作,仅处理键和值。
|
||||||
|
* 根据映射类型选择不同的遍历策略。
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param map 要遍历的映射
|
||||||
|
* @param action 要对每个键值对执行的操作,接收键和值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <K> 映射中键的类型
|
||||||
|
* @param <V> 映射中值的类型
|
||||||
|
*/
|
||||||
|
public static <K, V> void forEach(
|
||||||
|
Map<K, V> map,
|
||||||
|
P2RFunction<? super K, ? super V, Boolean> action
|
||||||
|
) {
|
||||||
|
// 参数校验:如果映射或操作为空,则直接返回
|
||||||
|
if (map == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 TreeMap 的条目集合
|
||||||
|
if (map instanceof TreeMap) {
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (action.call(entry.getKey(), entry.getValue())) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是 ConcurrentMap 或 LinkedHashMap,使用其内置的 forEach 方法
|
||||||
|
else if (map instanceof ConcurrentMap || map instanceof LinkedHashMap) {
|
||||||
|
forEach(map.entrySet(), i -> {
|
||||||
|
return action.call(i.getKey(), i.getValue());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 遍历其他类型映射的条目集合
|
||||||
|
else {
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (action.call(entry.getKey(), entry.getValue())) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的可变参数数组
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
P2RFunction<? super T, Integer, Boolean> action,
|
||||||
|
T... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.newArrayList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
T[] objects,
|
||||||
|
P2RFunction<? super T, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对迭代器执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param iterator 要遍历的迭代器
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterator<T> iterator,
|
||||||
|
P2RFunction<? super T, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
if (iterator == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (action.call(iterator.next(), index)) return;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对迭代器执行指定的操作,操作包含元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param iterator 要遍历的迭代器
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
Iterator<T> iterator,
|
||||||
|
P1RFunction<? super T, Boolean> action
|
||||||
|
) {
|
||||||
|
if (iterator == null || action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (action.call(iterator.next())) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的数组
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
T[] objects,
|
||||||
|
P1RFunction<? super T, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的可变参数数组
|
||||||
|
* @param <T> 数组中元素的类型
|
||||||
|
*/
|
||||||
|
public static <T> void forEach(
|
||||||
|
P1RFunction<? super T, Boolean> action,
|
||||||
|
T... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), (t, i) -> {
|
||||||
|
return action.call(t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
int[] objects,
|
||||||
|
P2RFunction<Integer, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Integer, Integer, Boolean> action,
|
||||||
|
int... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Integer, Boolean> action,
|
||||||
|
int... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的字节数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
byte[] objects,
|
||||||
|
P2RFunction<Byte, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的字节可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Byte, Integer, Boolean> action,
|
||||||
|
byte... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字节可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的字节可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Byte, Boolean> action,
|
||||||
|
byte... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的短整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
short[] objects,
|
||||||
|
P2RFunction<Short, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的短整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Short, Integer, Boolean> action,
|
||||||
|
short... objects
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对短整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的短整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Short, Boolean> action,
|
||||||
|
short... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的长整型数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
long[] objects,
|
||||||
|
P2RFunction<Long, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的长整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Long, Integer, Boolean> action,
|
||||||
|
long... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对长整型可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的长整型可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Long, Boolean> action,
|
||||||
|
long... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的浮点数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
float[] objects,
|
||||||
|
P2RFunction<Float, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Float, Integer, Boolean> action,
|
||||||
|
float... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对浮点可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Float, Boolean> action,
|
||||||
|
float... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的双精度浮点数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
double[] objects,
|
||||||
|
P2RFunction<Double, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的双精度浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Double, Integer, Boolean> action,
|
||||||
|
double... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对双精度浮点可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的双精度浮点可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Double, Boolean> action,
|
||||||
|
double... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的字符数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
char[] objects,
|
||||||
|
P2RFunction<Character, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(action, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的字符可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Character, Integer, Boolean> action,
|
||||||
|
char... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对字符可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的字符可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Character, Boolean> action,
|
||||||
|
char... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param objects 要遍历的布尔数组
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
*/
|
||||||
|
public static void forEach(
|
||||||
|
boolean[] objects,
|
||||||
|
P2RFunction<Character, Integer, Boolean> action
|
||||||
|
) {
|
||||||
|
forEach(objects, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔可变参数数组执行指定的操作,操作包含元素值和索引
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,接收元素值和索引作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的布尔可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P2RFunction<Boolean, Integer, Boolean> action,
|
||||||
|
boolean... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对布尔可变参数数组执行指定的操作,仅处理元素值
|
||||||
|
* 当操作返回 true 时,遍历将提前终止。
|
||||||
|
*
|
||||||
|
* @param action 要对每个元素执行的操作,只接收元素值作为参数,返回 Boolean 值决定是否继续遍历
|
||||||
|
* @param objects 要遍历的布尔可变参数数组
|
||||||
|
*/
|
||||||
|
private static void forEach(
|
||||||
|
P1RFunction<Boolean, Boolean> action,
|
||||||
|
boolean... objects
|
||||||
|
) {
|
||||||
|
forEach(Lists.toList(objects), action);
|
||||||
|
}
|
||||||
|
}
|
||||||
479
src/main/java/com/mingliqiye/utils/collection/Lists.java
Normal file
479
src/main/java/com/mingliqiye/utils/collection/Lists.java
Normal file
@ -0,0 +1,479 @@
|
|||||||
|
/*
|
||||||
|
* 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 Lists.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.collection;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.random.RandomInt;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists工具类提供了一系列创建List实现的便捷方法。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class Lists {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 新创建的空ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到列表中的元素,可以为0个或多个
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含指定元素的新ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(T... ts) {
|
||||||
|
List<T> list = newArrayList();
|
||||||
|
list.addAll(Arrays.asList(ts));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有列表创建一个新的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param list 要复制的列表
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含原列表所有元素的新ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(List<T> list) {
|
||||||
|
List<T> newList = newArrayList();
|
||||||
|
newList.addAll(list);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可迭代对象创建一个ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param iterable 可迭代对象
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含可迭代对象中所有元素的新ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(Iterable<T> iterable) {
|
||||||
|
List<T> list = newArrayList();
|
||||||
|
for (T t : iterable) {
|
||||||
|
list.add(t);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定初始容量的空ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param size 初始容量大小
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 指定初始容量的空ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(int size) {
|
||||||
|
return new ArrayList<>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定大小并用单个元素填充的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param size 列表大小
|
||||||
|
* @param t 用于填充列表的元素
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 指定大小且所有元素都相同的ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(int size, T t) {
|
||||||
|
List<T> list = newArrayList(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
list.add(t);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定大小并交替使用两个元素填充的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param size 列表大小
|
||||||
|
* @param t 第一个填充元素(索引为偶数时使用)
|
||||||
|
* @param t1 第二个填充元素(索引为奇数时使用)
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 指定大小且交替填充两个元素的ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(int size, T t, T t1) {
|
||||||
|
List<T> list = newArrayList(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
list.add(i % 2 == 0 ? t : t1);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定大小并循环使用三个元素填充的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param size 列表大小
|
||||||
|
* @param t 第一个填充元素(索引模3等于0时使用)
|
||||||
|
* @param t1 第二个填充元素(索引模3等于1时使用)
|
||||||
|
* @param t2 第三个填充元素(索引模3等于2时使用)
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 指定大小且循环填充三个元素的ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(int size, T t, T t1, T t2) {
|
||||||
|
List<T> list = newArrayList(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
list.add(i % 3 == 0 ? t : i % 3 == 1 ? t1 : t2);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定大小并循环使用四个元素填充的ArrayList实例。
|
||||||
|
*
|
||||||
|
* @param size 列表大小
|
||||||
|
* @param t 第一个填充元素(索引模4等于0时使用)
|
||||||
|
* @param t1 第二个填充元素(索引模4等于1时使用)
|
||||||
|
* @param t2 第三个填充元素(索引模4等于2时使用)
|
||||||
|
* @param t3 第四个填充元素(索引模4等于3时使用)
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 指定大小且循环填充四个元素的ArrayList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newArrayList(int size, T t, T t1, T t2, T t3) {
|
||||||
|
List<T> list = newArrayList(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
list.add(i % 4 == 0 ? t : i % 4 == 1 ? t1 : i % 4 == 2 ? t2 : t3);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的LinkedList实例。
|
||||||
|
*
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 新创建的空LinkedList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newLinkedList() {
|
||||||
|
return new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的LinkedList实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到列表中的元素,可以为0个或多个
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含指定元素的新LinkedList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newLinkedList(T... ts) {
|
||||||
|
List<T> list = newLinkedList();
|
||||||
|
list.addAll(Arrays.asList(ts));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有列表创建一个新的LinkedList实例。
|
||||||
|
*
|
||||||
|
* @param list 要复制的列表
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含原列表所有元素的新LinkedList实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newLinkedList(List<T> list) {
|
||||||
|
List<T> newList = newLinkedList();
|
||||||
|
newList.addAll(list);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的Vector实例。
|
||||||
|
*
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 新创建的空Vector实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newVector() {
|
||||||
|
return new Vector<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的Vector实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到列表中的元素,可以为0个或多个
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含指定元素的新Vector实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newVector(T... ts) {
|
||||||
|
List<T> list = newVector();
|
||||||
|
list.addAll(Arrays.asList(ts));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有列表创建一个新的Vector实例。
|
||||||
|
*
|
||||||
|
* @param list 要复制的列表
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含原列表所有元素的新Vector实例
|
||||||
|
*/
|
||||||
|
public static <T> List<T> newVector(List<T> list) {
|
||||||
|
List<T> newList = newVector();
|
||||||
|
newList.addAll(list);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定列表中的每个元素转换为字符串表示形式
|
||||||
|
*
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @param list 要转换的列表,不能为空
|
||||||
|
* @return 包含原列表各元素字符串表示的新列表,保持相同的顺序
|
||||||
|
*/
|
||||||
|
public static <T> List<String> toStringList(@NotNull List<T> list) {
|
||||||
|
// 创建与原列表相同大小的新列表,用于存储字符串转换结果
|
||||||
|
List<String> newList = newArrayList(list.size());
|
||||||
|
for (T t : list) {
|
||||||
|
newList.add(t == null ? "null" : t.toString());
|
||||||
|
}
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定数组中的每个元素转换为字符串表示形式
|
||||||
|
*
|
||||||
|
* @param <T> 数组元素的类型
|
||||||
|
* @param list 要转换的数组,不能为空
|
||||||
|
* @return 包含原数组各元素字符串表示的新字符串数组
|
||||||
|
*/
|
||||||
|
public static <T> String[] toStringList(@NotNull T[] list) {
|
||||||
|
// 创建新的字符串列表,用于存储转换后的结果
|
||||||
|
List<String> newList = newArrayList(list.length);
|
||||||
|
for (T t : list) {
|
||||||
|
newList.add(t == null ? "null" : t.toString());
|
||||||
|
}
|
||||||
|
return newList.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将列表转换为数组
|
||||||
|
*
|
||||||
|
* @param ts 要转换的列表
|
||||||
|
* @param <T> 数组元素的类型
|
||||||
|
* @return 包含列表中所有元素的数组,如果列表为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static <T> T[] toArray(List<T> ts) {
|
||||||
|
if (ts == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
T[] items = (T[]) new Object[ts.size()];
|
||||||
|
ForEach.forEach(ts, (t, i) -> items[i] = t);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数组转换为列表
|
||||||
|
*
|
||||||
|
* @param ts 要转换的数组
|
||||||
|
* @param <T> 列表元素的类型
|
||||||
|
* @return 包含数组中所有元素的列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
// 原始的方法 - 用于引用类型
|
||||||
|
@Nullable
|
||||||
|
public static <T> List<T> toList(T[] ts) {
|
||||||
|
return ts == null ? null : new ArrayList<>(Arrays.asList(ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static <T> List<T> toList(Stream<T> ts) {
|
||||||
|
return ts == null
|
||||||
|
? newArrayList()
|
||||||
|
: new ArrayList<>(ts.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将int数组转换为Integer列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的int数组
|
||||||
|
* @return 包含数组中所有元素的Integer列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Integer> toList(int[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Integer> list = new ArrayList<>(array.length);
|
||||||
|
for (int value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将long数组转换为Long列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的long数组
|
||||||
|
* @return 包含数组中所有元素的Long列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Long> toList(long[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Long> list = new ArrayList<>(array.length);
|
||||||
|
for (long value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将double数组转换为Double列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的double数组
|
||||||
|
* @return 包含数组中所有元素的Double列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Double> toList(double[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Double> list = new ArrayList<>(array.length);
|
||||||
|
for (double value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将float数组转换为Float列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的float数组
|
||||||
|
* @return 包含数组中所有元素的Float列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Float> toList(float[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Float> list = new ArrayList<>(array.length);
|
||||||
|
for (float value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将boolean数组转换为Boolean列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的boolean数组
|
||||||
|
* @return 包含数组中所有元素的Boolean列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Boolean> toList(boolean[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Boolean> list = new ArrayList<>(array.length);
|
||||||
|
for (boolean value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将char数组转换为Character列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的char数组
|
||||||
|
* @return 包含数组中所有元素的Character列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Character> toList(char[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Character> list = new ArrayList<>(array.length);
|
||||||
|
for (char value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将byte数组转换为Byte列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的byte数组
|
||||||
|
* @return 包含数组中所有元素的Byte列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Byte> toList(byte[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Byte> list = new ArrayList<>(array.length);
|
||||||
|
for (byte value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将short数组转换为Short列表
|
||||||
|
*
|
||||||
|
* @param array 要转换的short数组
|
||||||
|
* @return 包含数组中所有元素的Short列表,如果数组为null则返回null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<Short> toList(short[] array) {
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Short> list = new ArrayList<>(array.length);
|
||||||
|
for (short value : array) {
|
||||||
|
list.add(value);
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getLast(Collection<T> collectors) {
|
||||||
|
return com.mingliqiye.utils.collection.Collection.getFirst(collectors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getAny(Collection<T> collectors) {
|
||||||
|
return com.mingliqiye.utils.collection.Collection.getOrDefault(
|
||||||
|
collectors,
|
||||||
|
RandomInt.randomInt(0, collectors.size()),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
15985
src/main/java/com/mingliqiye/utils/collection/Maps.java
Normal file
15985
src/main/java/com/mingliqiye/utils/collection/Maps.java
Normal file
File diff suppressed because it is too large
Load Diff
167
src/main/java/com/mingliqiye/utils/collection/Sets.java
Normal file
167
src/main/java/com/mingliqiye/utils/collection/Sets.java
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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 Sets.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.collection;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets工具类提供了一系列创建Set实现的便捷方法。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class Sets {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的HashSet实例。
|
||||||
|
*
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 新创建的空HashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newHashSet() {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的HashSet实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到集合中的元素,可以为0个或多个
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 包含指定元素的新HashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newHashSet(T... ts) {
|
||||||
|
Set<T> set = newHashSet();
|
||||||
|
set.addAll(Arrays.asList(ts));
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有集合创建一个新的HashSet实例。
|
||||||
|
*
|
||||||
|
* @param set 要复制的集合
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 包含原集合所有元素的新HashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newHashSet(Set<T> set) {
|
||||||
|
Set<T> newSet = newHashSet();
|
||||||
|
newSet.addAll(set);
|
||||||
|
return newSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可迭代对象创建一个HashSet实例。
|
||||||
|
*
|
||||||
|
* @param iterable 可迭代对象
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 包含可迭代对象中所有元素的新HashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newHashSet(Iterable<T> iterable) {
|
||||||
|
Set<T> set = newHashSet();
|
||||||
|
for (T t : iterable) {
|
||||||
|
set.add(t);
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个指定初始容量的空HashSet实例。
|
||||||
|
*
|
||||||
|
* @param size 初始容量大小
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 指定初始容量的空HashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newHashSet(int size) {
|
||||||
|
return new HashSet<>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的LinkedHashSet实例。
|
||||||
|
*
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 新创建的空LinkedHashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newLinkedHashSet() {
|
||||||
|
return new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的LinkedHashSet实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到集合中的元素,可以为0个或多个
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 包含指定元素的新LinkedHashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newLinkedHashSet(T... ts) {
|
||||||
|
Set<T> set = newLinkedHashSet();
|
||||||
|
set.addAll(Arrays.asList(ts));
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有集合创建一个新的LinkedHashSet实例。
|
||||||
|
*
|
||||||
|
* @param set 要复制的集合
|
||||||
|
* @param <T> 集合元素的类型
|
||||||
|
* @return 包含原集合所有元素的新LinkedHashSet实例
|
||||||
|
*/
|
||||||
|
public static <T> Set<T> newLinkedHashSet(Set<T> set) {
|
||||||
|
Set<T> newSet = newLinkedHashSet();
|
||||||
|
newSet.addAll(set);
|
||||||
|
return newSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个空的TreeSet实例。
|
||||||
|
*
|
||||||
|
* @param <T> 集合元素的类型,必须实现Comparable接口
|
||||||
|
* @return 新创建的空TreeSet实例
|
||||||
|
*/
|
||||||
|
public static <T extends Comparable<T>> Set<T> newTreeSet() {
|
||||||
|
return new TreeSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据可变参数创建一个包含指定元素的TreeSet实例。
|
||||||
|
*
|
||||||
|
* @param ts 要添加到集合中的元素,可以为0个或多个
|
||||||
|
* @param <T> 集合元素的类型,必须实现Comparable接口
|
||||||
|
* @return 包含指定元素的新TreeSet实例
|
||||||
|
*/
|
||||||
|
public static <T extends Comparable<T>> Set<T> newTreeSet(T... ts) {
|
||||||
|
Set<T> set = newTreeSet();
|
||||||
|
set.addAll(Arrays.asList(ts));
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据已有集合创建一个新的TreeSet实例。
|
||||||
|
*
|
||||||
|
* @param set 要复制的集合
|
||||||
|
* @param <T> 集合元素的类型,必须实现Comparable接口
|
||||||
|
* @return 包含原集合所有元素的新TreeSet实例
|
||||||
|
*/
|
||||||
|
public static <T extends Comparable<T>> Set<T> newTreeSet(Set<T> set) {
|
||||||
|
Set<T> newSet = newTreeSet();
|
||||||
|
newSet.addAll(set);
|
||||||
|
return newSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
106
src/main/java/com/mingliqiye/utils/concurrent/IsChanged.java
Normal file
106
src/main/java/com/mingliqiye/utils/concurrent/IsChanged.java
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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 IsChanged.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.concurrent;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IsChanged 类提供了一个线程安全的包装器,用于检测值是否发生变化。
|
||||||
|
* 它基于 AtomicReference 实现,适用于需要监控数据变更的并发场景。
|
||||||
|
*
|
||||||
|
* @param <T> 泛型类型,表示被包装的数据类型
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class IsChanged<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 AtomicReference 来保证对数据的原子操作
|
||||||
|
*/
|
||||||
|
private final AtomicReference<T> atomicReferenceData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认构造函数,初始化数据为 null
|
||||||
|
*/
|
||||||
|
public IsChanged() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带参数的构造函数,使用指定的初始值初始化
|
||||||
|
*
|
||||||
|
* @param data 初始数据值
|
||||||
|
*/
|
||||||
|
public IsChanged(T data) {
|
||||||
|
atomicReferenceData = new AtomicReference<>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置新的数据值,不检查是否发生变化
|
||||||
|
*
|
||||||
|
* @param data 要设置的新数据值
|
||||||
|
*/
|
||||||
|
public void set(T data) {
|
||||||
|
atomicReferenceData.set(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前数据值
|
||||||
|
*
|
||||||
|
* @return 当前数据值
|
||||||
|
*/
|
||||||
|
public T get() {
|
||||||
|
return atomicReferenceData.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置新的数据值并返回旧的数据值
|
||||||
|
*
|
||||||
|
* @param data 要设置的新数据值
|
||||||
|
* @return 设置前的旧数据值
|
||||||
|
*/
|
||||||
|
public T setAndGet(T data) {
|
||||||
|
return atomicReferenceData.getAndSet(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置新的数据值,如果新值与当前值不同则更新并返回 true,否则返回 false
|
||||||
|
* 使用 CAS(Compare-And-Swap) 操作确保线程安全
|
||||||
|
*
|
||||||
|
* @param data 要设置的新数据值
|
||||||
|
* @return 如果值发生变化返回 true,否则返回 false
|
||||||
|
*/
|
||||||
|
public boolean setAndChanged(T data) {
|
||||||
|
T currentData;
|
||||||
|
do {
|
||||||
|
currentData = get();
|
||||||
|
// 如果新值与当前值相等,则认为没有变化,直接返回 false
|
||||||
|
if (Objects.equals(data, currentData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 使用 CAS 操作尝试更新值,如果失败则重试
|
||||||
|
} while (!atomicReferenceData.compareAndSet(currentData, data));
|
||||||
|
// 成功更新值,返回 true 表示发生了变化
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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 ThreadLocalDataHolder.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 泛型线程局部变量持有器
|
||||||
|
* <p>
|
||||||
|
* 封装了 ThreadLocal 的常用操作,提供更便捷的 API 来管理线程本地变量。
|
||||||
|
*
|
||||||
|
* @param <T> 存储的数据类型
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class ThreadLocalDataHolder<T> {
|
||||||
|
|
||||||
|
private final ThreadLocal<T> threadLocal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,初始化 ThreadLocal 实例
|
||||||
|
*/
|
||||||
|
public ThreadLocalDataHolder() {
|
||||||
|
this.threadLocal = new ThreadLocal<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前线程存储的值
|
||||||
|
*
|
||||||
|
* @return 当前线程存储的值,如果没有则返回null
|
||||||
|
*/
|
||||||
|
public T get() {
|
||||||
|
return threadLocal.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前线程的值
|
||||||
|
*
|
||||||
|
* @param value 要存储的值
|
||||||
|
*/
|
||||||
|
public void set(T value) {
|
||||||
|
threadLocal.set(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除当前线程存储的值
|
||||||
|
* <p>
|
||||||
|
* 防止内存泄漏,使用完毕后应调用此方法清理资源。
|
||||||
|
*/
|
||||||
|
public void remove() {
|
||||||
|
threadLocal.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前线程存储的值,如果不存在则返回默认值
|
||||||
|
*
|
||||||
|
* @param defaultValue 默认值
|
||||||
|
* @return 当前线程存储的值或默认值
|
||||||
|
*/
|
||||||
|
public T getOrDefault(T defaultValue) {
|
||||||
|
T value = threadLocal.get();
|
||||||
|
return value != null ? value : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全获取值(避免NPE)
|
||||||
|
* <p>
|
||||||
|
* 在某些异常情况下防止抛出异常,直接返回 null。
|
||||||
|
*
|
||||||
|
* @return 值或null
|
||||||
|
*/
|
||||||
|
public T safeGet() {
|
||||||
|
try {
|
||||||
|
return threadLocal.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查当前线程是否有值
|
||||||
|
*
|
||||||
|
* @return 是否有值
|
||||||
|
*/
|
||||||
|
public boolean isPresent() {
|
||||||
|
return threadLocal.get() != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
368
src/main/java/com/mingliqiye/utils/file/FileUtil.java
Normal file
368
src/main/java/com/mingliqiye/utils/file/FileUtil.java
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* 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 FileUtil.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.file;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.string.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件工具类,提供常用的文件操作方法
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class FileUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认字符集
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容为字符串
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 文件内容字符串
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static String readFileToString(String filePath) throws IOException {
|
||||||
|
return readFileToString(filePath, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容为字符串
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param charset 字符集
|
||||||
|
* @return 文件内容字符串
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static String readFileToString(String filePath, Charset charset)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
byte[] bytes = Files.readAllBytes(path);
|
||||||
|
return new String(bytes, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串写入文件
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param content 要写入的内容
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeStringToFile(String filePath, String content)
|
||||||
|
throws IOException {
|
||||||
|
writeStringToFile(filePath, content, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串写入文件
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param content 要写入的内容
|
||||||
|
* @param charset 字符集
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeStringToFile(
|
||||||
|
String filePath,
|
||||||
|
String content,
|
||||||
|
Charset charset
|
||||||
|
) throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
if (path.getParent() != null) {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
}
|
||||||
|
Files.write(path, content.getBytes(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容为字符串列表(按行分割)
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 文件内容按行分割的字符串列表
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static List<String> readLines(String filePath) throws IOException {
|
||||||
|
return readLines(filePath, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容为字符串列表(按行分割)
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param charset 字符集
|
||||||
|
* @return 文件内容按行分割的字符串列表
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static List<String> readLines(String filePath, Charset charset)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.readAllLines(path, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串列表写入文件(每行一个元素)
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param lines 要写入的行内容列表
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeLines(String filePath, List<String> lines)
|
||||||
|
throws IOException {
|
||||||
|
writeLines(filePath, lines, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串列表写入文件(每行一个元素)
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param lines 要写入的行内容列表
|
||||||
|
* @param charset 字符集
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeLines(
|
||||||
|
String filePath,
|
||||||
|
List<String> lines,
|
||||||
|
Charset charset
|
||||||
|
) throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.write(path, lines, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制文件
|
||||||
|
*
|
||||||
|
* @param sourcePath 源文件路径
|
||||||
|
* @param targetPath 目标文件路径
|
||||||
|
* @throws IOException 复制文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void copyFile(String sourcePath, String targetPath)
|
||||||
|
throws IOException {
|
||||||
|
Path source = Paths.get(sourcePath);
|
||||||
|
Path target = Paths.get(targetPath);
|
||||||
|
Files.createDirectories(target.getParent());
|
||||||
|
Files.copy(source, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 如果文件删除成功返回true,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean deleteFile(String filePath) {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.deleteIfExists(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文件是否存在
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 如果文件存在返回true,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean exists(String filePath) {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.exists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件大小
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 文件大小(字节),如果文件不存在返回-1
|
||||||
|
*/
|
||||||
|
public static long getFileSize(String filePath) {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.size(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建目录
|
||||||
|
*
|
||||||
|
* @param dirPath 目录路径
|
||||||
|
* @return 如果目录创建成功返回true,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean createDirectory(String dirPath) {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get(dirPath);
|
||||||
|
Files.createDirectories(path);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件扩展名
|
||||||
|
*
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 文件扩展名(不包含点号),如果无扩展名返回空字符串
|
||||||
|
*/
|
||||||
|
public static String getFileExtension(String fileName) {
|
||||||
|
if (StringUtils.isEmpty(fileName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int lastDotIndex = fileName.lastIndexOf('.');
|
||||||
|
if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return fileName.substring(lastDotIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取不带扩展名的文件名
|
||||||
|
*
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 不带扩展名的文件名
|
||||||
|
*/
|
||||||
|
public static String getFileNameWithoutExtension(String fileName) {
|
||||||
|
if (StringUtils.isEmpty(fileName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int lastDotIndex = fileName.lastIndexOf('.');
|
||||||
|
if (lastDotIndex == -1) {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
return fileName.substring(0, lastDotIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件内容为字节数组
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @return 文件内容的字节数组
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static byte[] readFileToByteArray(String filePath)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
return Files.readAllBytes(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组写入文件
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param data 要写入的字节数据
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeByteArrayToFile(String filePath, byte[] data)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.write(path, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组追加到文件末尾
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param data 要追加的字节数据
|
||||||
|
* @throws IOException 追加数据时发生错误
|
||||||
|
*/
|
||||||
|
public static void appendByteArrayToFile(String filePath, byte[] data)
|
||||||
|
throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
Files.write(
|
||||||
|
path,
|
||||||
|
data,
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.APPEND
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分块读取大文件为字节数组列表
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param chunkSize 每块大小(字节)
|
||||||
|
* @return 文件内容按指定大小分割的字节数组列表
|
||||||
|
* @throws IOException 读取文件时发生错误
|
||||||
|
*/
|
||||||
|
public static List<byte[]> readFileToByteArrayChunks(
|
||||||
|
String filePath,
|
||||||
|
int chunkSize
|
||||||
|
) throws IOException {
|
||||||
|
List<byte[]> chunks = new ArrayList<>();
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
|
||||||
|
try (InputStream inputStream = Files.newInputStream(path)) {
|
||||||
|
byte[] buffer = new byte[chunkSize];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||||
|
byte[] chunk = new byte[bytesRead];
|
||||||
|
System.arraycopy(buffer, 0, chunk, 0, bytesRead);
|
||||||
|
chunks.add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组列表写入文件
|
||||||
|
*
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param chunks 字节数组列表
|
||||||
|
* @throws IOException 写入文件时发生错误
|
||||||
|
*/
|
||||||
|
public static void writeByteArrayChunksToFile(
|
||||||
|
String filePath,
|
||||||
|
List<byte[]> chunks
|
||||||
|
) throws IOException {
|
||||||
|
Path path = Paths.get(filePath);
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
|
||||||
|
try (OutputStream outputStream = Files.newOutputStream(path)) {
|
||||||
|
for (byte[] chunk : chunks) {
|
||||||
|
outputStream.write(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/main/java/com/mingliqiye/utils/functions/Debouncer.java
Normal file
93
src/main/java/com/mingliqiye/utils/functions/Debouncer.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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 Debouncer.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防抖器类,用于实现防抖功能,防止在短时间内重复执行相同任务
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class Debouncer {
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler =
|
||||||
|
Executors.newSingleThreadScheduledExecutor();
|
||||||
|
private final ConcurrentHashMap<Object, Future<?>> delayedMap =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
private final long delay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,创建一个防抖器实例
|
||||||
|
*
|
||||||
|
* @param delay 延迟时间
|
||||||
|
* @param unit 时间单位
|
||||||
|
*/
|
||||||
|
public Debouncer(long delay, TimeUnit unit) {
|
||||||
|
this.delay = unit.toMillis(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行防抖操作,如果在指定延迟时间内再次调用相同key的任务,则取消之前的任务并重新计时
|
||||||
|
*
|
||||||
|
* @param key 任务的唯一标识符,用于区分不同任务
|
||||||
|
* @param task 要执行的任务
|
||||||
|
*/
|
||||||
|
public void debounce(final Object key, final Runnable task) {
|
||||||
|
// 提交新任务并获取之前可能存在的任务
|
||||||
|
final Future<?> prev = delayedMap.put(
|
||||||
|
key,
|
||||||
|
scheduler.schedule(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
task.run();
|
||||||
|
} finally {
|
||||||
|
// 任务执行完成后从映射中移除
|
||||||
|
delayedMap.remove(key);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delay,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 如果之前存在任务,则取消它
|
||||||
|
if (prev != null) {
|
||||||
|
prev.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭防抖器,取消所有待执行的任务并关闭调度器
|
||||||
|
*/
|
||||||
|
public void shutdown() {
|
||||||
|
// 先取消所有延迟任务
|
||||||
|
for (Future<?> future : delayedMap.values()) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
delayedMap.clear();
|
||||||
|
|
||||||
|
// 再关闭调度器
|
||||||
|
scheduler.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 P10Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P10Function<P, P1, P2, P3, P4, P5, P6, P7, P8, P9> {
|
||||||
|
void call(
|
||||||
|
P p,
|
||||||
|
P1 p1,
|
||||||
|
P2 p2,
|
||||||
|
P3 p3,
|
||||||
|
P4 p4,
|
||||||
|
P5 p5,
|
||||||
|
P6 p6,
|
||||||
|
P7 p7,
|
||||||
|
P8 p8,
|
||||||
|
P9 p9
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P10RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P10RFunction<P, P1, P2, P3, P4, P5, P6, P7, P8, P9, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P1Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P1Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P1Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P1Function<P> {
|
||||||
|
void call(P p);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P1RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P1RFunction<P, R> {
|
||||||
|
R call(P p);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P2Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P2Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P2Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P2Function<P, P1> {
|
||||||
|
void call(P p, P1 p1);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P2RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P2RFunction<P, P1, R> {
|
||||||
|
R call(P p, P1 p1);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P3Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P3Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P3Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P3Function<P, P1, P2> {
|
||||||
|
void call(P p, P1 p1, P2 p2);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P3RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P3RFunction<P, P1, P2, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P4Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P4Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P4Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P4Function<P, P1, P2, P3> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P4RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P4RFunction<P, P1, P2, P3, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P5Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P5Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P5Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P5Function<P, P1, P2, P3, P4> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P5RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P5RFunction<P, P1, P2, P3, P4, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P6Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P6Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P6Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P6Function<P, P1, P2, P3, P4, P5> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P6RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P6RFunction<P, P1, P2, P3, P4, P5, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P7Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P7Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P7Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P7Function<P, P1, P2, P3, P4, P5, P6> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P7RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P7RFunction<P, P1, P2, P3, P4, P5, P6, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6);
|
||||||
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P8Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P8Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P8Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P8Function<P, P1, P2, P3, P4, P5, P6, P7> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7);
|
||||||
|
}
|
||||||
@ -15,22 +15,14 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile JsonConverter.kt
|
* CurrentFile P8RFunction.java
|
||||||
* LastUpdate 2025-09-15 11:12:07
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.json.converters
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
interface JsonConverter<F, T> {
|
@FunctionalInterface
|
||||||
fun convert(obj: F?): T?
|
public interface P8RFunction<P, P1, P2, P3, P4, P5, P6, P7, R> {
|
||||||
fun deConvert(obj: T?): F?
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7);
|
||||||
val tClass: Class<F>
|
|
||||||
|
|
||||||
fun getStringConverter(): JsonStringConverter<F>? {
|
|
||||||
if (this is JsonStringConverter<*>) {
|
|
||||||
return this as JsonStringConverter<F>
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
28
src/main/java/com/mingliqiye/utils/functions/P9Function.java
Normal file
28
src/main/java/com/mingliqiye/utils/functions/P9Function.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P9Function.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P9Function<P, P1, P2, P3, P4, P5, P6, P7, P8> {
|
||||||
|
void call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 P9RFunction.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.functions;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface P9RFunction<P, P1, P2, P3, P4, P5, P6, P7, P8, R> {
|
||||||
|
R call(P p, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8);
|
||||||
|
}
|
||||||
114
src/main/java/com/mingliqiye/utils/hash/HashUtils.java
Normal file
114
src/main/java/com/mingliqiye/utils/hash/HashUtils.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 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 HashUtils.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.hash;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Security;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供常用的哈希计算工具方法,包括文件哈希值计算、BCrypt 加密等。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class HashUtils {
|
||||||
|
|
||||||
|
static {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算指定文件的哈希值。
|
||||||
|
*
|
||||||
|
* @param file 要计算哈希值的文件对象
|
||||||
|
* @param algorithm 使用的哈希算法名称(如 SHA-256、MD5 等)
|
||||||
|
* @return 文件的十六进制格式哈希值字符串
|
||||||
|
* @throws IOException 当文件不存在或读取过程中发生 I/O 错误时抛出
|
||||||
|
* @throws NoSuchAlgorithmException 当指定的哈希算法不可用时抛出
|
||||||
|
*/
|
||||||
|
public static String calculateFileHash(File file, String algorithm)
|
||||||
|
throws IOException, NoSuchAlgorithmException {
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new IOException("File not found: " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(algorithm);
|
||||||
|
|
||||||
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
// 分块读取文件内容并更新摘要
|
||||||
|
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||||
|
digest.update(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesToHex(digest.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组转换为十六进制字符串表示。
|
||||||
|
*
|
||||||
|
* @param bytes 输入的字节数组
|
||||||
|
* @return 对应的十六进制字符串
|
||||||
|
*/
|
||||||
|
private static String bytesToHex(byte[] bytes) {
|
||||||
|
StringBuilder hexString = new StringBuilder(2 * bytes.length);
|
||||||
|
for (byte b : bytes) {
|
||||||
|
String hex = Integer.toHexString(0xff & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
return hexString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 BCrypt 算法对字符串进行加密。
|
||||||
|
*
|
||||||
|
* @param string 需要加密的明文字符串
|
||||||
|
* @return 加密后的 BCrypt 哈希字符串
|
||||||
|
*/
|
||||||
|
public static String bcrypt(String string) {
|
||||||
|
return BCrypt.hashpw(string, BCrypt.gensalt());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证给定字符串与 BCrypt 哈希是否匹配。
|
||||||
|
*
|
||||||
|
* @param string 明文字符串
|
||||||
|
* @param bcrypted 已经使用 BCrypt 加密的哈希字符串
|
||||||
|
* @return 如果匹配返回 true,否则返回 false
|
||||||
|
*/
|
||||||
|
public static boolean checkBcrypt(String string, String bcrypted) {
|
||||||
|
return BCrypt.checkpw(string, bcrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/com/mingliqiye/utils/http/Response.java
Normal file
69
src/main/java/com/mingliqiye/utils/http/Response.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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 Response.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.http;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.time.DateTime;
|
||||||
|
import com.mingliqiye.utils.time.Formatter;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@Getter
|
||||||
|
public class Response<T> {
|
||||||
|
|
||||||
|
private final String time = DateTime.now().format(
|
||||||
|
Formatter.STANDARD_DATETIME_MILLISECOUND7
|
||||||
|
);
|
||||||
|
private String message;
|
||||||
|
private T data;
|
||||||
|
private int statusCode;
|
||||||
|
|
||||||
|
public Response(String message, T data, int statusCode) {
|
||||||
|
this.message = message;
|
||||||
|
this.data = data;
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> ok(T data) {
|
||||||
|
return new Response<>("操作成功", data, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<T> setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<T> setData(T data) {
|
||||||
|
this.data = data;
|
||||||
|
return Response.ok(getData())
|
||||||
|
.setMessage(getMessage())
|
||||||
|
.setStatusCode(getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<T> setStatusCode(int statusCode) {
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
222
src/main/java/com/mingliqiye/utils/iterator/Range.java
Normal file
222
src/main/java/com/mingliqiye/utils/iterator/Range.java
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* 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 Range.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.iterator;
|
||||||
|
|
||||||
|
import kotlin.ranges.ClosedRange;
|
||||||
|
import kotlin.ranges.OpenEndRange;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 范围 Range<br>
|
||||||
|
* Iterable 可遍历对象<br>
|
||||||
|
* 类似 KT的 {@code 0..10 = Range.of(0,10)} {@code 0..10 step 2 = Range.of(0,10,2)}
|
||||||
|
* @author MingLiPro
|
||||||
|
* @since 3.2.6
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class Range
|
||||||
|
implements Iterable<Integer>, ClosedRange<Integer>, OpenEndRange<Integer> {
|
||||||
|
|
||||||
|
private final int start;
|
||||||
|
private final int end;
|
||||||
|
private final int step;
|
||||||
|
private int current;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
*/
|
||||||
|
public Range(int start, int end) {
|
||||||
|
this(start, end, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @param step 步长
|
||||||
|
* @see Integer
|
||||||
|
*/
|
||||||
|
public Range(int start, int end, int step) {
|
||||||
|
this.start = start;
|
||||||
|
this.current = start;
|
||||||
|
this.step = step;
|
||||||
|
this.end = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 {@code 0 - range}<br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param range 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
*/
|
||||||
|
public Range(int range) {
|
||||||
|
this(0, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 {@code 0 - range}<br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param range 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
* @return Range 对象
|
||||||
|
*/
|
||||||
|
public static Range of(int range) {
|
||||||
|
return new Range(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
* @return Range 对象
|
||||||
|
*/
|
||||||
|
public static Range of(int start, int end) {
|
||||||
|
return new Range(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @param step 步长
|
||||||
|
* @see Integer
|
||||||
|
*/
|
||||||
|
public static Range of(int start, int end, int step) {
|
||||||
|
return new Range(start, end, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @param step 步长
|
||||||
|
* @see Integer
|
||||||
|
*/
|
||||||
|
public static Range range(int start, int end, int step) {
|
||||||
|
return new Range(start, end, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 {@code 0 - range}<br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param range 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
* @return Range 对象
|
||||||
|
*/
|
||||||
|
public static Range range(int range) {
|
||||||
|
return new Range(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个范围 <br>
|
||||||
|
* 最大值{@code Integer.MAX_VALUE = 2147483647 } <br>
|
||||||
|
* 最小值{@code Integer.MIN_VALUE = -2147483648} <br>
|
||||||
|
* @param start 开始 (包含)
|
||||||
|
* @param end 完毕 (包含)
|
||||||
|
* @see Integer
|
||||||
|
* @return Range 对象
|
||||||
|
*/
|
||||||
|
public static Range range(int start, int end) {
|
||||||
|
return new Range(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取迭代器
|
||||||
|
* @return 迭代器
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public @NotNull Iterator<Integer> iterator() {
|
||||||
|
return new Iterator<Integer>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return current < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer next() {
|
||||||
|
if (current >= end) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return current;
|
||||||
|
} finally {
|
||||||
|
current = current + step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
187
src/main/java/com/mingliqiye/utils/json/GsonJsonApi.java
Normal file
187
src/main/java/com/mingliqiye/utils/json/GsonJsonApi.java
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
|
||||||
|
public class GsonJsonApi implements JsonApi {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final Gson gsonUnicode;
|
||||||
|
private final Gson gsonPretty;
|
||||||
|
private final Gson gsonPrettyUnicode;
|
||||||
|
|
||||||
|
public GsonJsonApi() {
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gsonUnicode = new GsonBuilder()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gsonPretty = new GsonBuilder()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
|
||||||
|
gsonPrettyUnicode = new GsonBuilder()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GsonJsonApi(Gson gson) {
|
||||||
|
this.gson = gson
|
||||||
|
.newBuilder()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
this.gsonUnicode = gson
|
||||||
|
.newBuilder()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
this.gsonPretty = gson
|
||||||
|
.newBuilder()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
this.gsonPrettyUnicode = gson
|
||||||
|
.newBuilder()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.disableHtmlEscaping()
|
||||||
|
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T parse(String json, Class<T> clazz) {
|
||||||
|
return gson.fromJson(json, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T parse(String json, JsonTypeReference<T> type) {
|
||||||
|
return gson.fromJson(json, type.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(Object object) {
|
||||||
|
return gson.toJson(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatUnicode(Object object) {
|
||||||
|
return gsonUnicode.toJson(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatPretty(Object object) {
|
||||||
|
return gsonPretty.toJson(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatPrettyUnicode(Object object) {
|
||||||
|
return gsonPrettyUnicode.toJson(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidJson(String json) {
|
||||||
|
try {
|
||||||
|
JsonElement element = JsonParser.parseString(json);
|
||||||
|
return true;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String merge(String... jsons) {
|
||||||
|
JsonObject merged = new JsonObject();
|
||||||
|
for (String json : jsons) {
|
||||||
|
if (json == null || json.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
|
||||||
|
for (String key : obj.keySet()) {
|
||||||
|
merged.add(key, obj.get(key));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略无效的 JSON 字符串
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gson.toJson(merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNodeValue(String json, String path) {
|
||||||
|
try {
|
||||||
|
JsonElement element = JsonParser.parseString(json);
|
||||||
|
String[] paths = path.split("\\.");
|
||||||
|
JsonElement current = element;
|
||||||
|
|
||||||
|
for (String p : paths) {
|
||||||
|
if (current.isJsonObject()) {
|
||||||
|
current = current.getAsJsonObject().get(p);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.isJsonPrimitive()
|
||||||
|
? current.getAsString()
|
||||||
|
: current.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String updateNodeValue(String json, String path, Object newValue) {
|
||||||
|
try {
|
||||||
|
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
|
||||||
|
String[] paths = path.split("\\.");
|
||||||
|
JsonObject current = obj;
|
||||||
|
|
||||||
|
// 导航到倒数第二层
|
||||||
|
for (int i = 0; i < paths.length - 1; i++) {
|
||||||
|
String p = paths[i];
|
||||||
|
if (!current.has(p) || !current.get(p).isJsonObject()) {
|
||||||
|
current.add(p, new JsonObject());
|
||||||
|
}
|
||||||
|
current = current.getAsJsonObject(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置最后一层的值
|
||||||
|
String lastPath = paths[paths.length - 1];
|
||||||
|
if (newValue == null) {
|
||||||
|
current.remove(lastPath);
|
||||||
|
} else {
|
||||||
|
JsonElement element = gson.toJsonTree(newValue);
|
||||||
|
current.add(lastPath, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gson.toJson(obj);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, D> D convert(T source, Class<D> destinationClass) {
|
||||||
|
String json = gson.toJson(source);
|
||||||
|
return gson.fromJson(json, destinationClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
|
||||||
|
String json = gson.toJson(source);
|
||||||
|
return gson.fromJson(json, destinationType.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
341
src/main/java/com/mingliqiye/utils/json/JacksonJsonApi.java
Normal file
341
src/main/java/com/mingliqiye/utils/json/JacksonJsonApi.java
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* 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 JacksonJsonApi.java
|
||||||
|
* LastUpdate 2025-09-09 09:31:31
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于Jackson的JSON处理实现类,提供JSON字符串解析、格式化、合并、节点操作等功能。
|
||||||
|
*/
|
||||||
|
public class JacksonJsonApi implements JsonApi {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用默认的ObjectMapper构造实例
|
||||||
|
*/
|
||||||
|
public JacksonJsonApi() {
|
||||||
|
this.objectMapper = new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定的ObjectMapper构造实例
|
||||||
|
*
|
||||||
|
* @param objectMapper 自定义的ObjectMapper实例
|
||||||
|
*/
|
||||||
|
public JacksonJsonApi(ObjectMapper objectMapper) {
|
||||||
|
this.objectMapper = objectMapper.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定类型的对象
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param clazz 目标对象类型
|
||||||
|
* @param <T> 泛型参数,表示目标对象类型
|
||||||
|
* @return 解析后的对象
|
||||||
|
* @throws JsonException 当解析失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T parse(String json, Class<T> clazz) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(json, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JsonException("Failed to parse JSON string", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为复杂泛型结构的对象(如List、Map等)
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param type 泛型类型引用
|
||||||
|
* @param <T> 泛型参数,表示目标对象类型
|
||||||
|
* @return 解析后的对象
|
||||||
|
* @throws JsonException 当解析失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T parse(String json, JsonTypeReference<T> type) {
|
||||||
|
try {
|
||||||
|
ObjectReader reader = objectMapper.readerFor(
|
||||||
|
objectMapper.constructType(type.getType())
|
||||||
|
);
|
||||||
|
return reader.readValue(json);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JsonException("Failed to parse JSON string", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象格式化为JSON字符串
|
||||||
|
*
|
||||||
|
* @param object 待格式化的对象
|
||||||
|
* @return 格式化后的JSON字符串
|
||||||
|
* @throws JsonException 当格式化失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String format(Object object) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new JsonException(
|
||||||
|
"Failed to format object to JSON string",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatUnicode(Object object) {
|
||||||
|
try {
|
||||||
|
return objectMapper
|
||||||
|
.writer()
|
||||||
|
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
|
||||||
|
.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new JsonException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象格式化为美化(带缩进)的JSON字符串
|
||||||
|
*
|
||||||
|
* @param object 待格式化的对象
|
||||||
|
* @return 美化后的JSON字符串
|
||||||
|
* @throws JsonException 当格式化失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String formatPretty(Object object) {
|
||||||
|
try {
|
||||||
|
return objectMapper
|
||||||
|
.writerWithDefaultPrettyPrinter()
|
||||||
|
.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new JsonException(
|
||||||
|
"Failed to format object to pretty JSON string",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String formatPrettyUnicode(Object object) {
|
||||||
|
try {
|
||||||
|
return objectMapper
|
||||||
|
.writerWithDefaultPrettyPrinter()
|
||||||
|
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
|
||||||
|
.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new JsonException(
|
||||||
|
"Failed to format object to pretty JSON string",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定元素类型的List
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param elementType List中元素的类型
|
||||||
|
* @param <T> 泛型参数,表示List中元素的类型
|
||||||
|
* @return 解析后的List对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<T> parseList(String json, Class<T> elementType) {
|
||||||
|
return parse(json, JsonTypeUtils.listType(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定键值类型的Map
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param keyType Map中键的类型
|
||||||
|
* @param valueType Map中值的类型
|
||||||
|
* @param <K> 泛型参数,表示Map中键的类型
|
||||||
|
* @param <V> 泛型参数,表示Map中值的类型
|
||||||
|
* @return 解析后的Map对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <K, V> Map<K, V> parseMap(
|
||||||
|
String json,
|
||||||
|
Class<K> keyType,
|
||||||
|
Class<V> valueType
|
||||||
|
) {
|
||||||
|
return parse(json, JsonTypeUtils.MapType(keyType, valueType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定字符串是否是有效的JSON格式
|
||||||
|
*
|
||||||
|
* @param json 待验证的字符串
|
||||||
|
* @return 如果是有效JSON返回true,否则返回false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValidJson(String json) {
|
||||||
|
try {
|
||||||
|
objectMapper.readTree(json);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并多个JSON字符串为一个JSON对象
|
||||||
|
*
|
||||||
|
* @param jsons 多个JSON字符串
|
||||||
|
* @return 合并后的JSON字符串
|
||||||
|
* @throws JsonException 当合并失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String merge(String... jsons) {
|
||||||
|
ObjectNode result = objectMapper.createObjectNode();
|
||||||
|
for (String json : jsons) {
|
||||||
|
try {
|
||||||
|
JsonNode node = objectMapper.readTree(json);
|
||||||
|
if (node.isObject()) {
|
||||||
|
result.setAll((ObjectNode) node);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 忽略无效的JSON字符串
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(result);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new JsonException("Failed to merge JSON strings", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JSON字符串中指定路径的节点值
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param path 节点路径,使用"."分隔
|
||||||
|
* @return 节点值的文本表示,如果路径不存在则返回null
|
||||||
|
* @throws JsonException 当获取节点值失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getNodeValue(String json, String path) {
|
||||||
|
try {
|
||||||
|
JsonNode node = objectMapper.readTree(json);
|
||||||
|
String[] paths = path.split("\\.");
|
||||||
|
for (String p : paths) {
|
||||||
|
node = node.get(p);
|
||||||
|
if (node == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node.asText();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JsonException("Failed to get node value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新JSON字符串中指定路径的节点值
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param path 节点路径,使用"."分隔
|
||||||
|
* @param newValue 新的节点值
|
||||||
|
* @return 更新后的JSON字符串
|
||||||
|
* @throws JsonException 当更新节点值失败时抛出异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String updateNodeValue(String json, String path, Object newValue) {
|
||||||
|
try {
|
||||||
|
JsonNode node = objectMapper.readTree(json);
|
||||||
|
if (node instanceof ObjectNode) {
|
||||||
|
ObjectNode objectNode = (ObjectNode) node;
|
||||||
|
String[] paths = path.split("\\.");
|
||||||
|
JsonNode current = objectNode;
|
||||||
|
|
||||||
|
// 导航到目标节点的父节点
|
||||||
|
for (int i = 0; i < paths.length - 1; i++) {
|
||||||
|
current = current.get(paths[i]);
|
||||||
|
if (current == null || !(current instanceof ObjectNode)) {
|
||||||
|
return json; // 路径不存在或无效
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新值
|
||||||
|
if (current instanceof ObjectNode) {
|
||||||
|
ObjectNode parent = (ObjectNode) current;
|
||||||
|
if (newValue == null) {
|
||||||
|
parent.remove(paths[paths.length - 1]);
|
||||||
|
} else {
|
||||||
|
parent.set(
|
||||||
|
paths[paths.length - 1],
|
||||||
|
objectMapper.valueToTree(newValue)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectMapper.writeValueAsString(objectNode);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JsonException("Failed to update node value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在不同对象类型之间进行转换
|
||||||
|
*
|
||||||
|
* @param source 源对象
|
||||||
|
* @param destinationClass 目标对象类型
|
||||||
|
* @param <T> 源对象类型
|
||||||
|
* @param <D> 目标对象类型
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T, D> D convert(T source, Class<D> destinationClass) {
|
||||||
|
return objectMapper.convertValue(source, destinationClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在不同泛型对象类型之间进行转换
|
||||||
|
*
|
||||||
|
* @param source 源对象
|
||||||
|
* @param destinationType 目标对象的泛型类型引用
|
||||||
|
* @param <T> 源对象类型
|
||||||
|
* @param <D> 目标对象类型
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
|
||||||
|
return objectMapper.convertValue(
|
||||||
|
source,
|
||||||
|
objectMapper.constructType(destinationType.getType())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
390
src/main/java/com/mingliqiye/utils/json/JsonApi.java
Normal file
390
src/main/java/com/mingliqiye/utils/json/JsonApi.java
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* 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 JsonApi.java
|
||||||
|
* LastUpdate 2025-09-09 09:22:02
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON处理接口,提供JSON字符串与Java对象之间的相互转换功能
|
||||||
|
*/
|
||||||
|
public interface JsonApi {
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定类型的对象
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param clazz 目标对象的Class类型
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例
|
||||||
|
*/
|
||||||
|
<T> T parse(String json, Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定泛型类型对象
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param type 目标对象的Type类型(支持泛型)
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例
|
||||||
|
*/
|
||||||
|
<T> T parse(String json, JsonTypeReference<T> type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象格式化为JSON字符串
|
||||||
|
*
|
||||||
|
* @param object 待格式化的对象
|
||||||
|
* @return 格式化后的JSON字符串
|
||||||
|
*/
|
||||||
|
String format(Object object);
|
||||||
|
|
||||||
|
String formatUnicode(Object object);
|
||||||
|
|
||||||
|
default <T> T parseFrom(String path, Class<T> clazz) throws IOException {
|
||||||
|
return parseFrom(Paths.get(path), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(Path path, Class<T> clazz) throws IOException {
|
||||||
|
return parseFrom(path.toFile(), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(File file, Class<T> clazz) throws IOException {
|
||||||
|
try (InputStream inputStream = Files.newInputStream(file.toPath())) {
|
||||||
|
return parseFrom(inputStream, clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(InputStream inputStream, Class<T> clazz)
|
||||||
|
throws IOException {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalArgumentException("inputStream cannot be null");
|
||||||
|
}
|
||||||
|
if (clazz == null) {
|
||||||
|
throw new IllegalArgumentException("clazz cannot be null");
|
||||||
|
}
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||||
|
int readlength;
|
||||||
|
while ((readlength = inputStream.read(bytes)) != -1) {
|
||||||
|
bos.write(bytes, 0, readlength);
|
||||||
|
}
|
||||||
|
return parse(bos.toByteArray(), clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(String path, JsonTypeReference<T> type)
|
||||||
|
throws IOException {
|
||||||
|
return parseFrom(Paths.get(path), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(Path path, JsonTypeReference<T> type)
|
||||||
|
throws IOException {
|
||||||
|
return parseFrom(path.toFile(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(File file, JsonTypeReference<T> type)
|
||||||
|
throws IOException {
|
||||||
|
try (InputStream inputStream = Files.newInputStream(file.toPath())) {
|
||||||
|
return parseFrom(inputStream, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> T parseFrom(InputStream inputStream, JsonTypeReference<T> type)
|
||||||
|
throws IOException {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalArgumentException("inputStream cannot be null");
|
||||||
|
}
|
||||||
|
if (type == null) {
|
||||||
|
throw new IllegalArgumentException("type cannot be null");
|
||||||
|
}
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||||
|
int readlength;
|
||||||
|
while ((readlength = inputStream.read(bytes)) != -1) {
|
||||||
|
bos.write(bytes, 0, readlength);
|
||||||
|
}
|
||||||
|
return parse(bos.toByteArray(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组形式的JSON解析为指定类型的对象
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字节数组
|
||||||
|
* @param clazz 目标对象的Class类型
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例
|
||||||
|
*/
|
||||||
|
default <T> T parse(byte[] json, Class<T> clazz) {
|
||||||
|
return parse(new String(json), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组形式的JSON解析为指定泛型类型对象
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字节数组
|
||||||
|
* @param type 目标对象的Type类型(支持泛型)
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例
|
||||||
|
*/
|
||||||
|
default <T> T parse(byte[] json, JsonTypeReference<T> type) {
|
||||||
|
return parse(new String(json), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定类型的对象,解析失败时返回默认值
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param clazz 目标对象的Class类型
|
||||||
|
* @param defaultValue 解析失败时返回的默认值
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例或默认值
|
||||||
|
*/
|
||||||
|
default <T> T parse(String json, Class<T> clazz, T defaultValue) {
|
||||||
|
try {
|
||||||
|
return parse(json, clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定泛型类型对象,解析失败时返回默认值
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param type 目标对象的Type类型(支持泛型)
|
||||||
|
* @param defaultValue 解析失败时返回的默认值
|
||||||
|
* @param <T> 泛型参数,表示目标对象的类型
|
||||||
|
* @return 解析后的对象实例或默认值
|
||||||
|
*/
|
||||||
|
default <T> T parse(
|
||||||
|
String json,
|
||||||
|
JsonTypeReference<T> type,
|
||||||
|
T defaultValue
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
return parse(json, type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象格式化为美化格式的JSON字符串(带缩进和换行)
|
||||||
|
*
|
||||||
|
* @param object 待格式化的对象
|
||||||
|
* @return 格式化后的美化JSON字符串
|
||||||
|
*/
|
||||||
|
String formatPretty(Object object);
|
||||||
|
|
||||||
|
default byte[] formatPrettyBytes(Object object) {
|
||||||
|
return formatPretty(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatPrettyUnicode(Object object);
|
||||||
|
|
||||||
|
default byte[] formatPrettyUnicodeBytes(Object object) {
|
||||||
|
return formatPrettyUnicode(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPretty(Object object, String file) throws IOException {
|
||||||
|
formatPretty(object, Paths.get(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPretty(Object object, Path file) throws IOException {
|
||||||
|
formatPretty(object, file.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPretty(Object object, File file) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
formatPretty(object, fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPretty(Object object, OutputStream stream)
|
||||||
|
throws IOException {
|
||||||
|
stream.write(formatPrettyBytes(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPrettyUnicode(Object object, String file)
|
||||||
|
throws IOException {
|
||||||
|
formatPrettyUnicode(object, Paths.get(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPrettyUnicode(Object object, Path file)
|
||||||
|
throws IOException {
|
||||||
|
formatPrettyUnicode(object, file.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPrettyUnicode(Object object, File file)
|
||||||
|
throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
formatPrettyUnicode(object, fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatPrettyUnicode(Object object, OutputStream stream)
|
||||||
|
throws IOException {
|
||||||
|
stream.write(formatPrettyUnicodeBytes(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
default byte[] formatBytes(Object object) {
|
||||||
|
return format(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
default byte[] formatUnicodeBytes(Object object) {
|
||||||
|
return formatUnicode(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
default void format(Object object, String file) throws IOException {
|
||||||
|
format(object, Paths.get(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void format(Object object, Path file) throws IOException {
|
||||||
|
format(object, file.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void format(Object object, File file) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
format(object, fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void format(Object object, OutputStream stream) throws IOException {
|
||||||
|
stream.write(formatPrettyBytes(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatUnicode(Object object, String file) throws IOException {
|
||||||
|
formatUnicode(object, Paths.get(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatUnicode(Object object, Path file) throws IOException {
|
||||||
|
formatUnicode(object, file.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatUnicode(Object object, File file) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||||
|
formatUnicode(object, fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void formatUnicode(Object object, OutputStream stream)
|
||||||
|
throws IOException {
|
||||||
|
stream.write(formatPrettyUnicodeBytes(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定元素类型的List集合
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param elementType List中元素的类型
|
||||||
|
* @param <T> 泛型参数,表示List中元素的类型
|
||||||
|
* @return 解析后的List集合
|
||||||
|
*/
|
||||||
|
default <T> List<T> parseList(String json, Class<T> elementType) {
|
||||||
|
return parse(json, JsonTypeUtils.listType(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JSON字符串解析为指定键值类型的Map集合
|
||||||
|
*
|
||||||
|
* @param json 待解析的JSON字符串
|
||||||
|
* @param keyType Map中键的类型
|
||||||
|
* @param valueType Map中值的类型
|
||||||
|
* @param <K> 泛型参数,表示Map中键的类型
|
||||||
|
* @param <V> 泛型参数,表示Map中值的类型
|
||||||
|
* @return 解析后的Map集合
|
||||||
|
*/
|
||||||
|
default <K, V> Map<K, V> parseMap(
|
||||||
|
String json,
|
||||||
|
Class<K> keyType,
|
||||||
|
Class<V> valueType
|
||||||
|
) {
|
||||||
|
JsonTypeReference<Map<K, V>> mapType = new JsonTypeReference<
|
||||||
|
Map<K, V>
|
||||||
|
>() {};
|
||||||
|
return parse(json, mapType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证字符串是否为有效的JSON格式
|
||||||
|
*
|
||||||
|
* @param json 待验证的字符串
|
||||||
|
* @return 如果是有效的JSON格式返回true,否则返回false
|
||||||
|
*/
|
||||||
|
boolean isValidJson(String json);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为JSON字节数组
|
||||||
|
*
|
||||||
|
* @param object 待转换的对象
|
||||||
|
* @return 转换后的JSON字节数组
|
||||||
|
*/
|
||||||
|
default byte[] toBytes(Object object) {
|
||||||
|
return format(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为美化格式的JSON字节数组
|
||||||
|
*
|
||||||
|
* @param object 待转换的对象
|
||||||
|
* @return 转换后的美化格式JSON字节数组
|
||||||
|
*/
|
||||||
|
default byte[] toBytesPretty(Object object) {
|
||||||
|
return formatPretty(object).getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并多个JSON字符串为一个JSON对象
|
||||||
|
*
|
||||||
|
* @param jsons 待合并的JSON字符串数组
|
||||||
|
* @return 合并后的JSON字符串
|
||||||
|
*/
|
||||||
|
String merge(String... jsons);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JSON字符串中指定路径节点的值
|
||||||
|
*
|
||||||
|
* @param json JSON字符串
|
||||||
|
* @param path 节点路径(如:"user.name")
|
||||||
|
* @return 节点值的字符串表示
|
||||||
|
*/
|
||||||
|
String getNodeValue(String json, String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新JSON字符串中指定路径节点的值
|
||||||
|
*
|
||||||
|
* @param json 原始JSON字符串
|
||||||
|
* @param path 节点路径(如:"user.name")
|
||||||
|
* @param newValue 新的节点值
|
||||||
|
* @return 更新后的JSON字符串
|
||||||
|
*/
|
||||||
|
String updateNodeValue(String json, String path, Object newValue);
|
||||||
|
|
||||||
|
<T, D> D convert(T source, Class<D> destinationClass);
|
||||||
|
|
||||||
|
<T, D> D convert(T source, JsonTypeReference<D> destinationType);
|
||||||
|
}
|
||||||
@ -15,36 +15,24 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile InputStreamUtils.kt
|
* CurrentFile JsonException.java
|
||||||
* LastUpdate 2025-09-15 17:26:34
|
* LastUpdate 2025-09-09 09:25:08
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
@file:JvmName("InputStreamUtils")
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.io
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
import java.io.InputStream
|
public class JsonException extends RuntimeException {
|
||||||
import java.io.OutputStream
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
|
public JsonException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
fun InputStream.readAllText(charset: Charset = Charsets.UTF_8): String {
|
public JsonException(String message, Throwable cause) {
|
||||||
return this.readAllBytes().toString(charset)
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonException(Throwable cause) {
|
||||||
|
this(cause.getMessage(), cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readAllBytes(): ByteArray {
|
|
||||||
return this.readBytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun InputStream.exportBytes(out: OutputStream) {
|
|
||||||
out.write(this.readAllBytes())
|
|
||||||
out.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun InputStream.readToList(): List<Byte> {
|
|
||||||
return this.readBytes().toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
175
src/main/java/com/mingliqiye/utils/json/JsonTypeReference.java
Normal file
175
src/main/java/com/mingliqiye/utils/json/JsonTypeReference.java
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* 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 JsonTypeReference.java
|
||||||
|
* LastUpdate 2025-09-09 09:20:05
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的 JSON 类型引用类,用于在运行时保留泛型类型信息
|
||||||
|
* 适用于所有 JSON 库(Jackson、Gson、Fastjson 等)
|
||||||
|
*
|
||||||
|
* @param <T> 引用的泛型类型
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public abstract class JsonTypeReference<T>
|
||||||
|
implements Comparable<JsonTypeReference<T>> {
|
||||||
|
|
||||||
|
protected final Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,通过反射获取泛型类型信息
|
||||||
|
* 仅供内部匿名子类使用
|
||||||
|
*/
|
||||||
|
protected JsonTypeReference() {
|
||||||
|
Type superClass = getClass().getGenericSuperclass();
|
||||||
|
|
||||||
|
// 检查是否为匿名子类,防止直接实例化导致无法获取泛型信息
|
||||||
|
if (superClass instanceof Class) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"必须使用匿名子类方式创建 JsonTypeReference," +
|
||||||
|
"例如: new JsonTypeReference<List<String>>() {}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type =
|
||||||
|
((ParameterizedType) superClass).getActualTypeArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,直接指定类型
|
||||||
|
* @param type 具体的类型信息
|
||||||
|
*/
|
||||||
|
protected JsonTypeReference(Type type) {
|
||||||
|
this.type = Objects.requireNonNull(type, "Type cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建类型引用实例
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @return 类型引用实例
|
||||||
|
*/
|
||||||
|
public static <T> JsonTypeReference<T> of() {
|
||||||
|
return new JsonTypeReference<T>() {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Class 创建类型引用
|
||||||
|
* @param clazz 目标类
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @return 类型引用实例
|
||||||
|
*/
|
||||||
|
public static <T> JsonTypeReference<T> of(Class<T> clazz) {
|
||||||
|
return new JsonTypeReference<T>(clazz) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 Type 创建类型引用
|
||||||
|
* @param type 目标类型
|
||||||
|
* @param <T> 目标类型
|
||||||
|
* @return 类型引用实例
|
||||||
|
*/
|
||||||
|
public static <T> JsonTypeReference<T> of(Type type) {
|
||||||
|
return new JsonTypeReference<T>(type) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取原始类型(去掉泛型参数的类型)
|
||||||
|
* @return 原始类型 Class
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Class<T> getRawType() {
|
||||||
|
Type rawType = type;
|
||||||
|
|
||||||
|
// 如果是参数化类型,则提取原始类型部分
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
rawType = ((ParameterizedType) type).getRawType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawType instanceof Class) {
|
||||||
|
return (Class<T>) rawType;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("无法获取原始类型: " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
JsonTypeReference<?> that = (JsonTypeReference<?>) o;
|
||||||
|
|
||||||
|
// 对于 ParameterizedType,需要更完整的比较
|
||||||
|
if (
|
||||||
|
this.type instanceof ParameterizedType &&
|
||||||
|
that.type instanceof ParameterizedType
|
||||||
|
) {
|
||||||
|
ParameterizedType thisParamType = (ParameterizedType) this.type;
|
||||||
|
ParameterizedType thatParamType = (ParameterizedType) that.type;
|
||||||
|
|
||||||
|
return (
|
||||||
|
Objects.equals(
|
||||||
|
thisParamType.getRawType(),
|
||||||
|
thatParamType.getRawType()
|
||||||
|
) &&
|
||||||
|
Arrays.equals(
|
||||||
|
thisParamType.getActualTypeArguments(),
|
||||||
|
thatParamType.getActualTypeArguments()
|
||||||
|
) &&
|
||||||
|
Objects.equals(
|
||||||
|
thisParamType.getOwnerType(),
|
||||||
|
thatParamType.getOwnerType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Objects.equals(type, that.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
// 针对 ParameterizedType 进行完整哈希计算
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
ParameterizedType paramType = (ParameterizedType) type;
|
||||||
|
return Objects.hash(
|
||||||
|
paramType.getRawType(),
|
||||||
|
Arrays.hashCode(paramType.getActualTypeArguments()),
|
||||||
|
paramType.getOwnerType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Objects.hash(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "JsonTypeReference{" + type + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(JsonTypeReference<T> o) {
|
||||||
|
return this.type.toString().compareTo(o.type.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
253
src/main/java/com/mingliqiye/utils/json/JsonTypeUtils.java
Normal file
253
src/main/java/com/mingliqiye/utils/json/JsonTypeUtils.java
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* 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 JsonTypeUtils.java
|
||||||
|
* LastUpdate 2025-09-09 09:18:08
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON 类型工具类,提供类型相关的工具方法
|
||||||
|
*/
|
||||||
|
public class JsonTypeUtils {
|
||||||
|
|
||||||
|
private JsonTypeUtils() {
|
||||||
|
// 工具类,防止实例化
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查给定的类型是否是指定类或其子类/实现类。
|
||||||
|
*
|
||||||
|
* @param type 要检查的类型
|
||||||
|
* @param expectedClass 期望匹配的类
|
||||||
|
* @return 如果类型匹配则返回 true,否则返回 false
|
||||||
|
*/
|
||||||
|
public static boolean isTypeOf(Type type, Class<?> expectedClass) {
|
||||||
|
if (type instanceof Class) {
|
||||||
|
return expectedClass.isAssignableFrom((Class<?>) type);
|
||||||
|
} else if (type instanceof ParameterizedType) {
|
||||||
|
return isTypeOf(
|
||||||
|
((ParameterizedType) type).getRawType(),
|
||||||
|
expectedClass
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取泛型类型的参数类型。
|
||||||
|
*
|
||||||
|
* @param type 泛型类型
|
||||||
|
* @param index 参数索引(从0开始)
|
||||||
|
* @return 指定位置的泛型参数类型
|
||||||
|
* @throws IllegalArgumentException 当无法获取指定索引的泛型参数时抛出异常
|
||||||
|
*/
|
||||||
|
public static Type getGenericParameter(Type type, int index) {
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
Type[] typeArgs =
|
||||||
|
((ParameterizedType) type).getActualTypeArguments();
|
||||||
|
if (index >= 0 && index < typeArgs.length) {
|
||||||
|
return typeArgs[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"无法获取泛型参数: " + type + " at index " + index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类型名称,支持普通类和泛型类型。
|
||||||
|
*
|
||||||
|
* @param type 类型对象
|
||||||
|
* @return 类型名称字符串
|
||||||
|
*/
|
||||||
|
public static String getTypeName(Type type) {
|
||||||
|
if (type instanceof Class) {
|
||||||
|
return ((Class<?>) type).getSimpleName();
|
||||||
|
} else if (type instanceof ParameterizedType) {
|
||||||
|
ParameterizedType pType = (ParameterizedType) type;
|
||||||
|
Class<?> rawType = (Class<?>) pType.getRawType();
|
||||||
|
Type[] typeArgs = pType.getActualTypeArguments();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(rawType.getSimpleName());
|
||||||
|
sb.append("<");
|
||||||
|
for (int i = 0; i < typeArgs.length; i++) {
|
||||||
|
if (i > 0) sb.append(", ");
|
||||||
|
sb.append(getTypeName(typeArgs[i]));
|
||||||
|
}
|
||||||
|
sb.append(">");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
return type.getTypeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个表示数组类型的引用对象。
|
||||||
|
*
|
||||||
|
* @param componentType 数组元素的类型
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 表示数组类型的 JsonTypeReference 对象
|
||||||
|
*/
|
||||||
|
public static <T> JsonTypeReference<T[]> arrayType(Class<T> componentType) {
|
||||||
|
return new JsonTypeReference<T[]>() {
|
||||||
|
private final Type arrayType = java.lang.reflect.Array.newInstance(
|
||||||
|
componentType,
|
||||||
|
0
|
||||||
|
).getClass();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return new ParameterizedType() {
|
||||||
|
private final Type[] actualTypeArguments = new Type[] {
|
||||||
|
componentType,
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type[] getActualTypeArguments() {
|
||||||
|
return actualTypeArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getRawType() {
|
||||||
|
return arrayType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getOwnerType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个表示 List 类型的引用对象。
|
||||||
|
*
|
||||||
|
* @param componentType List 中元素的类型
|
||||||
|
* @param <T> 元素类型
|
||||||
|
* @return 表示 List 类型的 JsonTypeReference 对象
|
||||||
|
* @throws IllegalArgumentException 如果 componentType 为 null,则抛出异常
|
||||||
|
*/
|
||||||
|
public static <T> JsonTypeReference<List<T>> listType(
|
||||||
|
Class<T> componentType
|
||||||
|
) {
|
||||||
|
if (componentType == null) {
|
||||||
|
throw new IllegalArgumentException("componentType cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonTypeReference<List<T>>() {
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return new ParameterizedType() {
|
||||||
|
@Override
|
||||||
|
public Type[] getActualTypeArguments() {
|
||||||
|
return new Type[] { componentType };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getRawType() {
|
||||||
|
return List.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getOwnerType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个表示 Map 类型的引用对象。
|
||||||
|
*
|
||||||
|
* @param keyType Map 键的类型
|
||||||
|
* @param valueType Map 值的类型
|
||||||
|
* @param <K> 键类型
|
||||||
|
* @param <V> 值类型
|
||||||
|
* @return 表示 Map 类型的 JsonTypeReference 对象
|
||||||
|
* @throws IllegalArgumentException 如果 keyType 或 valueType 为 null,则抛出异常
|
||||||
|
*/
|
||||||
|
public static <K, V> JsonTypeReference<Map<K, V>> MapType(
|
||||||
|
Class<K> keyType,
|
||||||
|
Class<V> valueType
|
||||||
|
) {
|
||||||
|
if (keyType == null) {
|
||||||
|
throw new IllegalArgumentException("keyType cannot be null");
|
||||||
|
}
|
||||||
|
if (valueType == null) {
|
||||||
|
throw new IllegalArgumentException("valueType cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonTypeReference<Map<K, V>>() {
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return new ParameterizedType() {
|
||||||
|
@Override
|
||||||
|
public Type[] getActualTypeArguments() {
|
||||||
|
return new Type[] { keyType, valueType };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getRawType() {
|
||||||
|
return Map.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getOwnerType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (!(obj instanceof ParameterizedType)) return false;
|
||||||
|
|
||||||
|
ParameterizedType that = (ParameterizedType) obj;
|
||||||
|
return (
|
||||||
|
Objects.equals(getRawType(), that.getRawType()) &&
|
||||||
|
Arrays.equals(
|
||||||
|
getActualTypeArguments(),
|
||||||
|
that.getActualTypeArguments()
|
||||||
|
) &&
|
||||||
|
Objects.equals(getOwnerType(), that.getOwnerType())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (
|
||||||
|
Arrays.hashCode(getActualTypeArguments()) ^
|
||||||
|
Objects.hashCode(getRawType()) ^
|
||||||
|
Objects.hashCode(getOwnerType())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.time.DateTime;
|
||||||
|
import com.mingliqiye.utils.time.Formatter;
|
||||||
|
|
||||||
|
public class DateTimeJsonConverter extends JsonStringConverter<DateTime> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<DateTime> getTClass() {
|
||||||
|
return DateTime.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(DateTime obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return obj.format(Formatter.STANDARD_DATETIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DateTime deConvert(String string) {
|
||||||
|
if (string == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return DateTime.parse(
|
||||||
|
string,
|
||||||
|
Formatter.STANDARD_DATETIME_MILLISECOUND7,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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 FastjsonJsonStringConverterAdapter.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONReader;
|
||||||
|
import com.alibaba.fastjson2.JSONWriter;
|
||||||
|
import com.alibaba.fastjson2.reader.ObjectReader;
|
||||||
|
import com.alibaba.fastjson2.writer.ObjectWriter;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class FastjsonJsonStringConverterAdapter<
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> {
|
||||||
|
|
||||||
|
private final JsonStringConverter<TT> jsonStringConverter;
|
||||||
|
|
||||||
|
public FastjsonJsonStringConverterAdapter(T jsonStringConverter) {
|
||||||
|
this.jsonStringConverter = jsonStringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> FastjsonJsonStringConverterAdapter<T, TT> of(T t) {
|
||||||
|
return new FastjsonJsonStringConverterAdapter<>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取FastJson对象写入器
|
||||||
|
*
|
||||||
|
* @return FastJson的ObjectWriter实例
|
||||||
|
*/
|
||||||
|
public ObjectWriter<T> getFastJsonObjectWriter() {
|
||||||
|
return (
|
||||||
|
JSONWriter writer,
|
||||||
|
Object object,
|
||||||
|
Object fieldName,
|
||||||
|
Type fieldType,
|
||||||
|
long features
|
||||||
|
) -> {
|
||||||
|
// 如果对象为null则写入null
|
||||||
|
if (object == null) {
|
||||||
|
writer.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writer.writeString(jsonStringConverter.convert((TT) object));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取FastJson对象读取器
|
||||||
|
*
|
||||||
|
* @return FastJson的ObjectReader实例
|
||||||
|
*/
|
||||||
|
public ObjectReader<TT> getFastJsonObjectReader() {
|
||||||
|
return (
|
||||||
|
JSONReader reader,
|
||||||
|
Type fieldType,
|
||||||
|
Object fieldName,
|
||||||
|
long features
|
||||||
|
) -> {
|
||||||
|
String value = reader.readString();
|
||||||
|
return jsonStringConverter.deConvert(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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 GsonJsonStringConverterAdapter.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GsonJsonStringConverterAdapter<
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> {
|
||||||
|
|
||||||
|
private final JsonStringConverter<TT> jsonStringConverter;
|
||||||
|
|
||||||
|
public GsonJsonStringConverterAdapter(T jsonStringConverter) {
|
||||||
|
this.jsonStringConverter = jsonStringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> GsonJsonStringConverterAdapter<T, TT> of(T t) {
|
||||||
|
return new GsonJsonStringConverterAdapter<>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Gson类型适配器
|
||||||
|
*
|
||||||
|
* @return Gson的TypeAdapter实例
|
||||||
|
*/
|
||||||
|
public TypeAdapter<TT> getGsonTypeAdapter() {
|
||||||
|
return new TypeAdapter<TT>() {
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, TT value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
out.nullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.value(jsonStringConverter.convert(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TT read(JsonReader in) throws IOException {
|
||||||
|
String value = in.nextString();
|
||||||
|
return jsonStringConverter.deConvert(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.*;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON转换器的适配器
|
||||||
|
* @param <T> JSON转换器
|
||||||
|
* @param <TT> JSON转换器的泛型
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class JacksonJsonStringConverterAdapter<
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> {
|
||||||
|
|
||||||
|
private final JsonStringConverter<TT> jsonStringConverter;
|
||||||
|
|
||||||
|
private JacksonJsonStringConverterAdapter(T jsonStringConverter) {
|
||||||
|
this.jsonStringConverter = jsonStringConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param t JSON转换器实例
|
||||||
|
* @return JSON转换器的适配器
|
||||||
|
* @param <T> JSON转换器
|
||||||
|
* @param <TT> JSON转换器的泛型
|
||||||
|
*/
|
||||||
|
public static <
|
||||||
|
T extends JsonStringConverter<TT>,
|
||||||
|
TT
|
||||||
|
> JacksonJsonStringConverterAdapter<T, TT> of(T t) {
|
||||||
|
return new JacksonJsonStringConverterAdapter<>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Jackson反序列化器
|
||||||
|
*
|
||||||
|
* @return Jackson的JsonDeserializer实例
|
||||||
|
*/
|
||||||
|
public JsonDeserializer<TT> getJacksonJsonDeserializer() {
|
||||||
|
return new JsonDeserializer<TT>() {
|
||||||
|
@Override
|
||||||
|
public TT deserialize(JsonParser p, DeserializationContext ctxt)
|
||||||
|
throws IOException {
|
||||||
|
if (p.isNaN()) return null;
|
||||||
|
return jsonStringConverter.deConvert(p.getValueAsString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Jackson序列化器
|
||||||
|
*
|
||||||
|
* @return Jackson的JsonSerializer实例
|
||||||
|
*/
|
||||||
|
public JsonSerializer<TT> getJacksonJsonSerializer() {
|
||||||
|
return new JsonSerializer<TT>() {
|
||||||
|
@Override
|
||||||
|
public void serialize(
|
||||||
|
TT value,
|
||||||
|
JsonGenerator gen,
|
||||||
|
SerializerProvider serializers
|
||||||
|
) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
gen.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gen.writeString(jsonStringConverter.convert(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 获取 Jackson 的格式化模块
|
||||||
|
*
|
||||||
|
* @return 格式化模块
|
||||||
|
*/
|
||||||
|
public Module getJacksonModule() {
|
||||||
|
Class<TT> tClass = jsonStringConverter.getTClass();
|
||||||
|
SimpleModule m = new SimpleModule(tClass.getSimpleName());
|
||||||
|
m.addSerializer(tClass, getJacksonJsonSerializer());
|
||||||
|
m.addDeserializer(tClass, getJacksonJsonDeserializer());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON转换器接口,提供对象与字符串之间的相互转换功能,并支持多种JSON库
|
||||||
|
*
|
||||||
|
* @param <T> 需要转换的对象类型
|
||||||
|
*/
|
||||||
|
public abstract class JsonStringConverter<T> {
|
||||||
|
|
||||||
|
public abstract Class<T> getTClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为字符串
|
||||||
|
*
|
||||||
|
* @param obj 待转换的对象
|
||||||
|
* @return 转换后的字符串
|
||||||
|
*/
|
||||||
|
abstract String convert(T obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串转换为对象
|
||||||
|
*
|
||||||
|
* @param string 待转换的字符串
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
abstract T deConvert(String string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 Fastjson 的适配器
|
||||||
|
* @return 适配器实例
|
||||||
|
*/
|
||||||
|
public FastjsonJsonStringConverterAdapter<
|
||||||
|
JsonStringConverter<T>,
|
||||||
|
T
|
||||||
|
> getFastjsonJsonStringConverterAdapter() {
|
||||||
|
return FastjsonJsonStringConverterAdapter.of(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 Gson 的适配器
|
||||||
|
* @return 适配器实例
|
||||||
|
*/
|
||||||
|
public GsonJsonStringConverterAdapter<
|
||||||
|
JsonStringConverter<T>,
|
||||||
|
T
|
||||||
|
> getGsonJsonStringConverterAdapter() {
|
||||||
|
return GsonJsonStringConverterAdapter.of(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 Jackson 的适配器
|
||||||
|
* @return 适配器实例
|
||||||
|
*/
|
||||||
|
public JacksonJsonStringConverterAdapter<
|
||||||
|
JsonStringConverter<T>,
|
||||||
|
T
|
||||||
|
> getJacksonJsonStringConverterAdapter() {
|
||||||
|
return JacksonJsonStringConverterAdapter.of(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.mingliqiye.utils.json.converters;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.uuid.UUID;
|
||||||
|
|
||||||
|
public class UUIDJsonStringConverter extends JsonStringConverter<UUID> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<UUID> getTClass() {
|
||||||
|
return UUID.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(UUID obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return obj.toUUIDString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID deConvert(String string) {
|
||||||
|
if (string == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return UUID.of(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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 Pseudocryptography.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.pe.json;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.collection.ForEach;
|
||||||
|
import com.mingliqiye.utils.file.FileUtil;
|
||||||
|
import com.mingliqiye.utils.json.JsonApi;
|
||||||
|
import com.mingliqiye.utils.json.JsonTypeReference;
|
||||||
|
import com.mingliqiye.utils.string.StringUtils;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Pseudocryptography {
|
||||||
|
|
||||||
|
private final JsonApi jsonApi;
|
||||||
|
|
||||||
|
public Pseudocryptography(JsonApi jsonApi) {
|
||||||
|
this.jsonApi = jsonApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object prossed(Object object) {
|
||||||
|
if (object instanceof Map) {
|
||||||
|
System.out.println(object.getClass());
|
||||||
|
val map = new HashMap<>((Map<Object, Object>) object);
|
||||||
|
val map2 = new HashMap<>(map.size() + 3);
|
||||||
|
map.forEach((key, value) -> {
|
||||||
|
if (key instanceof String) {
|
||||||
|
map2.put(prossed(key), prossed(value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return map2;
|
||||||
|
} else if (object instanceof String) {
|
||||||
|
return StringUtils.stringToUnicode((String) object);
|
||||||
|
} else if (object instanceof List) {
|
||||||
|
ForEach.forEach((List<Object>) object, (t, i) -> {
|
||||||
|
((List<Object>) object).set(i, prossed(t));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decode(String path) {
|
||||||
|
try {
|
||||||
|
final Map<String, Object> map = jsonApi.parseFrom(
|
||||||
|
path,
|
||||||
|
new JsonTypeReference<HashMap<String, Object>>() {}
|
||||||
|
);
|
||||||
|
|
||||||
|
String s = jsonApi.format(prossed(map)).replace("\\\\u", "\\u");
|
||||||
|
FileUtil.writeStringToFile(StringUtils.format("old-{}", path), s);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,18 +15,18 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile JsonException.kt
|
* CurrentFile Description.java
|
||||||
* LastUpdate 2025-09-15 22:32:50
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.json
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
class JsonException : RuntimeException {
|
import lombok.Data;
|
||||||
|
|
||||||
constructor(message: String) : super(message)
|
@Data
|
||||||
|
public class Description {
|
||||||
|
|
||||||
constructor(message: String, cause: Throwable) : super(message, cause)
|
private String text;
|
||||||
|
private Extra[] extra;
|
||||||
constructor(cause: Throwable) : this(cause.message ?: "", cause)
|
|
||||||
}
|
}
|
||||||
@ -15,20 +15,20 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile StreamEmptyException.java
|
* CurrentFile Extra.java
|
||||||
* LastUpdate 2025-09-20 13:24:07
|
* LastUpdate 2025-09-09 08:37:34
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.stream;
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
public class StreamEmptyException extends java.lang.RuntimeException {
|
import lombok.Data;
|
||||||
|
|
||||||
public StreamEmptyException(String message) {
|
@Data
|
||||||
super(message);
|
public class Extra {
|
||||||
}
|
|
||||||
|
|
||||||
public StreamEmptyException(String message, Throwable cause) {
|
private String text;
|
||||||
super(message, cause);
|
private String color;
|
||||||
}
|
private Boolean bold;
|
||||||
|
private Boolean italic;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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 MinecraftServerStatus.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MinecraftServerStatus {
|
||||||
|
|
||||||
|
private Description description;
|
||||||
|
private Players players;
|
||||||
|
private Version version;
|
||||||
|
private String favicon;
|
||||||
|
private boolean enforcesSecureChat;
|
||||||
|
private boolean previewsChat;
|
||||||
|
private String jsonData;
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 PlayerSample.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PlayerSample {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 Players.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Players {
|
||||||
|
|
||||||
|
private int max;
|
||||||
|
private int online;
|
||||||
|
private PlayerSample[] sample;
|
||||||
|
}
|
||||||
219
src/main/java/com/mingliqiye/utils/minecraft/slp/SLP.java
Normal file
219
src/main/java/com/mingliqiye/utils/minecraft/slp/SLP.java
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* 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 SLP.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.mingliqiye.utils.network.NetworkEndpoint;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minecraft 服务器列表协议(Server List Ping, SLP)工具类。
|
||||||
|
* 提供了与 Minecraft 服务器通信以获取其状态信息的功能。
|
||||||
|
*/
|
||||||
|
public class SLP {
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 int32 值截断为无符号 short(2 字节)并按大端序写入字节数组。
|
||||||
|
*
|
||||||
|
* @param value 需要转换的整数(int32)
|
||||||
|
* @return 包含两个字节的数组,表示无符号 short
|
||||||
|
*/
|
||||||
|
public static byte[] toUnsignedShort(int value) {
|
||||||
|
byte[] array = new byte[2];
|
||||||
|
ByteBuffer.wrap(array, 0, 2)
|
||||||
|
.order(ByteOrder.BIG_ENDIAN)
|
||||||
|
.putShort((short) (value & 0xFFFF));
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造 Minecraft 握手包数据。
|
||||||
|
* 握手包用于初始化客户端与服务器之间的连接。
|
||||||
|
*
|
||||||
|
* @param serverIP 服务器 IP 地址或域名
|
||||||
|
* @param serverPort 服务器端口号
|
||||||
|
* @param type 连接类型(通常为 1 表示获取状态)
|
||||||
|
* @return 握手包的完整字节数组
|
||||||
|
* @throws IOException 如果构造过程中发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static byte[] getHandshakePack(
|
||||||
|
String serverIP,
|
||||||
|
int serverPort,
|
||||||
|
int type
|
||||||
|
) throws IOException {
|
||||||
|
ByteArrayOutputStream pack = new ByteArrayOutputStream();
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
pack.write(0x00); // 握手包标识符
|
||||||
|
pack.write(toVarInt(1156)); // 协议版本号(示例值)
|
||||||
|
byte[] sip = serverIP.getBytes();
|
||||||
|
pack.write(toVarInt(sip.length)); // 服务器地址长度
|
||||||
|
pack.write(sip); // 服务器地址
|
||||||
|
pack.write(toUnsignedShort(serverPort)); // 服务器端口
|
||||||
|
pack.write(toVarInt(type)); // 下一阶段类型(1 表示状态请求)
|
||||||
|
byteArrayOutputStream.write(toVarInt(pack.size())); // 包长度前缀
|
||||||
|
byteArrayOutputStream.write(pack.toByteArray());
|
||||||
|
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取状态请求包的固定字节表示。
|
||||||
|
* 此包用于向服务器请求当前状态信息。
|
||||||
|
*
|
||||||
|
* @return 状态请求包的字节数组
|
||||||
|
*/
|
||||||
|
public static byte[] getStatusPack() {
|
||||||
|
return new byte[] { 0x01, 0x00 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从输入流中读取服务器返回的状态 JSON 数据,并解析为 MinecraftServerStatus 实体对象。
|
||||||
|
*
|
||||||
|
* @param inputStream 输入流,包含服务器响应的数据
|
||||||
|
* @return 解析后的 MinecraftServerStatus 对象
|
||||||
|
* @throws IOException 如果读取过程中发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getStatusJsonEntity(
|
||||||
|
DataInputStream inputStream
|
||||||
|
) throws IOException {
|
||||||
|
readVarInt(inputStream); // 忽略第一个 VarInt(包长度)
|
||||||
|
inputStream.readByte(); // 忽略包标识符
|
||||||
|
int lengthjson = readVarInt(inputStream); // 读取 JSON 数据长度
|
||||||
|
byte[] data = new byte[lengthjson];
|
||||||
|
inputStream.readFully(data); // 读取完整的 JSON 数据
|
||||||
|
MinecraftServerStatus serverStatus = objectMapper.readValue(
|
||||||
|
data,
|
||||||
|
MinecraftServerStatus.class
|
||||||
|
);
|
||||||
|
serverStatus.setJsonData(new String(data)); // 设置原始 JSON 字符串
|
||||||
|
return serverStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从输入流中读取一个 VarInt 类型的整数(最多 5 个字节)。
|
||||||
|
*
|
||||||
|
* @param in 输入流
|
||||||
|
* @return 解码后的整数值
|
||||||
|
* @throws IOException 如果读取过程中发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static int readVarInt(DataInputStream in) throws IOException {
|
||||||
|
int value = 0;
|
||||||
|
int length = 0;
|
||||||
|
byte currentByte;
|
||||||
|
do {
|
||||||
|
currentByte = in.readByte();
|
||||||
|
value |= (currentByte & 0x7F) << (length * 7);
|
||||||
|
length += 1;
|
||||||
|
if (length > 5) {
|
||||||
|
throw new RuntimeException("VarInt too long");
|
||||||
|
}
|
||||||
|
} while ((currentByte & 0x80) != 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个 int32 整数编码为 VarInt 格式的字节数组(1 到 5 个字节)。
|
||||||
|
*
|
||||||
|
* @param value 需要编码的整数
|
||||||
|
* @return 编码后的 VarInt 字节数组
|
||||||
|
*/
|
||||||
|
public static byte[] toVarInt(int value) {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
while (true) {
|
||||||
|
if ((value & 0xFFFFFF80) == 0) {
|
||||||
|
buffer.write(value); // 最后一个字节
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer.write((value & 0x7F) | 0x80); // 写入带继续位的字节
|
||||||
|
value >>>= 7; // 右移 7 位继续处理
|
||||||
|
}
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的 Socket 连接到指定的网络端点,并设置超时时间。
|
||||||
|
*
|
||||||
|
* @param networkEndpoint 目标网络端点(包括主机和端口)
|
||||||
|
* @return 已连接的 Socket 实例
|
||||||
|
* @throws IOException 如果连接失败或发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static Socket getNewConnect(NetworkEndpoint networkEndpoint)
|
||||||
|
throws IOException {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
socket.setSoTimeout(5000); // 设置读取超时时间为 5 秒
|
||||||
|
socket.connect(networkEndpoint.toInetSocketAddress()); // 执行连接操作
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 "host:port" 格式的字符串连接到 Minecraft 服务器并获取其状态信息。
|
||||||
|
*
|
||||||
|
* @param s 域名或 IP 地址加端口号组成的字符串,例如 "127.0.0.1:25565"
|
||||||
|
* @return 服务器状态实体对象
|
||||||
|
* @throws IOException 如果连接失败或发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(String s)
|
||||||
|
throws IOException {
|
||||||
|
return getServerStatus(NetworkEndpoint.of(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定的主机名和端口号连接到 Minecraft 服务器并获取其状态信息。
|
||||||
|
*
|
||||||
|
* @param s 主机名或 IP 地址
|
||||||
|
* @param i 端口号
|
||||||
|
* @return 服务器状态实体对象
|
||||||
|
* @throws IOException 如果连接失败或发生 IO 错误
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(String s, Integer i)
|
||||||
|
throws IOException {
|
||||||
|
return getServerStatus(NetworkEndpoint.of(s, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 NetworkEndpoint 实例连接到 Minecraft 服务器并获取其状态信息。
|
||||||
|
*
|
||||||
|
* @param e 网络端点实例,包含主机和端口信息
|
||||||
|
* @return 服务器状态实体对象
|
||||||
|
* @throws IOException 如果连接失败或发生 IO 错误
|
||||||
|
* @see NetworkEndpoint
|
||||||
|
*/
|
||||||
|
public static MinecraftServerStatus getServerStatus(NetworkEndpoint e)
|
||||||
|
throws IOException {
|
||||||
|
Socket socket = getNewConnect(e); // 建立 TCP 连接
|
||||||
|
OutputStream out = socket.getOutputStream(); // 获取输出流发送数据
|
||||||
|
DataInputStream in = new DataInputStream(socket.getInputStream()); // 获取输入流接收数据
|
||||||
|
out.write(getHandshakePack(e.getHost(), e.getPort(), 1)); // 发送握手包
|
||||||
|
out.write(getStatusPack()); // 发送状态请求包
|
||||||
|
return getStatusJsonEntity(in); // 读取并解析服务器响应
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 Version.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.minecraft.slp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Version {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private int protocol;
|
||||||
|
}
|
||||||
218
src/main/java/com/mingliqiye/utils/network/NetworkAddress.java
Normal file
218
src/main/java/com/mingliqiye/utils/network/NetworkAddress.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* 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 NetworkAddress.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.network;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.string.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络地址类,用于表示一个网络地址(IP或域名),并提供相关操作。
|
||||||
|
* 支持IPv4和IPv6地址的解析与验证。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class NetworkAddress implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6标识
|
||||||
|
*/
|
||||||
|
public static int IPV6 = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv4标识
|
||||||
|
*/
|
||||||
|
public static int IPV4 = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv4地址正则表达式
|
||||||
|
*/
|
||||||
|
static String IPV4REG =
|
||||||
|
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" +
|
||||||
|
"(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译后的IPv4地址匹配模式
|
||||||
|
*/
|
||||||
|
private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4REG);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6地址正则表达式
|
||||||
|
*/
|
||||||
|
static String IPV6REG =
|
||||||
|
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" +
|
||||||
|
"^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" +
|
||||||
|
"|" +
|
||||||
|
"^(::)$|" +
|
||||||
|
"^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" +
|
||||||
|
"^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" +
|
||||||
|
"^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" +
|
||||||
|
"^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编译后的IPv6地址匹配模式
|
||||||
|
*/
|
||||||
|
private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6REG);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP地址类型:4 表示 IPv4,6 表示 IPv6
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private int IPv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP地址字符串
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 域名(如果输入的是域名)
|
||||||
|
*/
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标识是否是域名解析来的IP
|
||||||
|
*/
|
||||||
|
private boolean isdom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法,根据传入的字符串判断是IP地址还是域名,并进行相应处理。
|
||||||
|
*
|
||||||
|
* @param domip 可能是IP地址或域名的字符串
|
||||||
|
*/
|
||||||
|
NetworkAddress(String domip) {
|
||||||
|
try {
|
||||||
|
// 尝试将输入识别为IP地址
|
||||||
|
IPv = testIp(domip);
|
||||||
|
ip = domip;
|
||||||
|
} catch (NetworkException e) {
|
||||||
|
try {
|
||||||
|
// 如果不是有效IP,则尝试作为域名解析
|
||||||
|
String ips = getHostIp(domip);
|
||||||
|
IPv = testIp(ips);
|
||||||
|
ip = ips;
|
||||||
|
isdom = true;
|
||||||
|
domain = domip;
|
||||||
|
} catch (UnknownHostException ex) {
|
||||||
|
throw new NetworkException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态工厂方法,创建 NetworkAddress 实例。
|
||||||
|
*
|
||||||
|
* @param domip 可能是IP地址或域名的字符串
|
||||||
|
* @return 新建的 NetworkAddress 实例
|
||||||
|
*/
|
||||||
|
public static NetworkAddress of(String domip) {
|
||||||
|
return new NetworkAddress(domip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。
|
||||||
|
*
|
||||||
|
* @param inetAddress InetAddress 对象
|
||||||
|
* @return 新建的 NetworkAddress 实例
|
||||||
|
*/
|
||||||
|
public static NetworkAddress of(InetAddress inetAddress) {
|
||||||
|
return new NetworkAddress(inetAddress.getHostAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从DNS服务器解析域名获取对应的IP地址。
|
||||||
|
*
|
||||||
|
* @param domain 域名
|
||||||
|
* @return 解析出的第一个IP地址
|
||||||
|
* @throws UnknownHostException 如果域名无法解析
|
||||||
|
*/
|
||||||
|
public static String getHostIp(@NotNull String domain)
|
||||||
|
throws UnknownHostException {
|
||||||
|
InetAddress[] addresses = InetAddress.getAllByName(domain.trim());
|
||||||
|
return addresses[0].getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测给定字符串是否为有效的IPv4或IPv6地址。
|
||||||
|
*
|
||||||
|
* @param ip 要检测的IP地址字符串
|
||||||
|
* @return 4 表示IPv4,6 表示IPv6
|
||||||
|
* @throws NetworkException 如果IP格式无效
|
||||||
|
*/
|
||||||
|
public static int testIp(String ip) {
|
||||||
|
if (ip == null) {
|
||||||
|
throw new NetworkException("IP地址不能为null");
|
||||||
|
}
|
||||||
|
String trimmedIp = ip.trim();
|
||||||
|
|
||||||
|
// 判断是否匹配IPv4格式
|
||||||
|
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
|
||||||
|
return IPV4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否匹配IPv6格式
|
||||||
|
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
|
||||||
|
return IPV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不符合任一格式时抛出异常
|
||||||
|
throw new NetworkException(
|
||||||
|
StringUtils.format("[{}] 不是有效的IPv4或IPv6地址", ip)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前 NetworkAddress 转换为 InetAddress 对象。
|
||||||
|
*
|
||||||
|
* @return InetAddress 对象
|
||||||
|
*/
|
||||||
|
public InetAddress toInetAddress() {
|
||||||
|
try {
|
||||||
|
return InetAddress.getByName(ip != null ? ip : domain);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回 NetworkAddress 的字符串表示形式。
|
||||||
|
*
|
||||||
|
* @return 字符串表示
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return isdom
|
||||||
|
? StringUtils.format(
|
||||||
|
"NetworkAddress(IP='{}',type='{}'," + "domain='{}')",
|
||||||
|
ip,
|
||||||
|
IPv,
|
||||||
|
domain
|
||||||
|
)
|
||||||
|
: StringUtils.format("NetworkAddress(IP='{}',type='{}')", ip, IPv);
|
||||||
|
}
|
||||||
|
}
|
||||||
164
src/main/java/com/mingliqiye/utils/network/NetworkEndpoint.java
Normal file
164
src/main/java/com/mingliqiye/utils/network/NetworkEndpoint.java
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* 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 NetworkEndpoint.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.network;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.string.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP和端口聚集类,用于封装网络地址与端口信息。
|
||||||
|
* 该类提供了与InetSocketAddress之间的相互转换功能。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
* @see InetSocketAddress
|
||||||
|
*/
|
||||||
|
public class NetworkEndpoint implements Serializable {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final NetworkAddress networkAddress;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final NetworkPort networkPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,使用指定的网络地址和端口创建NetworkEndpoint实例。
|
||||||
|
*
|
||||||
|
* @param networkAddress 网络地址对象
|
||||||
|
* @param networkPort 网络端口对象
|
||||||
|
* @see NetworkAddress
|
||||||
|
* @see NetworkPort
|
||||||
|
*/
|
||||||
|
private NetworkEndpoint(
|
||||||
|
NetworkAddress networkAddress,
|
||||||
|
NetworkPort networkPort
|
||||||
|
) {
|
||||||
|
this.networkAddress = networkAddress;
|
||||||
|
this.networkPort = networkPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例。
|
||||||
|
*
|
||||||
|
* @param address InetSocketAddress对象
|
||||||
|
* @return 新建的NetworkEndpoint实例
|
||||||
|
* @see InetSocketAddress
|
||||||
|
*/
|
||||||
|
public static NetworkEndpoint of(InetSocketAddress address) {
|
||||||
|
return new NetworkEndpoint(
|
||||||
|
new NetworkAddress(address.getHostString()),
|
||||||
|
new NetworkPort(address.getPort())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例。
|
||||||
|
*
|
||||||
|
* @param s 主机名或IP地址字符串
|
||||||
|
* @param i 端口号
|
||||||
|
* @return 新建的NetworkEndpoint实例
|
||||||
|
*/
|
||||||
|
public static NetworkEndpoint of(String s, Integer i) {
|
||||||
|
NetworkAddress networkAddress = new NetworkAddress(s);
|
||||||
|
NetworkPort networkPort = new NetworkPort(i);
|
||||||
|
return new NetworkEndpoint(networkAddress, networkPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据"host:port"格式的字符串创建NetworkEndpoint实例。
|
||||||
|
* 例如:"127.0.0.1:8080"
|
||||||
|
*
|
||||||
|
* @param s "host:port"格式的字符串
|
||||||
|
* @return 新建的NetworkEndpoint实例
|
||||||
|
*/
|
||||||
|
public static NetworkEndpoint of(String s) {
|
||||||
|
// 查找最后一个冒号的位置,以支持IPv6地址中的冒号
|
||||||
|
int lastColonIndex = s.lastIndexOf(':');
|
||||||
|
return of(
|
||||||
|
s.substring(0, lastColonIndex),
|
||||||
|
Integer.parseInt(s.substring(lastColonIndex + 1))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前NetworkEndpoint转换为InetSocketAddress对象。
|
||||||
|
*
|
||||||
|
* @return 对应的InetSocketAddress对象
|
||||||
|
* @see InetSocketAddress
|
||||||
|
*/
|
||||||
|
public InetSocketAddress toInetSocketAddress() {
|
||||||
|
return new InetSocketAddress(
|
||||||
|
networkAddress.toInetAddress(),
|
||||||
|
networkPort.getPort()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前NetworkEndpoint转换为"host:port"格式的字符串。
|
||||||
|
* 例如:"127.0.0.1:25563"
|
||||||
|
*
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
public String toHostPortString() {
|
||||||
|
return StringUtils.format(
|
||||||
|
"{}:{}",
|
||||||
|
networkAddress.getIp(),
|
||||||
|
networkPort.getPort()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回NetworkEndpoint的详细字符串表示形式。
|
||||||
|
* 格式:NetworkEndpoint(IP=...,Port=...,Endpoint=...)
|
||||||
|
*
|
||||||
|
* @return 包含详细信息的字符串
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return StringUtils.format(
|
||||||
|
"NetworkEndpoint(IP={},Port={},Endpoint={})",
|
||||||
|
networkAddress.getIp(),
|
||||||
|
networkPort.getPort(),
|
||||||
|
toHostPortString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取主机名或IP地址字符串。
|
||||||
|
*
|
||||||
|
* @return 主机名或IP地址
|
||||||
|
*/
|
||||||
|
public String getHost() {
|
||||||
|
return networkAddress.getIp();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取端口号。
|
||||||
|
*
|
||||||
|
* @return 端口号
|
||||||
|
*/
|
||||||
|
public Integer getPort() {
|
||||||
|
return networkPort.getPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,28 +15,35 @@
|
|||||||
*
|
*
|
||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile QueryWrapper.kt
|
* CurrentFile NetworkException.java
|
||||||
* LastUpdate 2025-09-20 14:21:44
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.mingliqiye.utils.mybatisplus
|
package com.mingliqiye.utils.network;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BaseMapperQuery接口扩展了BaseMapper,提供了通用的查询包装器功能
|
* 网络异常类,用于处理网络相关的运行时异常
|
||||||
*
|
*
|
||||||
* @param T 实体类类型
|
* @author MingLiPro
|
||||||
*/
|
*/
|
||||||
interface BaseMapperQuery<T> : BaseMapper<T> {
|
public class NetworkException extends RuntimeException {
|
||||||
/**
|
|
||||||
* 创建并返回一个新的QueryWrapper实例
|
/**
|
||||||
*
|
* 构造一个带有指定详细消息的网络异常
|
||||||
* @return QueryWrapper<T> 返回类型化的查询包装器实例
|
*
|
||||||
*/
|
* @param message 异常的详细消息
|
||||||
fun queryWrapper(): QueryWrapper<T> {
|
*/
|
||||||
return QueryWrapper<T>()
|
public NetworkException(String message) {
|
||||||
}
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个网络异常,指定原因异常
|
||||||
|
*
|
||||||
|
* @param e 导致此异常的原因异常
|
||||||
|
*/
|
||||||
|
public NetworkException(Exception e) {
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
64
src/main/java/com/mingliqiye/utils/network/NetworkPort.java
Normal file
64
src/main/java/com/mingliqiye/utils/network/NetworkPort.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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 NetworkPort.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.network;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.string.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络端口类
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class NetworkPort implements Serializable {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,创建一个网络端口对象
|
||||||
|
*
|
||||||
|
* @param port 端口号,必须在0-65535范围内
|
||||||
|
*/
|
||||||
|
public NetworkPort(int port) {
|
||||||
|
testPort(port);
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证端口号是否合法
|
||||||
|
*
|
||||||
|
* @param port 待验证的端口号
|
||||||
|
* @throws NetworkException 当端口号不在合法范围(0-65535)内时抛出异常
|
||||||
|
*/
|
||||||
|
public static void testPort(int port) {
|
||||||
|
// 验证端口号范围是否在0-65535之间
|
||||||
|
if (!(0 <= port && 65535 >= port)) {
|
||||||
|
throw new NetworkException(
|
||||||
|
StringUtils.format("{} 不是正确的端口号", port)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
229
src/main/java/com/mingliqiye/utils/path/OsPath.java
Normal file
229
src/main/java/com/mingliqiye/utils/path/OsPath.java
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* 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 OsPath.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.path;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class OsPath implements Path {
|
||||||
|
|
||||||
|
private final Path path;
|
||||||
|
|
||||||
|
private OsPath(Path path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsPath of(String path) {
|
||||||
|
return of(Paths.get(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsPath of(Path path) {
|
||||||
|
return new OsPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsPath of(URI uri) {
|
||||||
|
return new OsPath(Paths.get(uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsPath of(File file) {
|
||||||
|
return new OsPath(file.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsPath getCwd() {
|
||||||
|
return new OsPath(Paths.get(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull FileSystem getFileSystem() {
|
||||||
|
return path.getFileSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAbsolute() {
|
||||||
|
return path.isAbsolute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getRoot() {
|
||||||
|
return path.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getFileName() {
|
||||||
|
return path.getFileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getParent() {
|
||||||
|
Path a = path.getParent();
|
||||||
|
if (a == null) {
|
||||||
|
a = path.toAbsolutePath().getParent();
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNameCount() {
|
||||||
|
return path.getNameCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path getName(int index) {
|
||||||
|
return path.getName(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path subpath(int beginIndex, int endIndex) {
|
||||||
|
return path.subpath(beginIndex, endIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startsWith(@NotNull Path other) {
|
||||||
|
return path.startsWith(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startsWith(@NotNull String other) {
|
||||||
|
return path.startsWith(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean endsWith(@NotNull Path other) {
|
||||||
|
return path.endsWith(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean endsWith(@NotNull String other) {
|
||||||
|
return path.endsWith(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path normalize() {
|
||||||
|
return path.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path resolve(@NotNull Path other) {
|
||||||
|
return path.resolve(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path resolve(@NotNull String other) {
|
||||||
|
return path.resolve(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path resolveSibling(@NotNull Path other) {
|
||||||
|
return path.resolveSibling(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path resolveSibling(@NotNull String other) {
|
||||||
|
return path.resolveSibling(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path relativize(@NotNull Path other) {
|
||||||
|
return path.relativize(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull URI toUri() {
|
||||||
|
return path.toUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path toAbsolutePath() {
|
||||||
|
return path.toAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Path toRealPath(@NotNull LinkOption... options)
|
||||||
|
throws IOException {
|
||||||
|
return path.toRealPath(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull File toFile() {
|
||||||
|
return path.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull WatchKey register(
|
||||||
|
@NotNull WatchService watcher,
|
||||||
|
WatchEvent.@NotNull Kind<?>[] events,
|
||||||
|
@NotNull WatchEvent.Modifier... modifiers
|
||||||
|
) throws IOException {
|
||||||
|
return path.register(watcher, events, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull WatchKey register(
|
||||||
|
@NotNull WatchService watcher,
|
||||||
|
WatchEvent.@NotNull Kind<?>... events
|
||||||
|
) throws IOException {
|
||||||
|
return path.register(watcher, events);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Iterator<@NotNull Path> iterator() {
|
||||||
|
return path.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Path other) {
|
||||||
|
return path.compareTo(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return path.equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return path.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String toString() {
|
||||||
|
return path.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(Consumer<? super Path> action) {
|
||||||
|
path.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spliterator<Path> spliterator() {
|
||||||
|
return path.spliterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.mingliqiye.utils.springboot.converters;
|
||||||
|
|
||||||
|
import static com.mingliqiye.utils.time.Formatter.STANDARD_DATETIME;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.time.DateTime;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring boot DateTime到字符串转换器
|
||||||
|
*
|
||||||
|
* @author MingliPro
|
||||||
|
* @see DateTime
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DateTimeToStringConverter implements Converter<DateTime, String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(@NotNull DateTime source) {
|
||||||
|
return source.format(STANDARD_DATETIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.mingliqiye.utils.springboot.converters;
|
||||||
|
|
||||||
|
import static com.mingliqiye.utils.time.Formatter.STANDARD_DATETIME_MILLISECOUND7;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.time.DateTime;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring boot 字符串到DateTime转换器
|
||||||
|
*
|
||||||
|
* @author MingliPro
|
||||||
|
* @see DateTime
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class StringToDateTimeConverter implements Converter<String, DateTime> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DateTime convert(@NotNull String source) {
|
||||||
|
return DateTime.parse(source, STANDARD_DATETIME_MILLISECOUND7, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.mingliqiye.utils.springboot.converters;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.uuid.UUID;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring boot 字符串到UUID转换器
|
||||||
|
* @see UUID
|
||||||
|
* @author MingliPro
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class StringToUUIDConverter implements Converter<String, UUID> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID convert(@NotNull String source) {
|
||||||
|
return UUID.of(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package com.mingliqiye.utils.springboot.converters;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.uuid.UUID;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring boot UUID到字符串转换器
|
||||||
|
* @see UUID
|
||||||
|
* @author MingliPro
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class UUIDToStringConverter implements Converter<UUID, String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convert(@NotNull UUID source) {
|
||||||
|
return source.toUUIDString();
|
||||||
|
}
|
||||||
|
}
|
||||||
279
src/main/java/com/mingliqiye/utils/stream/InOutSteam.java
Normal file
279
src/main/java/com/mingliqiye/utils/stream/InOutSteam.java
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
package com.mingliqiye.utils.stream;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义的输入输出流工具类,支持线程安全的数据读写操作。<br>
|
||||||
|
* 谁闲着没事干用本地输入输出<br>
|
||||||
|
* 实现了 AutoCloseable、Closeable 和 Flushable 接口,便于资源管理。
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public class InOutSteam implements AutoCloseable, Closeable, Flushable {
|
||||||
|
|
||||||
|
private final Lock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
List<Byte> bytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从内部缓冲区中读取最多 len 个字节到指定的字节数组 b 中。
|
||||||
|
*
|
||||||
|
* @param b 目标字节数组,用于存储读取的数据
|
||||||
|
* @param off 起始偏移位置
|
||||||
|
* @param len 最大读取字节数
|
||||||
|
* @return 实际读取的字节数;如果已到达流末尾,则返回 -1
|
||||||
|
* @throws IndexOutOfBoundsException 如果 off 或 len 参数非法
|
||||||
|
*/
|
||||||
|
public int read(byte@NotNull [] b, int off, int len) {
|
||||||
|
if (bytes == null) return -1;
|
||||||
|
if (bytes.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off < 0 || len < 0 || off + len > b.length) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
int bytesRead = Math.min(len, bytes.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < bytesRead; i++) {
|
||||||
|
b[off + i] = bytes.get(i);
|
||||||
|
}
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
bytes.subList(0, bytesRead).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取一个字节的数据。
|
||||||
|
*
|
||||||
|
* @return 下一个字节数据(0~255),如果已到达流末尾则返回 -1
|
||||||
|
*/
|
||||||
|
public int read() {
|
||||||
|
if (bytes == null) return -1;
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
if (bytes.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return bytes.remove(0);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从内部缓冲区中读取最多 b.length 个字节到指定的字节数组 b 中。
|
||||||
|
*
|
||||||
|
* @param b 目标字节数组,用于存储读取的数据
|
||||||
|
* @return 实际读取的字节数;如果已到达流末尾,则返回 -1
|
||||||
|
*/
|
||||||
|
public int read(byte@NotNull [] b) {
|
||||||
|
if (bytes == null) return -1;
|
||||||
|
return read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳过并丢弃此输入流中数据的 n 个字节。
|
||||||
|
*
|
||||||
|
* @param n 要跳过的字节数
|
||||||
|
* @return 实际跳过的字节数
|
||||||
|
*/
|
||||||
|
public long skip(long n) {
|
||||||
|
if (bytes == null) return -1;
|
||||||
|
if (bytes.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
if (n <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long bytesToSkip = Math.min(n, bytes.size());
|
||||||
|
|
||||||
|
// 移除跳过的字节
|
||||||
|
if (bytesToSkip > 0) {
|
||||||
|
bytes.subList(0, (int) bytesToSkip).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesToSkip;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
|
||||||
|
*
|
||||||
|
* @return 可以无阻塞读取的字节数
|
||||||
|
*/
|
||||||
|
public int available() {
|
||||||
|
if (bytes == null) return -1;
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
return bytes.size();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取与当前对象关联的 InputStream 实例。
|
||||||
|
*
|
||||||
|
* @return InputStream 实例
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
if (inputStream == null) {
|
||||||
|
inputStream = inputStream();
|
||||||
|
}
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream inputStream;
|
||||||
|
private OutputStream outputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取与当前对象关联的 OutputStream 实例。
|
||||||
|
*
|
||||||
|
* @return OutputStream 实例
|
||||||
|
*/
|
||||||
|
public OutputStream getOutputStream() {
|
||||||
|
if (outputStream == null) {
|
||||||
|
outputStream = outputStream();
|
||||||
|
}
|
||||||
|
return outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建并返回一个包装后的 InputStream 实例。
|
||||||
|
*
|
||||||
|
* @return 新创建的 InputStream 实例
|
||||||
|
*/
|
||||||
|
private InputStream inputStream() {
|
||||||
|
return new InputStreanWrapper(
|
||||||
|
new InputStream() {
|
||||||
|
@Override
|
||||||
|
public int read() {
|
||||||
|
return InOutSteam.this.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte@NotNull [] b, int off, int len) {
|
||||||
|
return InOutSteam.this.read(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) {
|
||||||
|
return InOutSteam.this.skip(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int available() {
|
||||||
|
return InOutSteam.this.available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建并返回一个 OutputStream 实例。
|
||||||
|
*
|
||||||
|
* @return 新创建的 OutputStream 实例
|
||||||
|
*/
|
||||||
|
private OutputStream outputStream() {
|
||||||
|
return new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
InOutSteam.this.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte@NotNull [] b, int off, int len) {
|
||||||
|
InOutSteam.this.write(b, off, len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数,初始化内部字节列表。
|
||||||
|
*/
|
||||||
|
public InOutSteam() {
|
||||||
|
bytes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定的字节写入此输出流。
|
||||||
|
*
|
||||||
|
* @param b 要写入的字节
|
||||||
|
*/
|
||||||
|
public void write(int b) {
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
bytes.add((byte) b);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定字节数组中的部分数据写入此输出流。
|
||||||
|
*
|
||||||
|
* @param b 数据源字节数组
|
||||||
|
* @param off 起始偏移位置
|
||||||
|
* @param len 写入的字节数
|
||||||
|
* @throws IndexOutOfBoundsException 如果 off 或 len 参数非法
|
||||||
|
*/
|
||||||
|
public void write(byte@NotNull [] b, int off, int len) {
|
||||||
|
if (off < 0 || len < 0 || off + len > b.length) {
|
||||||
|
throw new IndexOutOfBoundsException("Invalid offset or length");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
for (int i = off; i < off + len; i++) {
|
||||||
|
bytes.add(b[i]);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将整个字节数组写入此输出流。
|
||||||
|
*
|
||||||
|
* @param b 要写入的字节数组
|
||||||
|
*/
|
||||||
|
public void write(byte@NotNull [] b) {
|
||||||
|
write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新此输出流并强制写出所有缓冲的输出字节。
|
||||||
|
* 当前实现为空方法。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void flush() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭此流并释放与其相关的所有资源。
|
||||||
|
* 清空并置空内部字节列表。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
bytes.clear();
|
||||||
|
bytes = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
package com.mingliqiye.utils.stream;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.collection.Lists;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入流工具类,提供对InputStream的常用操作封装
|
||||||
|
*/
|
||||||
|
public class InputStreamUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认缓冲区大小:1MB
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将输入流读取到字节数组中<br>
|
||||||
|
* 请在外部自行关闭输入流对象 避免资源泄露
|
||||||
|
*
|
||||||
|
* @param inputStream 输入流对象,用于读取数据
|
||||||
|
* @return 包含输入流所有数据的字节数组
|
||||||
|
* @throws IOException 当读取输入流或写入输出流时发生IO异常
|
||||||
|
*/
|
||||||
|
public static byte[] readToArray(InputStream inputStream)
|
||||||
|
throws IOException {
|
||||||
|
// 使用ByteArrayOutputStream来收集输入流中的所有数据
|
||||||
|
try (val byteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||||
|
val bytes = new byte[DEFAULT_BUFFER_SIZE];
|
||||||
|
int length;
|
||||||
|
// 循环读取输入流数据,直到读取完毕
|
||||||
|
while ((length = inputStream.read(bytes)) != -1) {
|
||||||
|
byteArrayOutputStream.write(bytes, 0, length);
|
||||||
|
}
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将输入流读取到Byte列表中<br>
|
||||||
|
* 请在外部自行关闭输入流对象 避免资源泄露
|
||||||
|
*
|
||||||
|
* @param inputStream 输入流对象,用于读取数据
|
||||||
|
* @return 包含输入流所有数据的Byte列表
|
||||||
|
* @throws IOException 当读取输入流时发生IO异常
|
||||||
|
*/
|
||||||
|
public static List<Byte> readToList(InputStream inputStream)
|
||||||
|
throws IOException {
|
||||||
|
return Lists.toList(readToArray(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将输入流读取为字符串<br>
|
||||||
|
* 请在外部自行关闭输入流对象 避免资源泄露
|
||||||
|
*
|
||||||
|
* @param inputStream 输入流对象,用于读取数据
|
||||||
|
* @return 输入流对应的字符串内容
|
||||||
|
* @throws IOException 当读取输入流时发生IO异常
|
||||||
|
*/
|
||||||
|
public static String readToString(InputStream inputStream)
|
||||||
|
throws IOException {
|
||||||
|
return new String(readToArray(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将输入流的数据传输到输出流中<br>
|
||||||
|
* 请在外部自行关闭输入流输出流对象 避免资源泄露
|
||||||
|
*
|
||||||
|
* @param inputStream 源输入流,用于读取数据
|
||||||
|
* @param outputStream 目标输出流,用于写入数据
|
||||||
|
* @return 传输的总字节数
|
||||||
|
* @throws IOException 当读取或写入流时发生IO异常
|
||||||
|
*/
|
||||||
|
public static long transferTo(
|
||||||
|
InputStream inputStream,
|
||||||
|
OutputStream outputStream
|
||||||
|
) throws IOException {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalArgumentException("inputStream can not be null");
|
||||||
|
}
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IllegalArgumentException("outputStream can not be null");
|
||||||
|
}
|
||||||
|
val bytes = new byte[DEFAULT_BUFFER_SIZE];
|
||||||
|
int length;
|
||||||
|
long readAll = 0L;
|
||||||
|
// 循环读取并写入数据,直到输入流读取完毕
|
||||||
|
while ((length = inputStream.read(bytes)) != -1) {
|
||||||
|
outputStream.write(bytes, 0, length);
|
||||||
|
readAll += length;
|
||||||
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
return readAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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 InputStreanWrapper.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.stream;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class InputStreanWrapper extends InputStream implements AutoCloseable {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final InputStream inputStream;
|
||||||
|
|
||||||
|
public InputStreanWrapper(InputStream inputStream) {
|
||||||
|
this.inputStream = inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStreanWrapper of(InputStream inputStream) {
|
||||||
|
return new InputStreanWrapper(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int available() throws IOException {
|
||||||
|
return inputStream.available();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return inputStream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte@NotNull [] b) throws IOException {
|
||||||
|
return inputStream.read(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte@NotNull [] b, int off, int len) throws IOException {
|
||||||
|
return inputStream.read(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
return inputStream.skip(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mark(int readlimit) {
|
||||||
|
inputStream.mark(readlimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() throws IOException {
|
||||||
|
inputStream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return inputStream.markSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输入流转换为输出流 <br>
|
||||||
|
* jdk8 兼容实现 jdk9+ <br>
|
||||||
|
* 请使用 InputStream.transferTo()
|
||||||
|
*
|
||||||
|
* @param outputStream 输出流
|
||||||
|
* @return 转换的字节数
|
||||||
|
* @throws IOException IO错误
|
||||||
|
*/
|
||||||
|
public long transferToOutputStream(OutputStream outputStream)
|
||||||
|
throws IOException {
|
||||||
|
return InputStreamUtils.transferTo(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] readToArray() throws IOException {
|
||||||
|
return InputStreamUtils.readToArray(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Byte> readToList() throws IOException {
|
||||||
|
return InputStreamUtils.readToList(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String readToString() throws IOException {
|
||||||
|
return InputStreamUtils.readToString(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package com.mingliqiye.utils.stream;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class OutputStreamWrapper extends OutputStream implements AutoCloseable {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final OutputStream outputStream;
|
||||||
|
|
||||||
|
private final ByteArrayOutputStream byteArrayOutputStream =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
public OutputStreamWrapper(OutputStream outputStream) {
|
||||||
|
this.outputStream = outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OutputStreamWrapper of(OutputStream outputStream) {
|
||||||
|
return new OutputStreamWrapper(outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
byteArrayOutputStream.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte@NotNull [] b) throws IOException {
|
||||||
|
byteArrayOutputStream.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(List<Byte> b) throws IOException {
|
||||||
|
write(b, 0, b.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte@NotNull [] b, int off, int len) throws IOException {
|
||||||
|
byteArrayOutputStream.write(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(List<Byte> b, int off, int len) throws IOException {
|
||||||
|
byte[] bytes = new byte[b.size()];
|
||||||
|
for (int i = 0; i < b.size(); i++) {
|
||||||
|
bytes[i] = b.get(i);
|
||||||
|
}
|
||||||
|
byteArrayOutputStream.write(bytes, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
outputStream.write(byteArrayOutputStream.toByteArray());
|
||||||
|
byteArrayOutputStream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBufferCachedSize() {
|
||||||
|
return byteArrayOutputStream.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBufferCachedBytes() {
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long transferFromOutputStream(InputStream inputStream)
|
||||||
|
throws IOException {
|
||||||
|
return InputStreamUtils.transferTo(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,9 @@
|
|||||||
|
package com.mingliqiye.utils.stream.interfaces;
|
||||||
|
|
||||||
|
public interface GetIdable<T> extends Getable<T> {
|
||||||
|
T getId();
|
||||||
|
|
||||||
|
default T get() {
|
||||||
|
return getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.mingliqiye.utils.stream.interfaces;
|
||||||
|
|
||||||
|
public interface GetKeyable<T> {
|
||||||
|
T getKey();
|
||||||
|
|
||||||
|
default T get() {
|
||||||
|
return getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.mingliqiye.utils.stream.interfaces;
|
||||||
|
|
||||||
|
public interface GetNameable<T> extends Getable<T> {
|
||||||
|
T getName();
|
||||||
|
|
||||||
|
default T get() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.mingliqiye.utils.stream.interfaces;
|
||||||
|
|
||||||
|
public interface Getable<T> {
|
||||||
|
T get();
|
||||||
|
}
|
||||||
561
src/main/java/com/mingliqiye/utils/time/DateTime.java
Normal file
561
src/main/java/com/mingliqiye/utils/time/DateTime.java
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
/*
|
||||||
|
* 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 DateTime.java
|
||||||
|
* LastUpdate 2025-09-14 22:12:16
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.time;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.jna.WinKernel32Api;
|
||||||
|
import com.mingliqiye.utils.jna.WinKernel32ApiFactory;
|
||||||
|
import com.mingliqiye.utils.system.SystemUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.val;
|
||||||
|
import lombok.var;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.FILETIME_EPOCH_OFFSET;
|
||||||
|
import static com.mingliqiye.utils.jna.WinKernel32ApiFactory.NANOS_PER_100NS;
|
||||||
|
import static com.mingliqiye.utils.logger.Loggers.getMingLiLoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间类,用于处理日期时间的转换、格式化等操作。
|
||||||
|
* 提供了多种静态方法来创建 DateTime 实例,并支持与 Date、LocalDateTime 等类型的互转。
|
||||||
|
*<br>
|
||||||
|
* windows java 1.8 及以下 使用windows Api 获取高精度时间
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
* @see java.time
|
||||||
|
* @see LocalDateTime
|
||||||
|
* @see ChronoUnit
|
||||||
|
* @see Date
|
||||||
|
* @see DateTimeFormatter
|
||||||
|
* @see ZoneId
|
||||||
|
* @see Instant
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
public final class DateTime implements Serializable {
|
||||||
|
|
||||||
|
private static final WinKernel32Api WIN_KERNEL_32_API;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (
|
||||||
|
SystemUtils.getJavaVersionAsInteger() == 8 &&
|
||||||
|
SystemUtils.isWindows()
|
||||||
|
) {
|
||||||
|
final Logger log = getMingLiLoggerFactory().getLogger(
|
||||||
|
"mingli-utils DateTime"
|
||||||
|
);
|
||||||
|
val a = WinKernel32ApiFactory.getWinKernel32Apis();
|
||||||
|
|
||||||
|
if (a.size() > 1) {
|
||||||
|
log.warn(
|
||||||
|
"Multiple Size:{} WinKernel32Api implementations found.",
|
||||||
|
a.size()
|
||||||
|
);
|
||||||
|
a.forEach(api ->
|
||||||
|
log.warn(
|
||||||
|
"Found WinKernel32Api: {}",
|
||||||
|
api.getClass().getName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.isEmpty()) {
|
||||||
|
WIN_KERNEL_32_API = null;
|
||||||
|
log.warn(
|
||||||
|
"No WinKernel32Api implementation found. Use Jdk1.8 LocalDateTime"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
WIN_KERNEL_32_API = a.get(a.size() - 1);
|
||||||
|
log.info(
|
||||||
|
"Found and Use WinKernel32Api: {}",
|
||||||
|
WIN_KERNEL_32_API.getClass().getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WIN_KERNEL_32_API = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private ZoneId zoneId = ZoneId.systemDefault();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private LocalDateTime localDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有构造函数,使用指定的 LocalDateTime 初始化实例。
|
||||||
|
*
|
||||||
|
* @param time LocalDateTime 对象
|
||||||
|
*/
|
||||||
|
private DateTime(LocalDateTime time) {
|
||||||
|
setLocalDateTime(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有构造函数,使用当前系统时间初始化实例。
|
||||||
|
*/
|
||||||
|
private DateTime() {
|
||||||
|
setLocalDateTime(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前时间的 DateTime 实例。
|
||||||
|
* 如果运行在 Java 1.8 环境下,则通过 WinKernel32 获取高精度时间。
|
||||||
|
*
|
||||||
|
* @return 返回当前时间的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime now() {
|
||||||
|
if (WIN_KERNEL_32_API != null) {
|
||||||
|
return DateTime.of(
|
||||||
|
WIN_KERNEL_32_API.getTime()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new DateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Date 对象转换为 DateTime 实例。
|
||||||
|
*
|
||||||
|
* @param zoneId 时区信息
|
||||||
|
* @param date Date 对象
|
||||||
|
* @return 返回对应的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(Date date, ZoneId zoneId) {
|
||||||
|
return new DateTime(date.toInstant().atZone(zoneId).toLocalDateTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Date 对象转换为 DateTime 实例,使用系统默认时区。
|
||||||
|
*
|
||||||
|
* @param date Date 对象
|
||||||
|
* @return 返回对应的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(Date date) {
|
||||||
|
return new DateTime(
|
||||||
|
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 LocalDateTime 创建 DateTime 实例。
|
||||||
|
*
|
||||||
|
* @param localDateTime LocalDateTime 对象
|
||||||
|
* @return 返回对应的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(LocalDateTime localDateTime) {
|
||||||
|
return new DateTime(localDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析时间字符串并生成 DateTime 实例。
|
||||||
|
*
|
||||||
|
* @param timestr 时间字符串
|
||||||
|
* @param formatter 格式化模板
|
||||||
|
* @param fillZero 是否补零到模板长度
|
||||||
|
* @return 返回解析后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime parse(
|
||||||
|
String timestr,
|
||||||
|
String formatter,
|
||||||
|
boolean fillZero
|
||||||
|
) {
|
||||||
|
return new DateTime(
|
||||||
|
LocalDateTime.parse(
|
||||||
|
fillZero ? getFillZeroByLen(timestr, formatter) : timestr,
|
||||||
|
DateTimeFormatter.ofPattern(formatter)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例。
|
||||||
|
*
|
||||||
|
* @param timestr 时间字符串
|
||||||
|
* @param formatter 格式化模板枚举
|
||||||
|
* @param fillZero 是否补零到模板长度
|
||||||
|
* @return 返回解析后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime parse(
|
||||||
|
String timestr,
|
||||||
|
Formatter formatter,
|
||||||
|
boolean fillZero
|
||||||
|
) {
|
||||||
|
return parse(timestr, formatter.getValue(), fillZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Formatter 枚举解析时间字符串并生成 DateTime 实例,默认不补零。
|
||||||
|
*
|
||||||
|
* @param timestr 时间字符串
|
||||||
|
* @param formatter 格式化模板枚举
|
||||||
|
* @return 返回解析后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime parse(String timestr, Formatter formatter) {
|
||||||
|
return parse(timestr, formatter.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析时间字符串并生成 DateTime 实例,默认不补零。
|
||||||
|
*
|
||||||
|
* @param timestr 时间字符串
|
||||||
|
* @param formatter 格式化模板
|
||||||
|
* @return 返回解析后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime parse(String timestr, String formatter) {
|
||||||
|
return parse(timestr, formatter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补零处理时间字符串以匹配格式化模板长度。
|
||||||
|
*
|
||||||
|
* @param dstr 原始时间字符串
|
||||||
|
* @param formats 格式化模板
|
||||||
|
* @return 补零后的时间字符串
|
||||||
|
*/
|
||||||
|
private static String getFillZeroByLen(String dstr, String formats) {
|
||||||
|
if (dstr.length() == formats.length()) {
|
||||||
|
return dstr;
|
||||||
|
}
|
||||||
|
if (formats.length() > dstr.length()) {
|
||||||
|
if (dstr.length() == 19) {
|
||||||
|
dstr += ".";
|
||||||
|
}
|
||||||
|
var sb = new StringBuilder(dstr);
|
||||||
|
for (int i = 0; i < formats.length() - dstr.length(); i++) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Text: '%s' len %s < %s %s",
|
||||||
|
dstr,
|
||||||
|
dstr.length(),
|
||||||
|
formats,
|
||||||
|
formats.length()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据年、月、日创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param year 年份
|
||||||
|
* @param month 月份 (1-12)
|
||||||
|
* @param day 日期 (1-31)
|
||||||
|
* @return 返回指定日期的 DateTime 实例(时间部分为 00:00:00)
|
||||||
|
*/
|
||||||
|
public static DateTime of(int year, int month, int day) {
|
||||||
|
return new DateTime(LocalDateTime.of(year, month, day, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据年、月、日、时、分创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param year 年份
|
||||||
|
* @param month 月份 (1-12)
|
||||||
|
* @param day 日期 (1-31)
|
||||||
|
* @param hour 小时 (0-23)
|
||||||
|
* @param minute 分钟 (0-59)
|
||||||
|
* @return 返回指定日期时间的 DateTime 实例(秒部分为 00)
|
||||||
|
*/
|
||||||
|
public static DateTime of(
|
||||||
|
int year,
|
||||||
|
int month,
|
||||||
|
int day,
|
||||||
|
int hour,
|
||||||
|
int minute
|
||||||
|
) {
|
||||||
|
return new DateTime(LocalDateTime.of(year, month, day, hour, minute));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 FILETIME 转换为 LocalDateTime。
|
||||||
|
*
|
||||||
|
* @param fileTime FILETIME 时间戳(100纳秒单位自1601年1月1日起)
|
||||||
|
* @return 转换后的 LocalDateTime 实例
|
||||||
|
*/
|
||||||
|
public static LocalDateTime fileTimeToLocalDateTime(long fileTime) {
|
||||||
|
// 1. 将 FILETIME (100ns间隔 since 1601) 转换为 Unix 时间戳 (纳秒 since 1970)
|
||||||
|
long unixNanos = (fileTime + FILETIME_EPOCH_OFFSET) * NANOS_PER_100NS;
|
||||||
|
|
||||||
|
// 2. 从纳秒时间戳创建 Instant
|
||||||
|
Instant instant = Instant.ofEpochSecond(
|
||||||
|
unixNanos / 1_000_000_000L,
|
||||||
|
unixNanos % 1_000_000_000L
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. 转换为系统默认时区的 LocalDateTime
|
||||||
|
return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据年、月、日、时、分、秒创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param year 年份
|
||||||
|
* @param month 月份 (1-12)
|
||||||
|
* @param day 日期 (1-31)
|
||||||
|
* @param hour 小时 (0-23)
|
||||||
|
* @param minute 分钟 (0-59)
|
||||||
|
* @param second 秒 (0-59)
|
||||||
|
* @return 返回指定日期时间的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(
|
||||||
|
int year,
|
||||||
|
int month,
|
||||||
|
int day,
|
||||||
|
int hour,
|
||||||
|
int minute,
|
||||||
|
int second
|
||||||
|
) {
|
||||||
|
return new DateTime(
|
||||||
|
LocalDateTime.of(year, month, day, hour, minute, second)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据年、月、日、时、分、秒、纳秒创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param year 年份
|
||||||
|
* @param month 月份 (1-12)
|
||||||
|
* @param day 日期 (1-31)
|
||||||
|
* @param hour 小时 (0-23)
|
||||||
|
* @param minute 分钟 (0-59)
|
||||||
|
* @param second 秒 (0-59)
|
||||||
|
* @param nano 纳秒 (0-999,999,999)
|
||||||
|
* @return 返回指定日期时间的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(
|
||||||
|
int year,
|
||||||
|
int month,
|
||||||
|
int day,
|
||||||
|
int hour,
|
||||||
|
int minute,
|
||||||
|
int second,
|
||||||
|
int nano
|
||||||
|
) {
|
||||||
|
return new DateTime(
|
||||||
|
LocalDateTime.of(year, month, day, hour, minute, second, nano)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据毫秒时间戳创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param epochMilli 毫秒时间戳
|
||||||
|
* @return 返回对应时间的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(long epochMilli) {
|
||||||
|
return new DateTime(
|
||||||
|
Instant.ofEpochMilli(epochMilli)
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据毫秒时间戳和时区创建 DateTime 实例
|
||||||
|
*
|
||||||
|
* @param epochMilli 毫秒时间戳
|
||||||
|
* @param zoneId 时区信息
|
||||||
|
* @return 返回对应时间的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public static DateTime of(long epochMilli, ZoneId zoneId) {
|
||||||
|
return new DateTime(
|
||||||
|
Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前 DateTime 转换为 Date 对象。
|
||||||
|
*
|
||||||
|
* @return 返回对应的 Date 对象
|
||||||
|
*/
|
||||||
|
public Date toDate() {
|
||||||
|
return Date.from(localDateTime.atZone(getZoneId()).toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前 DateTime 中的 LocalDateTime 实例。
|
||||||
|
*
|
||||||
|
* @return 返回 LocalDateTime 对象
|
||||||
|
*/
|
||||||
|
public LocalDateTime toLocalDateTime() {
|
||||||
|
return localDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在当前时间基础上增加指定的时间偏移量。
|
||||||
|
*
|
||||||
|
* @param dateTimeOffset 时间偏移对象
|
||||||
|
* @return 返回修改后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public DateTime add(DateTimeOffset dateTimeOffset) {
|
||||||
|
return new DateTime(
|
||||||
|
this.localDateTime.plus(
|
||||||
|
dateTimeOffset.getOffset(),
|
||||||
|
dateTimeOffset.getOffsetType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在当前时间基础上减少指定的时间偏移量。
|
||||||
|
*
|
||||||
|
* @param dateTimeOffset 时间偏移对象
|
||||||
|
* @return 返回修改后的 DateTime 实例
|
||||||
|
*/
|
||||||
|
public DateTime sub(DateTimeOffset dateTimeOffset) {
|
||||||
|
return new DateTime(
|
||||||
|
this.localDateTime.plus(
|
||||||
|
-dateTimeOffset.getOffset(),
|
||||||
|
dateTimeOffset.getOffsetType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定格式化模板将当前时间格式化为字符串。
|
||||||
|
*
|
||||||
|
* @param formatter 格式化模板
|
||||||
|
* @return 返回格式化后的时间字符串
|
||||||
|
*/
|
||||||
|
public String format(String formatter) {
|
||||||
|
return format(formatter, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Formatter 枚举将当前时间格式化为字符串。
|
||||||
|
*
|
||||||
|
* @param formatter 格式化模板枚举
|
||||||
|
* @return 返回格式化后的时间字符串
|
||||||
|
*/
|
||||||
|
public String format(Formatter formatter) {
|
||||||
|
return format(formatter.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用指定格式化模板将当前时间格式化为字符串,并可选择是否去除末尾多余的零。
|
||||||
|
*
|
||||||
|
* @param formatter 格式化模板
|
||||||
|
* @param repcZero 是否去除末尾多余的零
|
||||||
|
* @return 返回格式化后的时间字符串
|
||||||
|
*/
|
||||||
|
public String format(String formatter, boolean repcZero) {
|
||||||
|
var formatted = DateTimeFormatter.ofPattern(formatter).format(
|
||||||
|
toLocalDateTime()
|
||||||
|
);
|
||||||
|
if (repcZero) {
|
||||||
|
// 处理小数点后多余的0
|
||||||
|
formatted = formatted.replaceAll("(\\.\\d*?)0+\\b", "$1");
|
||||||
|
formatted = formatted.replaceAll("\\.$", "");
|
||||||
|
}
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Formatter 枚举将当前时间格式化为字符串,并可选择是否去除末尾多余的零。
|
||||||
|
*
|
||||||
|
* @param formatter 格式化模板枚举
|
||||||
|
* @param repcZero 是否去除末尾多余的零
|
||||||
|
* @return 返回格式化后的时间字符串
|
||||||
|
*/
|
||||||
|
public String format(Formatter formatter, boolean repcZero) {
|
||||||
|
return format(formatter.getValue(), repcZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回当前时间的标准字符串表示形式。
|
||||||
|
*
|
||||||
|
* @return 返回标准格式的时间字符串
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"DateTime(%s)",
|
||||||
|
format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较当前DateTime对象与指定对象是否相等
|
||||||
|
*
|
||||||
|
* @param obj 要比较的对象
|
||||||
|
* @return 如果对象相等则返回true,否则返回false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// 检查对象类型是否为DateTime
|
||||||
|
if (obj instanceof DateTime) {
|
||||||
|
// 比较两个DateTime对象转换为LocalDateTime后的值
|
||||||
|
return toLocalDateTime().equals(((DateTime) obj).toLocalDateTime());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前 DateTime 转换为 Instant 对象。
|
||||||
|
*
|
||||||
|
* @return 返回 Instant 对象
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Instant toInstant() {
|
||||||
|
return localDateTime.atZone(zoneId).toInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前时间是否在指定时间之后。
|
||||||
|
*
|
||||||
|
* @param dateTime 指定时间
|
||||||
|
* @return 如果当前时间在指定时间之后则返回 true,否则返回 false
|
||||||
|
*/
|
||||||
|
public boolean isAfter(DateTime dateTime) {
|
||||||
|
if (dateTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return toInstant().isAfter(dateTime.toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前时间是否在指定时间之前。
|
||||||
|
*
|
||||||
|
* @param dateTime 指定时间
|
||||||
|
* @return 如果当前时间在指定时间之前则返回 true,否则返回 false
|
||||||
|
*/
|
||||||
|
public boolean isBefore(DateTime dateTime) {
|
||||||
|
if (dateTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return toInstant().isBefore(dateTime.toInstant());
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main/java/com/mingliqiye/utils/time/DateTimeOffset.java
Normal file
65
src/main/java/com/mingliqiye/utils/time/DateTimeOffset.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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 DateTimeOffset.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.time;
|
||||||
|
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间位移 类
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class DateTimeOffset {
|
||||||
|
|
||||||
|
private final ChronoUnit offsetType;
|
||||||
|
private final Long offset;
|
||||||
|
|
||||||
|
private DateTimeOffset(ChronoUnit offsetType, Long offset) {
|
||||||
|
this.offsetType = offsetType;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的DateTimeOffset实例
|
||||||
|
*
|
||||||
|
* @param offsetType 偏移量的单位类型,指定偏移量的计算单位
|
||||||
|
* @param offset 偏移量的数值,可以为正数、负数或零
|
||||||
|
* @return 返回一个新的DateTimeOffset对象,包含指定的偏移量信息
|
||||||
|
*/
|
||||||
|
public static DateTimeOffset of(ChronoUnit offsetType, Long offset) {
|
||||||
|
return new DateTimeOffset(offsetType, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个 DateTimeOffset 实例
|
||||||
|
*
|
||||||
|
* @param offset 偏移量数值
|
||||||
|
* @param offsetType 偏移量的时间单位类型
|
||||||
|
* @return 返回一个新的 DateTimeOffset 实例
|
||||||
|
*/
|
||||||
|
public static DateTimeOffset of(Long offset, ChronoUnit offsetType) {
|
||||||
|
return new DateTimeOffset(offsetType, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main/java/com/mingliqiye/utils/time/DateTimeUnit.java
Normal file
65
src/main/java/com/mingliqiye/utils/time/DateTimeUnit.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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 DateTimeUnit.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间单位常量定义
|
||||||
|
*
|
||||||
|
* @author MingLiPro
|
||||||
|
*/
|
||||||
|
public interface DateTimeUnit {
|
||||||
|
// 时间单位常量
|
||||||
|
String YEAR = "year";
|
||||||
|
String MONTH = "month";
|
||||||
|
String WEEK = "week";
|
||||||
|
String DAY = "day";
|
||||||
|
String HOUR = "hour";
|
||||||
|
String MINUTE = "minute";
|
||||||
|
String SECOND = "second";
|
||||||
|
String MILLISECOND = "millisecond";
|
||||||
|
String MICROSECOND = "microsecond";
|
||||||
|
String NANOSECOND = "nanosecond";
|
||||||
|
|
||||||
|
// 时间单位缩写
|
||||||
|
String YEAR_ABBR = "y";
|
||||||
|
String MONTH_ABBR = "M";
|
||||||
|
String WEEK_ABBR = "w";
|
||||||
|
String DAY_ABBR = "d";
|
||||||
|
String HOUR_ABBR = "h";
|
||||||
|
String MINUTE_ABBR = "m";
|
||||||
|
String SECOND_ABBR = "s";
|
||||||
|
String MILLISECOND_ABBR = "ms";
|
||||||
|
String MICROSECOND_ABBR = "μs";
|
||||||
|
String NANOSECOND_ABBR = "ns";
|
||||||
|
|
||||||
|
// 时间单位转换系数(毫秒为基准)
|
||||||
|
long MILLIS_PER_SECOND = 1000L;
|
||||||
|
long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
|
||||||
|
long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
|
||||||
|
long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
|
||||||
|
long MILLIS_PER_WEEK = 7 * MILLIS_PER_DAY;
|
||||||
|
|
||||||
|
// 月份和年的毫秒数仅为近似值
|
||||||
|
long MILLIS_PER_MONTH = 30 * MILLIS_PER_DAY; // 近似值
|
||||||
|
long MILLIS_PER_YEAR = 365 * MILLIS_PER_DAY; // 近似值
|
||||||
|
}
|
||||||
115
src/main/java/com/mingliqiye/utils/time/Formatter.java
Normal file
115
src/main/java/com/mingliqiye/utils/time/Formatter.java
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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 Formatter.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.time;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间格式化枚举类
|
||||||
|
* <p>
|
||||||
|
* 定义了常用的时间格式化模式,用于日期时间的解析和格式化操作
|
||||||
|
* 每个枚举常量包含对应的格式化字符串和字符串长度
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum Formatter {
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式:yyyy-MM-dd HH:mm:ss
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME("yyyy-MM-dd HH:mm:ss"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(7位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSSS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND7("yyyy-MM-dd HH:mm:ss.SSSSSSS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(6位毫秒):yyyy-MM-dd HH:mm:ss.SSSSSS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND6("yyyy-MM-dd HH:mm:ss.SSSSSS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(5位毫秒):yyyy-MM-dd HH:mm:ss.SSSSS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND5("yyyy-MM-dd HH:mm:ss.SSSSS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(4位毫秒):yyyy-MM-dd HH:mm:ss.SSSS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND4("yyyy-MM-dd HH:mm:ss.SSSS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(3位毫秒):yyyy-MM-dd HH:mm:ss.SSS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND3("yyyy-MM-dd HH:mm:ss.SSS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(2位毫秒):yyyy-MM-dd HH:mm:ss.SS
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND2("yyyy-MM-dd HH:mm:ss.SS"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间格式(1位毫秒):yyyy-MM-dd HH:mm:ss.S
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_MILLISECOUND1("yyyy-MM-dd HH:mm:ss.S"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准ISO格式:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
|
||||||
|
*/
|
||||||
|
STANDARD_ISO("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期时间秒格式:yyyy-MM-dd HH:mm:ss
|
||||||
|
*/
|
||||||
|
STANDARD_DATETIME_SECOUND("yyyy-MM-dd HH:mm:ss"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准日期格式:yyyy-MM-dd
|
||||||
|
*/
|
||||||
|
STANDARD_DATE("yyyy-MM-dd"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISO8601格式:yyyy-MM-dd'T'HH:mm:ss.SSS'000'
|
||||||
|
*/
|
||||||
|
ISO8601("yyyy-MM-dd'T'HH:mm:ss.SSS'000'"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 紧凑型日期时间格式:yyyyMMddHHmmss
|
||||||
|
*/
|
||||||
|
COMPACT_DATETIME("yyyyMMddHHmmss");
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
*
|
||||||
|
* @param value 格式化模式字符串
|
||||||
|
*/
|
||||||
|
Formatter(String value) {
|
||||||
|
this.value = value;
|
||||||
|
this.len = value.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* 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.java
|
||||||
|
* LastUpdate 2025-09-09 08:37:33
|
||||||
|
* UpdateUser MingLiPro
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.mingliqiye.utils.time.typehandlers;
|
||||||
|
|
||||||
|
import com.mingliqiye.utils.time.DateTime;
|
||||||
|
import com.mingliqiye.utils.time.Formatter;
|
||||||
|
import java.sql.*;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||||
|
import org.apache.ibatis.type.MappedTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateTime类型处理器类
|
||||||
|
* 用于在MyBatis中处理DateTime类型与数据库VARCHAR类型之间的转换
|
||||||
|
*/
|
||||||
|
@MappedTypes({ DateTime.class })
|
||||||
|
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||||
|
public class DateTimeTypeHandler extends BaseTypeHandler<DateTime> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置非空参数值
|
||||||
|
* 将DateTime对象转换为Timestamp并设置到PreparedStatement中
|
||||||
|
*
|
||||||
|
* @param ps PreparedStatement对象
|
||||||
|
* @param i 参数索引位置
|
||||||
|
* @param parameter DateTime参数值
|
||||||
|
* @param jdbcType JDBC类型
|
||||||
|
* @throws SQLException SQL异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(
|
||||||
|
PreparedStatement ps,
|
||||||
|
int i,
|
||||||
|
DateTime parameter,
|
||||||
|
JdbcType jdbcType
|
||||||
|
) throws SQLException {
|
||||||
|
ps.setTimestamp(i, Timestamp.valueOf(parameter.getLocalDateTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从ResultSet中获取可为空的结果值
|
||||||
|
* 根据列名获取字符串值并解析为DateTime对象
|
||||||
|
*
|
||||||
|
* @param rs ResultSet对象
|
||||||
|
* @param columnName 列名
|
||||||
|
* @return DateTime对象,如果值为null则返回null
|
||||||
|
* @throws SQLException SQL异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DateTime getNullableResult(ResultSet rs, String columnName)
|
||||||
|
throws SQLException {
|
||||||
|
return parse(rs.getString(columnName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从ResultSet中获取可为空的结果值
|
||||||
|
* 根据列索引获取字符串值并解析为DateTime对象
|
||||||
|
*
|
||||||
|
* @param rs ResultSet对象
|
||||||
|
* @param columnIndex 列索引
|
||||||
|
* @return DateTime对象,如果值为null则返回null
|
||||||
|
* @throws SQLException SQL异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DateTime getNullableResult(ResultSet rs, int columnIndex)
|
||||||
|
throws SQLException {
|
||||||
|
return parse(rs.getString(columnIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从CallableStatement中获取可为空的结果值
|
||||||
|
* 根据列索引获取字符串值并解析为DateTime对象
|
||||||
|
*
|
||||||
|
* @param cs CallableStatement对象
|
||||||
|
* @param columnIndex 列索引
|
||||||
|
* @return DateTime对象,如果值为null则返回null
|
||||||
|
* @throws SQLException SQL异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DateTime getNullableResult(CallableStatement cs, int columnIndex)
|
||||||
|
throws SQLException {
|
||||||
|
return parse(cs.getString(columnIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析字符串为DateTime对象
|
||||||
|
*
|
||||||
|
* @param s 待解析的字符串
|
||||||
|
* @return DateTime对象,如果字符串为null则返回null
|
||||||
|
*/
|
||||||
|
public DateTime parse(String s) {
|
||||||
|
if (s == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return DateTime.parse(s, Formatter.STANDARD_DATETIME_MILLISECOUND7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化DateTime对象为字符串
|
||||||
|
*
|
||||||
|
* @param t DateTime对象
|
||||||
|
* @return 格式化后的字符串
|
||||||
|
*/
|
||||||
|
public String format(DateTime t) {
|
||||||
|
return t.format(Formatter.STANDARD_DATETIME_MILLISECOUND7);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,20 +16,17 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile Main.kt
|
* CurrentFile Main.kt
|
||||||
* LastUpdate 2025-09-20 13:22:11
|
* LastUpdate 2025-09-14 22:05:03
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:JvmName("Main")
|
@file:JvmName("Main")
|
||||||
|
|
||||||
package com.mingliqiye.utils.main
|
package com.mingliqiye.utils
|
||||||
|
|
||||||
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
||||||
import com.mingliqiye.utils.stream.SuperStream
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
AutoConfiguration.printBanner()
|
AutoConfiguration.printBanner()
|
||||||
val data = SuperStream.of(Array(0) { 1 })
|
|
||||||
|
|
||||||
|
|
||||||
println(data)
|
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@
|
|||||||
* ProjectName mingli-utils
|
* ProjectName mingli-utils
|
||||||
* ModuleName mingli-utils.main
|
* ModuleName mingli-utils.main
|
||||||
* CurrentFile AesUtils.kt
|
* CurrentFile AesUtils.kt
|
||||||
* LastUpdate 2025-09-19 21:35:53
|
* LastUpdate 2025-09-14 18:43:04
|
||||||
* UpdateUser MingLiPro
|
* UpdateUser MingLiPro
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -25,7 +25,8 @@
|
|||||||
|
|
||||||
package com.mingliqiye.utils.aes
|
package com.mingliqiye.utils.aes
|
||||||
|
|
||||||
import com.mingliqiye.utils.base.BASE64
|
import com.mingliqiye.utils.base64.decode
|
||||||
|
import com.mingliqiye.utils.base64.encode
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.security.GeneralSecurityException
|
import java.security.GeneralSecurityException
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@ -71,8 +72,8 @@ fun encrypt(sSrc: String, sKey: String?): String? {
|
|||||||
val encrypted = cipher.doFinal(
|
val encrypted = cipher.doFinal(
|
||||||
sSrc.toByteArray(StandardCharsets.UTF_8)
|
sSrc.toByteArray(StandardCharsets.UTF_8)
|
||||||
)
|
)
|
||||||
return BASE64.encode(
|
return encode(
|
||||||
"${BASE64.encode(iv)}:${BASE64.encode(encrypted)}".toByteArray()
|
"${encode(iv)}:${encode(encrypted)}".toByteArray()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,13 +86,13 @@ fun encrypt(sSrc: String, sKey: String?): String? {
|
|||||||
fun decrypt(sSrc: String, sKey: String): String? {
|
fun decrypt(sSrc: String, sKey: String): String? {
|
||||||
try {
|
try {
|
||||||
// 分割IV和加密数据
|
// 分割IV和加密数据
|
||||||
val sSrcs = String(BASE64.decode(sSrc))
|
val sSrcs = String(decode(sSrc))
|
||||||
val parts: Array<String?> = sSrcs.split(":".toRegex(), limit = 2).toTypedArray()
|
val parts: Array<String?> = sSrcs.split(":".toRegex(), limit = 2).toTypedArray()
|
||||||
if (parts.size != 2) {
|
if (parts.size != 2) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val iv = BASE64.decode(parts[0]!!)
|
val iv = decode(parts[0]!!)
|
||||||
val encryptedData = BASE64.decode(parts[1]!!)
|
val encryptedData = decode(parts[1]!!)
|
||||||
if (iv.size != GCM_IV_LENGTH) {
|
if (iv.size != GCM_IV_LENGTH) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -121,4 +122,3 @@ private fun createSecretKey(sKey: String): SecretKeySpec {
|
|||||||
val digest = md.digest(key)
|
val digest = md.digest(key)
|
||||||
return SecretKeySpec(digest, ALGORITHM)
|
return SecretKeySpec(digest, ALGORITHM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,54 +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 Base16.kt
|
|
||||||
* LastUpdate 2025-09-17 10:56:07
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base16编解码器实现类
|
|
||||||
* 提供字节数组与十六进制字符串之间的相互转换功能
|
|
||||||
*/
|
|
||||||
class Base16 : BaseCodec {
|
|
||||||
/**
|
|
||||||
* 将字节数组编码为十六进制字符串
|
|
||||||
* @param bytes 待编码的字节数组
|
|
||||||
* @return 编码后的十六进制字符串,每个字节对应两位十六进制字符
|
|
||||||
*/
|
|
||||||
override fun encode(bytes: ByteArray): String {
|
|
||||||
// 将每个字节转换为两位十六进制字符串并拼接
|
|
||||||
return bytes.joinToString("") {
|
|
||||||
it.toInt().and(0xff).toString(16).padStart(2, '0')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将十六进制字符串解码为字节数组
|
|
||||||
* @param string 待解码的十六进制字符串
|
|
||||||
* @return 解码后的字节数组
|
|
||||||
*/
|
|
||||||
override fun decode(string: String): ByteArray {
|
|
||||||
// 按每两个字符分组,转换为字节
|
|
||||||
return string.chunked(2).map {
|
|
||||||
it.toInt(16).toByte()
|
|
||||||
}.toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,313 +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 Base256.kt
|
|
||||||
* LastUpdate 2025-09-20 14:01:29
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base256 字符集 256个
|
|
||||||
*
|
|
||||||
* 256个字符 要字符集的下面复制
|
|
||||||
*
|
|
||||||
* !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~§±×÷←↑→↓⇒⇔∀∃∅∆∇∈∉∋∌∏∑−∓∕∗∘∙√∛∜∞∟∠∣∥∧∨∩∪∫∬∭∮∯∰∱∲∳∴∵∶∷≈≠≡≤≥≦≧≪≫≺≻⊂⊃⊆⊇⊈⊉⊊⊋⊕⊖⊗⊘⊙⊚⊛⊜⊝⊞⊟⊠⊡⊢⊣⊤⊥⊦⊧⊨⊩⊪⊫⊬⊭⊮⊯⋀⋁⋂⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩▁▂▃▄▅▆▇█▉▊▋▌▍▎▏▐░▒▓▔▕▖▗▘▙
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Base256 : BaseCodec {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val code = arrayOf(
|
|
||||||
'!',
|
|
||||||
'#',
|
|
||||||
'$',
|
|
||||||
'%',
|
|
||||||
'&',
|
|
||||||
'(',
|
|
||||||
')',
|
|
||||||
'*',
|
|
||||||
'+',
|
|
||||||
',',
|
|
||||||
'-',
|
|
||||||
'.',
|
|
||||||
'/',
|
|
||||||
'0',
|
|
||||||
'1',
|
|
||||||
'2',
|
|
||||||
'3',
|
|
||||||
'4',
|
|
||||||
'5',
|
|
||||||
'6',
|
|
||||||
'7',
|
|
||||||
'8',
|
|
||||||
'9',
|
|
||||||
':',
|
|
||||||
';',
|
|
||||||
'<',
|
|
||||||
'=',
|
|
||||||
'>',
|
|
||||||
'?',
|
|
||||||
'@',
|
|
||||||
'A',
|
|
||||||
'B',
|
|
||||||
'C',
|
|
||||||
'D',
|
|
||||||
'E',
|
|
||||||
'F',
|
|
||||||
'G',
|
|
||||||
'H',
|
|
||||||
'I',
|
|
||||||
'J',
|
|
||||||
'K',
|
|
||||||
'L',
|
|
||||||
'M',
|
|
||||||
'N',
|
|
||||||
'O',
|
|
||||||
'P',
|
|
||||||
'Q',
|
|
||||||
'R',
|
|
||||||
'S',
|
|
||||||
'T',
|
|
||||||
'U',
|
|
||||||
'V',
|
|
||||||
'W',
|
|
||||||
'X',
|
|
||||||
'Y',
|
|
||||||
'Z',
|
|
||||||
'[',
|
|
||||||
']',
|
|
||||||
'^',
|
|
||||||
'_',
|
|
||||||
'`',
|
|
||||||
'a',
|
|
||||||
'b',
|
|
||||||
'c',
|
|
||||||
'd',
|
|
||||||
'e',
|
|
||||||
'f',
|
|
||||||
'g',
|
|
||||||
'h',
|
|
||||||
'i',
|
|
||||||
'j',
|
|
||||||
'k',
|
|
||||||
'l',
|
|
||||||
'm',
|
|
||||||
'n',
|
|
||||||
'o',
|
|
||||||
'p',
|
|
||||||
'q',
|
|
||||||
'r',
|
|
||||||
's',
|
|
||||||
't',
|
|
||||||
'u',
|
|
||||||
'v',
|
|
||||||
'w',
|
|
||||||
'x',
|
|
||||||
'y',
|
|
||||||
'z',
|
|
||||||
'{',
|
|
||||||
'|',
|
|
||||||
'}',
|
|
||||||
'~',
|
|
||||||
'§',
|
|
||||||
'±',
|
|
||||||
'×',
|
|
||||||
'÷',
|
|
||||||
'←',
|
|
||||||
'↑',
|
|
||||||
'→',
|
|
||||||
'↓',
|
|
||||||
'⇒',
|
|
||||||
'⇔',
|
|
||||||
'∀',
|
|
||||||
'∃',
|
|
||||||
'∅',
|
|
||||||
'∆',
|
|
||||||
'∇',
|
|
||||||
'∈',
|
|
||||||
'∉',
|
|
||||||
'∋',
|
|
||||||
'∌',
|
|
||||||
'∏',
|
|
||||||
'∑',
|
|
||||||
'−',
|
|
||||||
'∓',
|
|
||||||
'∕',
|
|
||||||
'∗',
|
|
||||||
'∘',
|
|
||||||
'∙',
|
|
||||||
'√',
|
|
||||||
'∛',
|
|
||||||
'∜',
|
|
||||||
'∞',
|
|
||||||
'∟',
|
|
||||||
'∠',
|
|
||||||
'∣',
|
|
||||||
'∥',
|
|
||||||
'∧',
|
|
||||||
'∨',
|
|
||||||
'∩',
|
|
||||||
'∪',
|
|
||||||
'∫',
|
|
||||||
'∬',
|
|
||||||
'∭',
|
|
||||||
'∮',
|
|
||||||
'∯',
|
|
||||||
'∰',
|
|
||||||
'∱',
|
|
||||||
'∲',
|
|
||||||
'∳',
|
|
||||||
'∴',
|
|
||||||
'∵',
|
|
||||||
'∶',
|
|
||||||
'∷',
|
|
||||||
'≈',
|
|
||||||
'≠',
|
|
||||||
'≡',
|
|
||||||
'≤',
|
|
||||||
'≥',
|
|
||||||
'≦',
|
|
||||||
'≧',
|
|
||||||
'≪',
|
|
||||||
'≫',
|
|
||||||
'≺',
|
|
||||||
'≻',
|
|
||||||
'⊂',
|
|
||||||
'⊃',
|
|
||||||
'⊆',
|
|
||||||
'⊇',
|
|
||||||
'⊈',
|
|
||||||
'⊉',
|
|
||||||
'⊊',
|
|
||||||
'⊋',
|
|
||||||
'⊕',
|
|
||||||
'⊖',
|
|
||||||
'⊗',
|
|
||||||
'⊘',
|
|
||||||
'⊙',
|
|
||||||
'⊚',
|
|
||||||
'⊛',
|
|
||||||
'⊜',
|
|
||||||
'⊝',
|
|
||||||
'⊞',
|
|
||||||
'⊟',
|
|
||||||
'⊠',
|
|
||||||
'⊡',
|
|
||||||
'⊢',
|
|
||||||
'⊣',
|
|
||||||
'⊤',
|
|
||||||
'⊥',
|
|
||||||
'⊦',
|
|
||||||
'⊧',
|
|
||||||
'⊨',
|
|
||||||
'⊩',
|
|
||||||
'⊪',
|
|
||||||
'⊫',
|
|
||||||
'⊬',
|
|
||||||
'⊭',
|
|
||||||
'⊮',
|
|
||||||
'⊯',
|
|
||||||
'⋀',
|
|
||||||
'⋁',
|
|
||||||
'⋂',
|
|
||||||
'⋃',
|
|
||||||
'⋄',
|
|
||||||
'⋅',
|
|
||||||
'⋆',
|
|
||||||
'⋇',
|
|
||||||
'⋈',
|
|
||||||
'⋉',
|
|
||||||
'⋊',
|
|
||||||
'⋋',
|
|
||||||
'⋌',
|
|
||||||
'⋍',
|
|
||||||
'⋎',
|
|
||||||
'⋏',
|
|
||||||
'⋐',
|
|
||||||
'⋑',
|
|
||||||
'⋒',
|
|
||||||
'⋓',
|
|
||||||
'⋔',
|
|
||||||
'⋕',
|
|
||||||
'⋖',
|
|
||||||
'⋗',
|
|
||||||
'⋘',
|
|
||||||
'⋙',
|
|
||||||
'⋚',
|
|
||||||
'⋛',
|
|
||||||
'⋜',
|
|
||||||
'⋝',
|
|
||||||
'⋞',
|
|
||||||
'⋟',
|
|
||||||
'⋠',
|
|
||||||
'⋡',
|
|
||||||
'⋢',
|
|
||||||
'⋣',
|
|
||||||
'⋤',
|
|
||||||
'⋥',
|
|
||||||
'⋦',
|
|
||||||
'⋧',
|
|
||||||
'⋨',
|
|
||||||
'⋩',
|
|
||||||
'▁',
|
|
||||||
'▂',
|
|
||||||
'▃',
|
|
||||||
'▄',
|
|
||||||
'▅',
|
|
||||||
'▆',
|
|
||||||
'▇',
|
|
||||||
'█',
|
|
||||||
'▉',
|
|
||||||
'▊',
|
|
||||||
'▋',
|
|
||||||
'▌',
|
|
||||||
'▍',
|
|
||||||
'▎',
|
|
||||||
'▏',
|
|
||||||
'▐',
|
|
||||||
'░',
|
|
||||||
'▒',
|
|
||||||
'▓',
|
|
||||||
'▔',
|
|
||||||
'▕',
|
|
||||||
'▖',
|
|
||||||
'▗',
|
|
||||||
'▘',
|
|
||||||
'▙'
|
|
||||||
)
|
|
||||||
val codeMap = code.mapIndexed { index, c -> c to index }.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun encode(bytes: ByteArray): String {
|
|
||||||
val result = CharArray(bytes.size)
|
|
||||||
for (i in bytes.indices) {
|
|
||||||
val unsignedByte = bytes[i].toInt() and 0xFF
|
|
||||||
result[i] = code[unsignedByte]
|
|
||||||
}
|
|
||||||
return String(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun decode(string: String): ByteArray {
|
|
||||||
val result = ByteArray(string.length)
|
|
||||||
for (i in string.indices) {
|
|
||||||
result[i] = codeMap[string[i]]!!.toByte()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +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 Base64.kt
|
|
||||||
* LastUpdate 2025-09-17 10:56:32
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Base64编解码工具类
|
|
||||||
* 提供Base64编码和解码功能的实现
|
|
||||||
*/
|
|
||||||
class Base64 : BaseCodec {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Base64编码器实例
|
|
||||||
* 用于执行字节数组到Base64字符串的编码操作
|
|
||||||
*/
|
|
||||||
val BASE_64_ENCODER: java.util.Base64.Encoder = java.util.Base64.getEncoder()
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Base64解码器实例
|
|
||||||
* 用于执行Base64字符串到字节数组的解码操作
|
|
||||||
*/
|
|
||||||
val BASE_64_DECODER: java.util.Base64.Decoder = java.util.Base64.getDecoder()
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 将字节数组编码为Base64字符串
|
|
||||||
*
|
|
||||||
* @param bytes 待编码的字节数组
|
|
||||||
* @return 编码后的Base64字符串
|
|
||||||
*/
|
|
||||||
override fun encode(bytes: ByteArray): String {
|
|
||||||
return BASE_64_ENCODER.encodeToString(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 将Base64字符串解码为字节数组
|
|
||||||
*
|
|
||||||
* @param string 待解码的Base64字符串
|
|
||||||
* @return 解码后的字节数组
|
|
||||||
*/
|
|
||||||
override fun decode(string: String): ByteArray {
|
|
||||||
return BASE_64_DECODER.decode(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,404 +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 Base91.kt
|
|
||||||
* LastUpdate 2025-09-19 20:08:46
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base91 编解码工具类,用于将字节数组编码为 Base91 字符串,或将 Base91 字符串解码为原始字节数组。
|
|
||||||
*
|
|
||||||
* Base91 是一种高效的二进制到文本的编码方式,相较于 Base64,它使用更少的字符来表示相同的数据。
|
|
||||||
*/
|
|
||||||
class Base91 : BaseCodec {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Base91 编码表,共 91 个可打印 ASCII 字符。
|
|
||||||
*/
|
|
||||||
val ENCODING_TABLE: CharArray = charArrayOf(
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
||||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$',
|
|
||||||
'%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=',
|
|
||||||
'>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"'
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base91 解码表,大小为 256,用于快速查找字符对应的数值。
|
|
||||||
* 初始化时将所有元素设为 -1,表示无效字符;然后根据 ENCODING_TABLE 填充有效字符的索引。
|
|
||||||
*/
|
|
||||||
val DECODING_TABLE: Array<Int> = arrayOf(
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
62,
|
|
||||||
90,
|
|
||||||
63,
|
|
||||||
64,
|
|
||||||
65,
|
|
||||||
66,
|
|
||||||
-1,
|
|
||||||
67,
|
|
||||||
68,
|
|
||||||
69,
|
|
||||||
70,
|
|
||||||
71,
|
|
||||||
-1,
|
|
||||||
72,
|
|
||||||
73,
|
|
||||||
52,
|
|
||||||
53,
|
|
||||||
54,
|
|
||||||
55,
|
|
||||||
56,
|
|
||||||
57,
|
|
||||||
58,
|
|
||||||
59,
|
|
||||||
60,
|
|
||||||
61,
|
|
||||||
74,
|
|
||||||
75,
|
|
||||||
76,
|
|
||||||
77,
|
|
||||||
78,
|
|
||||||
79,
|
|
||||||
80,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
7,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21,
|
|
||||||
22,
|
|
||||||
23,
|
|
||||||
24,
|
|
||||||
25,
|
|
||||||
81,
|
|
||||||
-1,
|
|
||||||
82,
|
|
||||||
83,
|
|
||||||
84,
|
|
||||||
85,
|
|
||||||
26,
|
|
||||||
27,
|
|
||||||
28,
|
|
||||||
29,
|
|
||||||
30,
|
|
||||||
31,
|
|
||||||
32,
|
|
||||||
33,
|
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36,
|
|
||||||
37,
|
|
||||||
38,
|
|
||||||
39,
|
|
||||||
40,
|
|
||||||
41,
|
|
||||||
42,
|
|
||||||
43,
|
|
||||||
44,
|
|
||||||
45,
|
|
||||||
46,
|
|
||||||
47,
|
|
||||||
48,
|
|
||||||
49,
|
|
||||||
50,
|
|
||||||
51,
|
|
||||||
86,
|
|
||||||
87,
|
|
||||||
88,
|
|
||||||
89,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字节数组编码为 Base91 字符串。
|
|
||||||
*
|
|
||||||
* @param bytes 待编码的字节数组
|
|
||||||
* @return 编码后的 Base91 字符串
|
|
||||||
*/
|
|
||||||
override fun encode(bytes: ByteArray): String {
|
|
||||||
if (bytes.isEmpty()) return ""
|
|
||||||
val sb = StringBuilder()
|
|
||||||
var ebq = 0 // 编码缓冲区,用于暂存待处理的位数据
|
|
||||||
var en = 0 // 当前缓冲区中的有效位数
|
|
||||||
|
|
||||||
for (b in bytes) {
|
|
||||||
// 将当前字节加入缓冲区
|
|
||||||
ebq = ebq or ((b.toInt() and 0xFF) shl en)
|
|
||||||
en += 8
|
|
||||||
|
|
||||||
// 每当缓冲区中有超过 13 位的数据时,尝试进行编码
|
|
||||||
if (en > 13) {
|
|
||||||
var ev = ebq and 0x1FFF // 取出低 13 位作为候选值
|
|
||||||
if (ev > 88) {
|
|
||||||
// 如果候选值大于 88,则使用 13 位编码
|
|
||||||
ebq = ebq shr 13
|
|
||||||
en -= 13
|
|
||||||
} else {
|
|
||||||
// 否则使用 14 位编码
|
|
||||||
ev = ebq and 0x3FFF
|
|
||||||
ebq = ebq shr 14
|
|
||||||
en -= 14
|
|
||||||
}
|
|
||||||
// 将两个字符追加到结果中
|
|
||||||
sb.append(ENCODING_TABLE[ev % 91])
|
|
||||||
sb.append(ENCODING_TABLE[ev / 91])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理剩余未编码的数据
|
|
||||||
if (en > 0) {
|
|
||||||
sb.append(ENCODING_TABLE[ebq % 91])
|
|
||||||
if (en > 7 || ebq > 90) {
|
|
||||||
sb.append(ENCODING_TABLE[ebq / 91])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 Base91 字符串解码为原始字节数组。
|
|
||||||
*
|
|
||||||
* @param string 待解码的 Base91 字符串
|
|
||||||
* @return 解码后的字节数组
|
|
||||||
*/
|
|
||||||
override fun decode(string: String): ByteArray {
|
|
||||||
if (string.isEmpty()) return ByteArray(0)
|
|
||||||
var dbq = 0 // 解码缓冲区,用于暂存待处理的位数据
|
|
||||||
var dn = 0 // 当前缓冲区中的有效位数
|
|
||||||
var dv = -1 // 当前读取到的 Base91 值
|
|
||||||
val buffer = ByteArray(string.length * 13 / 8) // 预分配输出缓冲区
|
|
||||||
var index = 0 // 输出缓冲区写入位置
|
|
||||||
|
|
||||||
for (c in string.toCharArray()) {
|
|
||||||
// 忽略不在编码表中的字符
|
|
||||||
if (DECODING_TABLE[c.code] == -1) continue
|
|
||||||
|
|
||||||
if (dv == -1) {
|
|
||||||
// 第一次读取字符,保存为 dv
|
|
||||||
dv = DECODING_TABLE[c.code]
|
|
||||||
} else {
|
|
||||||
// 第二次读取字符,组合成完整的 Base91 值
|
|
||||||
dv += DECODING_TABLE[c.code] * 91
|
|
||||||
dbq = dbq or (dv shl dn)
|
|
||||||
// 根据值大小判断是 13 位还是 14 位编码
|
|
||||||
dn += if ((dv and 0x1FFF) > 88) 13 else 14
|
|
||||||
|
|
||||||
// 将缓冲区中完整的字节写入输出数组
|
|
||||||
do {
|
|
||||||
buffer[index++] = (dbq and 0xFF).toByte()
|
|
||||||
dbq = dbq shr 8
|
|
||||||
dn -= 8
|
|
||||||
} while (dn > 7)
|
|
||||||
|
|
||||||
dv = -1 // 重置 dv,准备下一轮读取
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理最后剩余的一个字符(如果存在)
|
|
||||||
if (dv != -1) {
|
|
||||||
buffer[index++] = ((dbq or (dv shl dn)) and 0xFF).toByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回实际使用的部分
|
|
||||||
return buffer.copyOf(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,173 +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 BaseCodec.kt
|
|
||||||
* LastUpdate 2025-09-18 14:07:35
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
interface BaseCodec {
|
|
||||||
/**
|
|
||||||
* 将字节数组编码为Base64字符串
|
|
||||||
*
|
|
||||||
* @param bytes 需要编码的字节数组
|
|
||||||
* @return 编码后的Base64字符串
|
|
||||||
*/
|
|
||||||
fun encode(bytes: ByteArray): String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Base64字符串解码为字节数组
|
|
||||||
*
|
|
||||||
* @param string 需要解码的Base64字符串
|
|
||||||
* @return 解码后的字节数组
|
|
||||||
*/
|
|
||||||
fun decode(string: String): ByteArray
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将文件内容编码为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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串编码为Base64字符串
|
|
||||||
*
|
|
||||||
* @param string 需要编码的字符串
|
|
||||||
* @return 编码后的Base64字符串
|
|
||||||
*/
|
|
||||||
fun encode(string: String): String {
|
|
||||||
return encode(string.toByteArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Base64字符串解码为字符串
|
|
||||||
*
|
|
||||||
* @param string 需要解码的Base64字符串
|
|
||||||
* @return 解码后的字符串
|
|
||||||
*/
|
|
||||||
fun decodetoString(string: String): String {
|
|
||||||
return decode(string).toString(Charsets.UTF_8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,63 +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 BaseUtils.kt
|
|
||||||
* LastUpdate 2025-09-19 20:18:09
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:JvmName("BaseUtils")
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.base
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base64编解码器实例
|
|
||||||
* 使用懒加载方式初始化Base64编解码器对象
|
|
||||||
* 保证线程安全且只在首次访问时创建实例
|
|
||||||
*/
|
|
||||||
val BASE64: BaseCodec by lazy {
|
|
||||||
Base64()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base91编解码器实例
|
|
||||||
* 使用懒加载方式初始化Base91编解码器对象
|
|
||||||
* 保证线程安全且只在首次访问时创建实例
|
|
||||||
*/
|
|
||||||
val BASE91: BaseCodec by lazy {
|
|
||||||
Base91()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base91编解码器实例
|
|
||||||
* 使用懒加载方式初始化Base91编解码器对象
|
|
||||||
* 保证线程安全且只在首次访问时创建实例
|
|
||||||
*/
|
|
||||||
val BASE16: BaseCodec by lazy {
|
|
||||||
Base16()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base256编解码器实例
|
|
||||||
* 使用懒加载方式初始化Base256编解码器对象
|
|
||||||
* 保证线程安全且只在首次访问时创建实例
|
|
||||||
*/
|
|
||||||
val BASE256: BaseCodec by lazy {
|
|
||||||
Base256()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 BCrypt.kt
|
|
||||||
* LastUpdate 2025-09-19 20:17:41
|
|
||||||
* UpdateUser MingLiPro
|
|
||||||
*/
|
|
||||||
|
|
||||||
@file:JvmName("BCrypt")
|
|
||||||
|
|
||||||
package com.mingliqiye.utils.bcrypt
|
|
||||||
|
|
||||||
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import org.mindrot.jbcrypt.BCrypt as JBCrypt
|
|
||||||
|
|
||||||
|
|
||||||
fun hashpw(string: String): String {
|
|
||||||
return hashpw(string, gensalt())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun hashpw(string: String, salt: String = gensalt()): String {
|
|
||||||
return JBCrypt.hashpw(string, salt)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun checkpw(string: String, bcrypted: String): Boolean {
|
|
||||||
return JBCrypt.checkpw(string, bcrypted)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun gensalt(): String {
|
|
||||||
return JBCrypt.gensalt()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun gensalt(long: Int): String {
|
|
||||||
return JBCrypt.gensalt(long)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun gensalt(long: Int, secureRandom: SecureRandom): String {
|
|
||||||
return JBCrypt.gensalt(long, secureRandom)
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user