Compare commits

...

40 Commits

Author SHA1 Message Date
1509597032
Merge pull request 'dev' (#12) from dev into master
Reviewed-on: #12
2025-09-21 15:41:49 +08:00
ac92f62967
build(jdk8): 更新构建脚本中的 Kotlin 和 Dokka 插件版本- 在 jdk8/build.gradle.kts 中添加了 Kotlin JVM 插件和 Dokka 插件
- 更新 `build.gradle.kts` 中的 Dokka 版本从2.1.0-Beta 到2.0.0- 调整了 Gradle 任务依赖方式,使用字符串名称替代任务引用
- 升级项目版本号从 4.1.8 到 4.1.9
2025-09-21 15:39:14 +08:00
683aeb2c7f
```
feat(stream): 优化 SuperStream 的 toArray 方法实现- 调整 toArray 方法,支持传入 Class 参数以正确创建泛型数组
- 原无参 toArray 方法改为返回 Object[],避免类型转换异常
- 移除对 ForEach 工具类的依赖
- 提升流处理中数组转换的灵活性与安全性

```

```
feat(collection): 改进 toArray 工具方法支持泛型数组创建

- 新增基于 reified 泛型的 toArray 扩展方法,自动推断数组类型
- 添加带 Class 参数的 toArray 重载方法,用于明确指定元素类型
- 处理空列表时直接返回空数组,避免后续操作异常

```

```
build(gradle): 升级 dokka 插件版本并更新项目依赖- 将 org.jetbrains.dokka 插件升级至 2.1.0-Beta 版本
- 添加 jna5.17.0 依赖用于本地库调用支持
- 引入 mybatis-plus-core 3.0.1 编译依赖
- 更新项目版本号从 4.1.7 至 4.1.8

```
2025-09-21 14:37:22 +08:00
5eed682aa1
feat(utils): 添加 MyBatis-Plus 查询包装器支持
在 build.gradle.kts 中替换 JNA依赖为 mybatis-plus-core,并新增BaseMapperQuery 接口,提供通用的 QueryWrapper 实例创建方法,便于MyBatis-Plus 相关操作的统一封装与复用
2025-09-20 14:22:14 +08:00
578f0a3e89
fix(collection): 抑制类型转换警告并更新文件时间戳修复了 Collection.kt 文件中的类型转换警告问题,通过添加 @Suppress("UNCHECKED_CAST")
注解来抑制编译器警告。同时更新了文件的最后修改时
2025-09-20 14:05:41 +08:00
075dc2346a
feat(utils): 更新工具类并优化集合扩展函数
- 更新多个工具类的最后修改时间和用户信息
- 移除冗余的 main 函数测试代码
- 优化 ByteUtils 中流处理方法的引用- 为 Collection 扩展大量实用函数,包括转换、获取元素和创建集合实例等
- 引入 SuperStream 替代部分自定义流处理逻辑
- 调整 Spring Boot 自动配置包扫描路径- 修复资源读取时的空指针风险,使用 Kotlin 的 elvis 操作符简化代码
2025-09-20 14:01:36 +08:00
23548c0c3d
refactor(Base91): 更新Base91解码表并添加示例
更新了Base91解码表的初始化方式,并添加了一个示例方法来演示编码和解码功能。

feat(Base256): 添加Base256编解码器

新增了Base256类,实现了Base256编解码功能,并在BaseUtils中添加了相应的实例。

refactor(BaseCodec): 增加字符串编解码方法

在BaseCodec接口中增加了对字符串进行Base64编码和解码的方法。refactor(OsPath): 简化路径处理逻辑

移除了OsPath类中不必要的方法实现,简化了路径处理逻辑。

feat(UUID): 支持Base256短字符串

在UUID类中添加了对Base256短字符串的支持,包括编码和解码方法。
2025-09-18 14:43:01 +08:00
4b187f3774
添加 String.join 的文档
添加 List.join 的文档
添加 split 的文档
2025-09-18 09:28:06 +08:00
c90c1d590b
修改 List.join 为<T> 2025-09-18 09:24:43 +08:00
42a3302495
添加 String.join 方法 2025-09-18 09:23:19 +08:00
496c3e6248
更新List.join方法 2025-09-18 09:22:55 +08:00
9002f41c63
Merge pull request 'dev' (#11) from dev into master
Reviewed-on: #11
2025-09-17 21:20:20 +08:00
58806e85f1
refactor(bcrypt): 重构 BCrypt.kt 文件
- 将 BCrypt 对象中的函数转换为顶级函数
- 添加 @JvmName 注解以自定义 JVM 方法名
- 更新相关文件中的导入和引用
- 调整 DateTime 类的 parse 和 format 方法
- 优化 StringUtils 中的 isEmpty 方法
2025-09-17 21:15:39 +08:00
0f5748d55d
feat(utils): 添加 BCrypt 加密工具类
- 新增 BCrypt.kt 文件,提供 BCrypt 加密相关方法
- 更新 build.gradle.kts,调整依赖项和版本
- 更新 gradle.properties,升级版本号至 4.1.1
- 更新 HashUtils.kt,使用新的 BCrypt 工具类
- 添加 NOTICE 文件,记录第三方软件的版权声明
2025-09-17 12:10:53 +08:00
8f8ffc72db
Merge pull request 'feat(build): 重构项目并添加 Maven 发布支持' (#10) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2s
Reviewed-on: #10
2025-09-17 11:12:41 +08:00
fcd528a821
feat(build): 重构项目并添加 Maven 发布支持
- 更新 .gitignore 文件,添加 secret.gpg
- 移除 .prettierrc 文件
- 重构 AES 加密工具类,使用新的 Base64 实现
- 新增 Base16、Base64 和 Base91 编解码工具类
- 新增 BaseCodec接口和 BaseUtils 工具类
- 更新 build.gradle.kts 配置,添加 Maven 发布和签名
- 修复 ByteUtils 和 DateTime 工具类中的问题
- 重构 UUID 使用自己的实现 不依赖标准库以及其他的 UUID库
2025-09-17 11:12:10 +08:00
0450e87c13
Merge pull request 'dev' (#9) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 3m11s
Reviewed-on: #9
2025-09-15 22:33:56 +08:00
541a8a82b4
feat(network): 添加网络地址和端口相关工具类
- 新增 NetworkAddress 类用于表示网络地址,支持 IPv4 和 IPv6
- 新增 NetworkPort 类用于表示端口号
- 新增 NetworkEndpoint 类用于封装网络地址和端口信息
- 优化 AutoConfiguration 类,添加更多系统信息
- 更新 AesUtils、Base64Utils等类的版本信息
- 删除 Minecraft SLF 相关无用代码
- 更新项目版本号至 4.0.7
2025-09-15 22:32:56 +08:00
7c3c13e28c
feat(utils): 更新版本号并优化 UUID 功能
- 将项目版本号从 4.0.5 升级到 4.0.6
- 更新 Main.kt 文件,使用 UUID 替代 DateTime
- 改进 UUID.kt 中的 equals 方法,支持与 JUUID 类型的比较
2025-09-15 18:03:35 +08:00
e4bb9884c1
Merge pull request 'refactor(stream): 重构流处理相关代码' (#8) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m21s
Reviewed-on: #8
2025-09-15 17:27:10 +08:00
cc3156572f
refactor(stream): 重构流处理相关代码
- 移除 InOutSteam、InputStreanWrapper、OutputStreamWrapper 类
- 删除 Getable、GetIdable、GetKeyable、GetNameable 接口- 更新 ByteUtils 和 Collection.kt 中的流处理逻辑
- 新增 InputStreamUtils.kt 文件,提供输入流相关扩展函数
- 更新项目版本号至 4.0.5
2025-09-15 17:26:39 +08:00
0b1aac8ecc
Merge pull request 'refactor(mybatis): 更新类型处理器以支持 JDBC 类型参数为 null' (#7) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m25s
Reviewed-on: #7
2025-09-15 13:55:22 +08:00
9a6c6cd662
refactor(mybatis): 更新类型处理器以支持 JDBC 类型参数为 null
- 修改 DateTimeTypeHandler、MysqlUUIDBinaryTypeHandler 和 UUIDTypeHandler
- 将 setNonNullParameter 方法的 jdbcType 参数变更为可空类型
- 更新方法实现以适应新的可空参数
- 提升代码的健壮性和灵活性,允许在某些情况下不指定 JDBC 类型
2025-09-15 13:55:01 +08:00
3d1f249970
Merge pull request 'dev' (#6) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2m14s
Reviewed-on: #6
2025-09-15 12:46:12 +08:00
b329953377
feat(foreach): 增加带有提前终止功能的遍历方法并优化代码结构
- 新增 forEachB 系列函数,支持在遍历过程中提前终止
- 为数组和集合添加专门的 forEach 和 forEachB 函数
- 优化现有 forEach 函数的实现,提高性能
- 添加针对 Map 类型的 forEachMap 和 forEachMapB 函数
- 更新函数注释,明确参数和返回值的含义
2025-09-15 12:45:59 +08:00
f9e96fccd3
feat(foreach): 增加带有提前终止功能的遍历方法并优化代码结构
- 新增 forEachB 系列函数,支持在遍历过程中提前终止
- 为数组和集合添加专门的 forEach 和 forEachB 函数
- 优化现有 forEach 函数的实现,提高性能
- 添加针对 Map 类型的 forEachMap 和 forEachMapB 函数
- 更新函数注释,明确参数和返回值的含义
2025-09-15 12:45:16 +08:00
d6517287d1
Merge pull request 'feat(utils): 添加 foreach 扩展函数并更新项目版本' (#5) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m4s
Reviewed-on: #5
2025-09-15 12:01:58 +08:00
33999bf4c6
feat(utils): 添加 foreach 扩展函数并更新项目版本
- 新增 ForEach.kt 文件,提供多种 foreach 函数实现
- 更新项目版本至 4.0.2
- 修改 gradle-wrapper.properties 和 gradlew 文件,更新 Gradle 分发 URL
2025-09-15 12:01:38 +08:00
533ba9bed7
Merge pull request 'refactor(time): 重构 DateTime 类并添加新功能' (#4) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 1m54s
Reviewed-on: #4
2025-09-15 11:33:46 +08:00
b19fcba67b
refactor(time): 重构 DateTime 类并添加新功能
- 从 Java 文件中删除了旧的 DateTime 类
- 新增 Kotlin 版本的 DateTime 类,具有以下改进:
  - 添加了时间格式化枚举类 Formatter
  - 新增时间位移类 DateTimeOffset - 重构了 parse 和 format 方法,支持新的 Formatter 枚举  - 优化了文件时间转换方法,使用纳秒精度
- 删除了旧的 DateTimeJsonConverter 类
2025-09-15 11:33:09 +08:00
092947d81a
Merge pull request 'refactor(time): 重构 DateTime 类并添加新功能' (#3) from dev into master
Some checks failed
Gitea Actions Build / Build (push) Failing after 2m30s
Reviewed-on: #3
2025-09-15 11:20:38 +08:00
7526b2e787
refactor(time): 重构 DateTime 类并添加新功能
- 从 Java 文件中删除了旧的 DateTime 类
- 新增 Kotlin 版本的 DateTime 类,具有以下改进:
  - 添加了时间格式化枚举类 Formatter
  - 新增时间位移类 DateTimeOffset - 重构了 parse 和 format 方法,支持新的 Formatter 枚举  - 优化了文件时间转换方法,使用纳秒精度
- 删除了旧的 DateTimeJsonConverter 类
2025-09-15 11:20:08 +08:00
6a7d73091e
Merge pull request 'refactor(mingli-utils):重构集合工具类并添加新功能' (#2) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 2m4s
Reviewed-on: #2
2025-09-15 09:32:42 +08:00
dc129c016f
refactor(mingli-utils):重构集合工具类并添加新功能
- 重写 Collection 类,使用 Kotlin 语法和特性优化代码结构
- 添加新方法以支持数组和集合之间的转换
- 新增 CopyOnWriteArrayList、Stack 和 TreeSet 相关方法
-优化现有方法,提高代码可读性和性能
- 删除未使用的 ForEach 导入
-调整 build.gradle.kts 中的依赖项
2025-09-15 09:30:41 +08:00
67a1256682
Merge pull request 'refactor(kotlin): 重构 AES 工具类并优化 Base64 编解码方法' (#1) from dev into master
All checks were successful
Gitea Actions Build / Build (push) Successful in 4m11s
Reviewed-on: #1
2025-09-14 22:13:10 +08:00
d6a2117b58
格式化文件 2025-09-14 22:12:22 +08:00
8ef3cb5ba4
refactor(kotlin): 重构 AES 工具类并优化 Base64 编解码方法
- 重构 AesUtils.kt,使用 Kotlin 标准库的 encode 和 decode 方法替代自定义实现- 删除 Java 版本的 Base64Utils 类,迁移到 Kotlin 实现
- 重命名 ByteUtil.kt 为 ByteUtils.kt,统一命名风格
- 删除 Java 版本的 CloneUtil 类和 Factory 类,使用 Kotlin 实现
- 新增 Kotlin 版本的 SpringBeanUtils 工具类重构项目,迁移到 Kotlin

- 将 Java 文件转换为 Kotlin 文件
- 更新项目结构和命名- 优化代码实现
- 添加必要的依赖
2025-09-14 22:10:47 +08:00
01bfb052d0
refactor(kotlin): 重构 AES 工具类并优化 Base64 编解码方法
Some checks failed
Gitea Actions Build / Build (push) Failing after 1m17s
- 重构 AesUtils.kt,使用 Kotlin 标准库的 encode 和 decode 方法替代自定义实现- 删除 Java 版本的 Base64Utils 类,迁移到 Kotlin 实现
- 重命名 ByteUtil.kt 为 ByteUtils.kt,统一命名风格
- 删除 Java 版本的 CloneUtil 类和 Factory 类,使用 Kotlin 实现
- 新增 Kotlin 版本的 SpringBeanUtils 工具类
2025-09-14 21:47:15 +08:00
1fab0b02be
refactor(kotlin): 重构 AES 工具类并优化 Base64 编解码方法
Some checks failed
Gitea Actions Build / Build (push) Has been cancelled
- 重构 AesUtils.kt,使用 Kotlin 标准库的 encode 和 decode 方法替代自定义实现- 删除 Java 版本的 Base64Utils 类,迁移到 Kotlin 实现
- 重命名 ByteUtil.kt 为 ByteUtils.kt,统一命名风格
- 删除 Java 版本的 CloneUtil 类和 Factory 类,使用 Kotlin 实现
- 新增 Kotlin 版本的 SpringBeanUtils 工具类
2025-09-14 21:47:04 +08:00
fb4e103da8
no message
All checks were successful
Gitea Actions Build / Build (push) Successful in 4m11s
2025-09-14 18:23:34 +08:00
165 changed files with 11613 additions and 28213 deletions

3
.gitignore vendored
View File

@ -44,4 +44,5 @@ log
.idea .idea
node_modules node_modules
*lock* *lock*
.kotlin
secret.gpg

View File

@ -1,8 +0,0 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"plugins": [
"prettier-plugin-java"
],
"tabWidth": 4,
"useTabs": true
}

25
NOTICE Normal file
View File

@ -0,0 +1,25 @@
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
View File

@ -1,167 +0,0 @@
# 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) 文件。

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils * ModuleName mingli-utils
* CurrentFile build.gradle.kts * CurrentFile build.gradle.kts
* LastUpdate 2025-09-12 14:06:21 * LastUpdate 2025-09-21 15:36:59
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
@ -26,12 +26,12 @@ import java.time.format.DateTimeFormatter
plugins { plugins {
idea idea
java java
id("java-library") signing
id("maven-publish") `java-library`
`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
@ -59,30 +59,27 @@ sourceSets {
} }
} }
configurations {
}
java { java {
withSourcesJar() withSourcesJar()
toolchain.languageVersion.set(JavaLanguageVersion.of(8)) toolchain.languageVersion.set(JavaLanguageVersion.of(8))
} }
dependencies { dependencies {
annotationProcessor("org.jetbrains:annotations:24.0.0")
annotationProcessor("org.projectlombok:lombok:1.18.38") implementation("org.slf4j:slf4j-api:2.0.17")
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")
implementation("org.bouncycastle:bcprov-jdk18on:1.81") compileOnly("com.baomidou:mybatis-plus-core:3.0.1")
implementation("com.github.f4b6a3:uuid-creator:6.1.0") compileOnly("net.java.dev.jna:jna:5.17.0")
implementation("org.mindrot:jbcrypt:0.4")
implementation("org.jetbrains:annotations:24.0.0")
implementation("net.java.dev.jna:jna:5.17.0")
implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
} }
@ -90,36 +87,21 @@ tasks.withType<JavaCompile> {
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
tasks.register<Jar>("javaDocJar") {
group = "build"
archiveClassifier.set("javadoc")
dependsOn(tasks.dokkaGfm, tasks.dokkaHtml, tasks.dokkaJavadoc, tasks.dokkaJekyll)
from(buildDir.resolve("dokka/javadoc"))
}
tasks.register<Jar>("kotlinDocJar") {
group = "build"
archiveClassifier.set("kotlindoc")
dependsOn(tasks.dokkaHtml)
from(buildDir.resolve("dokka/html"))
}
tasks.build {
dependsOn("javaDocJar", "kotlinDocJar")
}
tasks.withType<JavaExec>().configureEach { tasks.withType<JavaExec>().configureEach {
jvmArgs = listOf( jvmArgs = listOf(
"-Dfile.encoding=UTF-8", "-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8"
"-Dsun.stdout.encoding=UTF-8",
"-Dsun.stderr.encoding=UTF-8"
) )
} }
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-Class" to "com.mingliqiye.utils.main.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",
@ -142,57 +124,93 @@ tasks.withType<org.gradle.jvm.tasks.Jar> {
) )
} }
} }
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") {
group = "build"
archiveClassifier.set("javadoc")
dependsOn("dokkaJavadoc")
from(buildDir.resolve("dokka/javadoc"))
}
tasks.register<Jar>("kotlinDocJar") {
group = "build"
archiveClassifier.set("kotlindoc")
dependsOn("dokkaHtml")
from(buildDir.resolve("dokka/html"))
}
publishing { publishing {
repositories { repositories {
maven { maven {
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"])
groupId = GROUPSID
artifactId = ARTIFACTID
version = VERSIONS
artifact(tasks.named("javaDocJar")) artifact(tasks.named("javaDocJar"))
artifact(tasks.named("kotlinDocJar")) artifact(tasks.named("kotlinDocJar"))
artifactId = ARTIFACTID
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
pom { pom {
name.set(project.name) name = "mingli-utils"
url.set("https://github.com/minglipro/mingli-utils") url = "https://mingli-utils.mingliqiye.com"
description = "A Java/kotlin Utils"
licenses { licenses {
license { license {
name.set("Apache-2.0") name = "The Apache License, Version 2.0"
url.set("https://opensource.org/licenses/Apache-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 {
dependsOn("javaDocJar", "kotlinDocJar")
}
tasks.processResources { tasks.processResources {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
outputs.upToDateWhen { false } outputs.upToDateWhen { false }
filesMatching("META-INF/meta-data") { filesMatching("META-INF/meta-data") {
expand( expand(
mapOf( project.properties + mapOf(
"buildTime" to LocalDateTime.now() "buildTime" to LocalDateTime.now().format(
.format( DateTimeFormatter.ofPattern(
DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss.SSSSSSS"
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
)
) )
) + project.properties )
)
) )
} }
} }

View File

@ -16,10 +16,13 @@
# ProjectName mingli-utils # ProjectName mingli-utils
# ModuleName mingli-utils # ModuleName mingli-utils
# CurrentFile gradle.properties # CurrentFile gradle.properties
# LastUpdate 2025-09-12 14:10:24 # LastUpdate 2025-09-21 15:38:52
# UpdateUser MingLiPro # UpdateUser MingLiPro
# #
JDKVERSIONS=1.8 JDKVERSIONS=1.8
GROUPSID=com.mingliqiye.utils GROUPSID=com.mingliqiye.utils
ARTIFACTID=mingli-utils ARTIFACTID=mingli-utils
VERSIONS=3.2.7 VERSIONS=4.1.9
signing.keyId=B22AA93B
signing.password=
signing.secretKeyRingFile=secret.gpg

Binary file not shown.

View File

@ -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-09 08:37:34 # LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro # UpdateUser MingLiPro
# #
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.14-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@ -18,7 +18,7 @@
# ProjectName mingli-utils # ProjectName mingli-utils
# ModuleName mingli-utils # ModuleName mingli-utils
# CurrentFile gradlew # CurrentFile gradlew
# LastUpdate 2025-09-09 08:37:33 # LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro # UpdateUser MingLiPro
# #

90
jdk8/build.gradle.kts Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.jdk8
* CurrentFile build.gradle.kts
* LastUpdate 2025-09-21 15:39:12
* UpdateUser MingLiPro
*/
plugins {
id("java-library")
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 VERSIONS = project.properties["VERSIONS"] as String
val ARTIFACTID = project.properties["ARTIFACTID"] as String
version = VERSIONS
group = GROUPSID
base.archivesName.set(ARTIFACTID)
publishing {
repositories {
maven {
name = "MavenRepositoryRaw"
url = uri("C:/data/git/maven-repository-raw")
}
maven {
name = "OSSRepository"
url = uri("C:/data/git/maven-repository-raw-utils")
}
}
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
artifactId = "$ARTIFACTID-win-jdk8"
java.toolchain.languageVersion.set(JavaLanguageVersion.of(8))
pom {
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))
dependencies {
api(rootProject)
implementation("com.mingliqiye.utils.jna:WinKernel32Platform:1.0.1")
}

23
jdk8/gradle.properties Normal file
View File

@ -0,0 +1,23 @@
#
# 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

View File

@ -1 +0,0 @@
lombok.addLombokGeneratedAnnotation = false

View File

@ -1,14 +0,0 @@
{
"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"
}
}

View File

@ -16,9 +16,10 @@
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils * ModuleName mingli-utils
* CurrentFile settings.gradle.kts * CurrentFile settings.gradle.kts
* LastUpdate 2025-09-09 08:37:33 * LastUpdate 2025-09-16 12:32:52
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
include("jdk8")
val ARTIFACTID: String by settings.extra val ARTIFACTID: String by settings.extra
rootProject.name = ARTIFACTID rootProject.name = ARTIFACTID

View File

@ -1,133 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AesUtils.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.aes;
import com.mingliqiye.utils.base64.Base64Utils;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtils {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final int GCM_IV_LENGTH = 12;
private static final int GCM_TAG_LENGTH = 16;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
/**
* AES加密方法使用GCM模式
* @param sSrc 待加密的字符串
* @param sKey 加密密钥
* @return 加密后的字符串格式为 IV:EncryptedData+Tag均为Base64编码
* @throws GeneralSecurityException 加密错误
*/
public static String encrypt(String sSrc, String sKey)
throws GeneralSecurityException {
if (sKey == null) {
return null;
}
// 生成密钥
SecretKeySpec secretKeySpec = createSecretKey(sKey);
// 生成安全随机IV
byte[] iv = new byte[GCM_IV_LENGTH];
SECURE_RANDOM.nextBytes(iv);
// 初始化加密器
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(
GCM_TAG_LENGTH * 8,
iv
);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
// 执行加密
byte[] encrypted = cipher.doFinal(
sSrc.getBytes(StandardCharsets.UTF_8)
);
// 将IV和加密数据包含认证标签组合返回
return Base64Utils.encode(
(Base64Utils.encode(iv) +
":" +
Base64Utils.encode(encrypted)).getBytes()
);
}
/**
* AES解密方法使用GCM模式
* @param sSrc 待解密的字符串格式为 IV:EncryptedData+Tag均为Base64编码
* @param sKey 解密密钥
* @return 解密后的原始字符串
*/
public static String decrypt(String sSrc, String sKey) {
if (sKey == null) {
return null;
}
try {
// 分割IV和加密数据
String sSrcs = new String(Base64Utils.decode(sSrc));
String[] parts = sSrcs.split(":", 2);
if (parts.length != 2) {
return null;
}
byte[] iv = Base64Utils.decode(parts[0]);
byte[] encryptedData = Base64Utils.decode(parts[1]);
if (iv.length != GCM_IV_LENGTH) {
return null;
}
SecretKeySpec secretKeySpec = createSecretKey(sKey);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(
GCM_TAG_LENGTH * 8,
iv
);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] original = cipher.doFinal(encryptedData);
return new String(original, StandardCharsets.UTF_8);
} catch (Exception e) {
return null;
}
}
/**
* 创建AES密钥支持任意长度的密钥
* @param sKey 字符串密钥
* @return SecretKeySpec对象
* @throws Exception 可能抛出的异常
*/
private static SecretKeySpec createSecretKey(String sKey)
throws GeneralSecurityException {
byte[] key = sKey.getBytes(StandardCharsets.UTF_8);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(key);
return new SecretKeySpec(digest, ALGORITHM);
}
}

View File

@ -1,198 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base64Utils.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.base64;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Base64;
/**
* Base64工具类提供对字节数组文件和字符串的Base64编码与解码功能
*/
public class Base64Utils {
// Base64编码器实例
private static final Base64.Encoder BASE_64_ENCODER = Base64.getEncoder();
// Base64解码器实例
private static final Base64.Decoder BASE_64_DECODER = Base64.getDecoder();
/**
* 对字节数组进行Base64编码
*
* @param bytes 待编码的字节数组
* @return 编码后的Base64字符串
*/
public static String encode(byte[] bytes) {
return BASE_64_ENCODER.encodeToString(bytes);
}
/**
* 对文件内容进行Base64编码
*
* @param file 待编码的文件对象
* @return 编码后的Base64字符串
* @throws RuntimeException 如果读取文件时发生IO异常
*/
public static String encode(File file) {
try {
byte[] bytes = java.nio.file.Files.readAllBytes(file.toPath());
return encode(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 根据文件路径对文件内容进行Base64编码
*
* @param filePath 文件路径
* @return 编码后的Base64字符串
*/
public static String encode(String filePath) {
return encode(new File(filePath));
}
/**
* 安全地对文件内容进行Base64编码出错时返回null
*
* @param file 待编码的文件对象
* @return 编码后的Base64字符串出错时返回null
*/
public static String encodeSafe(File file) {
try {
return encode(file);
} catch (Exception e) {
return null;
}
}
/**
* 安全地根据文件路径对文件内容进行Base64编码出错时返回null
*
* @param filePath 文件路径
* @return 编码后的Base64字符串出错时返回null
*/
public static String encodeSafe(String filePath) {
try {
return encode(filePath);
} catch (Exception e) {
return null;
}
}
/**
* 对Base64字符串进行解码
*
* @param base64 待解码的Base64字符串
* @return 解码后的字节数组
*/
public static byte[] decode(String base64) {
return BASE_64_DECODER.decode(base64);
}
/**
* 安全地对Base64字符串进行解码出错时返回null
*
* @param base64 待解码的Base64字符串
* @return 解码后的字节数组出错时返回null
*/
public static byte[] decodeSafe(String base64) {
try {
return decode(base64);
} catch (Exception e) {
return null;
}
}
/**
* 将Base64字符串解码并写入指定文件
*
* @param base64 待解码的Base64字符串
* @param file 目标文件对象
* @throws RuntimeException 如果写入文件时发生IO异常
*/
public static void decodeToFile(String base64, File file) {
try (FileOutputStream fos = new FileOutputStream(file)) {
byte[] bytes = decode(base64);
fos.write(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 将Base64字符串解码并写入指定路径的文件
*
* @param base64 待解码的Base64字符串
* @param filePath 目标文件路径
*/
public static void decodeToFile(String base64, String filePath) {
decodeToFile(base64, new File(filePath));
}
/**
* 安全地将Base64字符串解码并写入指定文件出错时返回false
*
* @param base64 待解码的Base64字符串
* @param file 目标文件对象
* @return 成功写入返回true否则返回false
*/
public static boolean decodeToFileSafe(String base64, File file) {
try {
decodeToFile(base64, file);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 安全地将Base64字符串解码并写入指定路径的文件出错时返回false
*
* @param base64 待解码的Base64字符串
* @param filePath 目标文件路径
* @return 成功写入返回true否则返回false
*/
public static boolean decodeToFileSafe(String base64, String filePath) {
return decodeToFileSafe(base64, new File(filePath));
}
/**
* 对字节数组中指定范围的数据进行Base64编码
*
* @param bytes 源字节数组
* @param offset 起始偏移量
* @param length 要编码的数据长度
* @return 编码后的Base64字符串
*/
public static String encodeBytes(byte[] bytes, int offset, int length) {
byte[] data = new byte[length];
System.arraycopy(bytes, offset, data, 0, length);
return encode(data);
}
public static String encodeBytes(byte[] bytes) {
return encodeBytes(bytes, 0, bytes.length);
}
}

View File

@ -1,270 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Factory.java
* LastUpdate 2025-09-09 08:39:07
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bean;
import com.mingliqiye.utils.bean.annotation.ComponentBean;
import com.mingliqiye.utils.bean.annotation.InjectBean;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 类似于SpringBoot的Bean管理器
*
* @author MingLiPro
*/
public class Factory {
/**
* 存储所有已注册的Bean实例键为Bean名称值为Bean实例
*/
public static final ConcurrentMap<String, Object> BEANS =
new ConcurrentHashMap<>();
/**
* 存储按类型查找的Bean实例键为Bean的Class对象值为Bean实例
*/
private static final ConcurrentMap<Class<?>, Object> TYPE_BEANS =
new ConcurrentHashMap<>();
/**
* 私有构造函数防止外部实例化该类
*/
private Factory() {}
/**
* 自动扫描指定类所在包下的所有类并注册为Bean
*
* @param c 指定的类用于获取其所在的包
* @throws IllegalArgumentException 如果传入的类为null或位于默认包中
*/
public static void autoScan(Class<?> c) {
if (c == null) {
throw new IllegalArgumentException("Class cannot be null");
}
Package pkg = c.getPackage();
if (pkg == null) {
throw new IllegalArgumentException(
"Class is in the default package"
);
}
scan(pkg.getName());
}
/**
* 扫描指定包路径下的所有类文件并注册其中带有@ComponentBean注解的类为Bean
*
* @param basePackage 要扫描的基础包名
* @throws RuntimeException 如果在扫描过程中发生异常
*/
public static void scan(String basePackage) {
try {
String path = basePackage.replace('.', '/');
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = null;
resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
File file = new File(resource.toURI());
scanDirectory(file, basePackage);
}
injectDependencies();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 递归扫描目录中的所有类文件并注册符合条件的类为Bean
*
* @param directory 当前要扫描的目录
* @param packageName 当前目录对应的包名
* @throws Exception 如果在扫描或类加载过程中发生异常
*/
private static void scanDirectory(File directory, String packageName)
throws Exception {
File[] files = directory.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
scanDirectory(file, packageName + "." + file.getName());
} else if (file.getName().endsWith(".class")) {
String className =
packageName + '.' + file.getName().replace(".class", "");
registerComponent(Class.forName(className));
}
}
}
/**
* 注册一个带有@ComponentBean注解的类为Bean实例
*
* @param clazz 要注册的类
* @throws Exception 如果在实例化类或处理注解时发生异常
*/
private static void registerComponent(Class<?> clazz) throws Exception {
if (clazz.isAnnotationPresent(ComponentBean.class)) {
ComponentBean component = clazz.getAnnotation(ComponentBean.class);
String name = component.value().isEmpty()
? clazz.getName()
: component.value();
Object instance = clazz.getDeclaredConstructor().newInstance();
BEANS.put(name, instance);
TYPE_BEANS.put(clazz, instance);
for (Class<?> interfaceClass : clazz.getInterfaces()) {
TYPE_BEANS.putIfAbsent(interfaceClass, instance);
}
}
}
/**
* 对所有已注册的Bean进行依赖注入处理
*
* @throws Exception 如果在注入过程中发生异常
*/
private static void injectDependencies() throws Exception {
for (Object bean : BEANS.values()) {
for (Field field : bean.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(InjectBean.class)) {
InjectBean inject = field.getAnnotation(InjectBean.class);
Object dependency = findDependency(
field.getType(),
inject.value()
);
if (dependency == null) {
throw new IllegalStateException(
"No suitable dependency found for field " +
field.getName() +
" in class " +
bean.getClass().getName()
);
}
field.setAccessible(true);
field.set(bean, dependency);
}
}
}
}
/**
* 根据类型和名称查找对应的依赖实例
*
* @param type 依赖的类型
* @param name 依赖的名称可为空
* @return 找到的依赖实例未找到则返回null
*/
private static Object findDependency(Class<?> type, String name) {
if (!name.isEmpty()) {
return BEANS.get(name);
}
Object dependency = TYPE_BEANS.get(type);
if (dependency != null) {
return dependency;
}
for (Class<?> interfaceType : TYPE_BEANS.keySet()) {
if (type.isAssignableFrom(interfaceType)) {
return TYPE_BEANS.get(interfaceType);
}
}
return null;
}
/**
* 将一个对象添加到Bean容器中使用其类名作为键
*
* @param object 要添加的对象
* @throws RuntimeException 如果在注入依赖时发生异常
*/
public static void add(Object object) {
Class<?> clazz = object.getClass();
String name = clazz.getName();
BEANS.put(name, object);
TYPE_BEANS.put(clazz, object);
try {
injectDependencies();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 将一个对象以指定名称添加到Bean容器中
*
* @param name Bean的名称
* @param object 要添加的对象
* @throws RuntimeException 如果在注入依赖时发生异常
*/
public static void add(String name, Object object) {
BEANS.put(name, object);
TYPE_BEANS.put(object.getClass(), object);
try {
injectDependencies();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 根据类型获取对应的Bean实例
*
* @param objclass Bean的类型
* @param <T> Bean的泛型类型
* @return 对应类型的Bean实例未找到则返回null
*/
public static <T> T get(Class<T> objclass) {
return objclass.cast(TYPE_BEANS.get(objclass));
}
/**
* 根据名称和类型获取对应的Bean实例
*
* @param name Bean的名称
* @param objclass Bean的类型
* @param <T> Bean的泛型类型
* @return 对应名称和类型的Bean实例未找到则返回null
*/
public static <T> T get(String name, Class<T> objclass) {
return objclass.cast(BEANS.get(name));
}
/**
* 根据名称获取对应的Bean实例
*
* @param name Bean的名称
* @return 对应名称的Bean实例未找到则返回null
*/
public static Object get(String name) {
return BEANS.get(name);
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ComponentBean.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author MingLiPro
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentBean {
String value() default "";
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile InjectBean.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author MingLiPro
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectBean {
String value() default "";
}

View File

@ -1,97 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SpringBeanUtil.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bean.springboot;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring Bean工具类
* 实现ApplicationContextAware接口并加入Component注解让spring扫描到该bean
* 该类用于在普通Java类中注入bean,普通Java类中用@Autowired是无法注入bean的
* <p>
* 需要放入扫描类中
*
* @author MingLiPro
*/
@Component
public class SpringBeanUtil implements ApplicationContextAware {
/**
* 获取applicationContext
*/
@Getter
private static ApplicationContext applicationContext;
/**
* 通过bean名称获取Bean实例
*
* @param name bean名称
* @return bean实例对象
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过bean类型获取Bean实例
*
* @param clazz bean的Class类型
* @param <T> 泛型类型
* @return 指定类型的bean实例
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过bean名称和类型获取指定的Bean实例
*
* @param name bean名称
* @param clazz bean的Class类型
* @param <T> 泛型类型
* @return 指定名称和类型的bean实例
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
/**
* 设置ApplicationContext上下文对象
* 当Spring容器初始化时会自动调用此方法将ApplicationContext注入到本工具类中
* 通过判断避免重复赋值确保只设置一次ApplicationContext
*
* @param applicationContext Spring应用上下文对象
* @throws BeansException bean异常
*/
@Override
public void setApplicationContext(
@NotNull ApplicationContext applicationContext
) throws BeansException {
SpringBeanUtil.applicationContext = applicationContext;
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ByteUtil.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.bytes;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author MingLiPro
*
* 字节数组处理工具类
*/
public class ByteUtil {
public static final byte ESC_ASC = 0x1A;
public static final byte ESC_DESC = 0x1B;
public static final byte ESC_NONE = 0x00;
public static final byte ESC_START = 0x01;
public static final byte ESC_END = 0x02;
public static final byte ESC_ESC = 0x03;
public static final byte ESC_CONTROL = 0x04;
public static final byte ESC_DATA = 0x05;
public static final byte ESC_RESERVED = 0x06;
/**
* 将字节数组转换为十六进制字符串列表
* <p>
* 每个字节都会被转换为两位的十六进制字符串表示形式
* 例如: 字节值为10的字节会被转换为"0a"值为255的字节会被转换为"ff"
*
* @param bytes 输入的字节数组
* @return 包含每个字节对应十六进制字符串的列表
*/
public static List<String> getByteArrayString(byte[] bytes) {
List<Byte> byteList = new ArrayList<>(bytes.length);
for (byte aByte : bytes) {
byteList.add(aByte);
}
return byteList
.stream()
.map(a -> String.format("%02x", a & 0xFF))
.collect(Collectors.toList());
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile CloneUtil.java
* LastUpdate 2025-09-09 09:32:17
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.clone;
import com.mingliqiye.utils.json.JsonApi;
import com.mingliqiye.utils.json.JsonException;
import java.io.*;
public class CloneUtil {
/**
* 对指定的可序列化对象进行深拷贝
*
* @param object 需要进行深拷贝的对象必须实现Serializable接口
* @param <T> 对象的类型必须实现Serializable接口
* @return 深拷贝后的新对象与原对象内容相同但内存地址不同
* @throws RuntimeException 当序列化或反序列化过程中发生IO异常或类未找到异常时抛出
*/
public static <T extends Serializable> T deepClone(T object) {
try {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(object);
ByteArrayInputStream bis = new ByteArrayInputStream(
bao.toByteArray()
);
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 深度克隆对象使用JSON序列化和反序列化实现
*
* @param <T> 对象类型参数
* @param object 需要克隆的对象实例
* @param jsonApi JSON序列化接口实现
* @return 克隆后的对象实例
*/
public static <T> T deepJsonClone(T object, JsonApi jsonApi) {
if (object == null) {
return null;
}
if (jsonApi == null) {
throw new IllegalArgumentException("jsonApi cannot be null");
}
try {
return (T) jsonApi.convert(object, object.getClass());
} catch (Exception e) {
throw new JsonException(
"Failed to deep clone object using JSON",
e
);
}
}
}

View File

@ -1,347 +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 Collection.java
* LastUpdate 2025-09-09 08:37:33
* 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);
}
}

View File

@ -1,579 +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 ForEach.java
* LastUpdate 2025-09-09 08:37:33
* 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);
}
}

View File

@ -1,656 +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 ForEach.java
* LastUpdate 2025-09-09 08:37:33
* 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);
}
}

View File

@ -1,475 +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 Lists.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.collection;
import static com.mingliqiye.utils.collection.Collection.findFirst;
import com.github.f4b6a3.uuid.util.internal.RandomUtil;
import com.mingliqiye.utils.random.RandomInt;
import java.util.*;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Lists工具类提供了一系列创建List实现的便捷方法
*
* @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 <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
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,167 +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 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;
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile 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;
}
}

View File

@ -1,105 +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 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;
}
}

View File

@ -1,367 +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 FileUtil.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.file;
import com.mingliqiye.utils.string.StringUtil;
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;
import lombok.Getter;
import lombok.Setter;
/**
* 文件工具类提供常用的文件操作方法
*
* @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 (StringUtil.isEmpty(fileName)) {
return "";
}
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
return "";
}
return fileName.substring(lastDotIndex + 1);
}
/**
* 获取不带扩展名的文件名
*
* @param fileName 文件名
* @return 不带扩展名的文件名
*/
public static String getFileNameWithoutExtension(String fileName) {
if (StringUtil.isEmpty(fileName)) {
return "";
}
int lastDotIndex = fileName.lastIndexOf('.');
if (lastDotIndex == -1) {
return fileName;
}
return fileName.substring(0, lastDotIndex);
}
/**
* 读取文件内容为字节数组
*
* @param 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);
}
}
}
}

View File

@ -1,93 +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 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();
}
}

View File

@ -1,39 +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 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
);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,28 +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 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);
}

View File

@ -1,114 +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 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-256MD5
* @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);
}
}

View File

@ -1,69 +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 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;
}
}

View File

@ -1,186 +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 Range.java
* LastUpdate 2025-09-12 17:12:29
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.iterator;
import lombok.Getter;
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> {
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;
}
}
};
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile FieldStructure.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.jna;
import com.sun.jna.Structure;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* @author MingLiPro
*/
public class FieldStructure extends Structure {
@Override
protected List<String> getFieldOrder() {
List<String> fieldOrderList = new ArrayList<>();
for (
Class<?> cls = getClass();
!cls.equals(FieldStructure.class);
cls = cls.getSuperclass()
) {
Field[] fields = cls.getDeclaredFields();
int modifiers;
for (Field field : fields) {
modifiers = field.getModifiers();
if (
Modifier.isStatic(modifiers) ||
!Modifier.isPublic(modifiers)
) {
continue;
}
fieldOrderList.add(field.getName());
}
}
return fieldOrderList;
}
}

View File

@ -1,187 +0,0 @@
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());
}
}

View File

@ -1,341 +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 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字符串解析为复杂泛型结构的对象如ListMap等
*
* @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())
);
}
}

View File

@ -1,390 +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 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);
}

View File

@ -1,38 +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 JsonException.java
* LastUpdate 2025-09-09 09:25:08
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
public class JsonException extends RuntimeException {
public JsonException(String message) {
super(message);
}
public JsonException(String message, Throwable cause) {
super(message, cause);
}
public JsonException(Throwable cause) {
this(cause.getMessage(), cause);
}
}

View File

@ -1,175 +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 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 JacksonGsonFastjson
*
* @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());
}
}

View File

@ -1,253 +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 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())
);
}
};
}
};
}
}

View File

@ -1,32 +0,0 @@
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
);
}
}

View File

@ -1,70 +0,0 @@
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);
};
}
}

View File

@ -1,50 +0,0 @@
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);
}
};
}
}

View File

@ -1,91 +0,0 @@
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;
}
}

View File

@ -1,60 +0,0 @@
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);
}
}

View File

@ -1,27 +0,0 @@
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);
}
}

View File

@ -1,57 +0,0 @@
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.StringUtil;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.val;
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 StringUtil.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(StringUtil.format("old-{}", path), s);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Description.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Description {
private String text;
private Extra[] extra;
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Extra.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Extra {
private String text;
private String color;
private Boolean bold;
private Boolean italic;
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile 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;
}

View File

@ -1,219 +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 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 值截断为无符号 short2 字节并按大端序写入字节数组
*
* @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); // 读取并解析服务器响应
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile 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;
}

View File

@ -1,217 +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 NetworkAddress.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtil;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
/**
* 网络地址类用于表示一个网络地址IP或域名并提供相关操作
* 支持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 表示 IPv46 表示 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 表示IPv46 表示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(
StringUtil.format("[{}] 不是有效的IPv4或IPv6地址", ip)
);
}
/**
* 将当前 NetworkAddress 转换为 InetAddress 对象
*
* @return InetAddress 对象
*/
public InetAddress toInetAddress() {
try {
return InetAddress.getByName(ip != null ? ip : domain);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
/**
* 返回 NetworkAddress 的字符串表示形式
*
* @return 字符串表示
*/
public String toString() {
return isdom
? StringUtil.format(
"NetworkAddress(IP='{}',type='{}'," + "domain='{}')",
ip,
IPv,
domain
)
: StringUtil.format("NetworkAddress(IP='{}',type='{}')", ip, IPv);
}
}

View File

@ -1,163 +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 NetworkEndpoint.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtil;
import java.io.Serializable;
import java.net.InetSocketAddress;
import lombok.Getter;
/**
* 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 StringUtil.format(
"{}:{}",
networkAddress.getIp(),
networkPort.getPort()
);
}
/**
* 返回NetworkEndpoint的详细字符串表示形式
* 格式NetworkEndpoint(IP=...,Port=...,Endpoint=...)
*
* @return 包含详细信息的字符串
*/
public String toString() {
return StringUtil.format(
"NetworkEndpoint(IP={},Port={},Endpoint={})",
networkAddress.getIp(),
networkPort.getPort(),
toHostPortString()
);
}
/**
* 获取主机名或IP地址字符串
*
* @return 主机名或IP地址
*/
public String getHost() {
return networkAddress.getIp();
}
/**
* 获取端口号
*
* @return 端口号
*/
public Integer getPort() {
return networkPort.getPort();
}
}

View File

@ -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 NetworkPort.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtil;
import java.io.Serializable;
import lombok.Getter;
/**
* 网络端口类
*
* @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(
StringUtil.format("{} 不是正确的端口号", port)
);
}
}
}

View File

@ -1,226 +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 OsPath.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.path;
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;
import org.jetbrains.annotations.NotNull;
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();
}
}

View File

@ -1,111 +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 AutoConfiguration.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.springboot.autoconfigure;
import com.mingliqiye.utils.collection.ForEach;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.time.Formatter;
import java.io.IOException;
import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
@org.springframework.boot.autoconfigure.AutoConfiguration
@EnableConfigurationProperties(AutoConfiguration.class)
@ComponentScan(
{
"com.mingliqiye.utils.bean.springboot",
"com.mingliqiye.utils.springboot.converters",
}
)
public class AutoConfiguration {
private static final String banner =
"---------------------------------------------------------\n" +
"| $$\\ $$\\ $$\\ $$\\ $$\\ $$$$$$$$\\ $$$$$$\\ |\n" +
"| $$$\\ $$$ |$$ | $$ | $$ |\\__$$ __|$$ __$$\\ |\n" +
"| $$$$\\ $$$$ |$$ | $$ | $$ | $$ | $$ / \\__| |\n" +
"| $$\\$$\\$$ $$ |$$ | $$ | $$ | $$ | \\$$$$$$\\ |\n" +
"| $$ \\$$$ $$ |$$ | $$ | $$ | $$ | \\____$$\\ |\n" +
"| $$ |\\$ /$$ |$$ | $$ | $$ | $$ | $$\\ $$ | |\n" +
"| $$ | \\_/ $$ |$$$$$$$$\\\\$$$$$$ | $$ | \\$$$$$$ | |\n" +
"| \\__| \\__|\\________|\\______/ \\__| \\______/ |\n";
private static String banner2;
private final Logger log = LoggerFactory.getLogger(
"MingliUtils-AutoConfiguration"
);
public AutoConfiguration() {
printBanner();
log.info("MingliUtils AutoConfiguration succeed");
}
public static void printBanner() {
StringBuilder bannerBuilder = new StringBuilder(banner);
try (
InputStream inputStream =
AutoConfiguration.class.getResourceAsStream(
"/META-INF/meta-data"
)
) {
if (inputStream == null) {
return;
}
int readlen;
byte[] buffer = new byte[1024];
StringBuilder metaData = new StringBuilder();
while ((readlen = inputStream.read(buffer)) != -1) {
metaData.append(new String(buffer, 0, readlen));
}
ForEach.forEach(metaData.toString().split("\n"), (s, i) -> {
String[] d = s.trim().split("=", 2);
if (d.length >= 2) {
String content = "| " + d[0] + ": " + d[1];
int targetLength = 56;
if (content.length() < targetLength) {
bannerBuilder.append(
String.format("%-" + targetLength + "s|\n", content)
);
} else {
bannerBuilder
.append(content, 0, targetLength)
.append("|\n");
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
banner2 = bannerBuilder.toString();
System.out.printf(
banner2,
DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7)
);
System.out.println(
"---------------------------------------------------------"
);
}
}

View File

@ -1,73 +0,0 @@
package com.mingliqiye.utils.springboot.autoconfigure;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mingliqiye.utils.json.GsonJsonApi;
import com.mingliqiye.utils.json.JsonApi;
import com.mingliqiye.utils.json.converters.DateTimeJsonConverter;
import com.mingliqiye.utils.json.converters.JsonStringConverter;
import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.uuid.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.gson.GsonBuilderCustomizer;
import org.springframework.context.annotation.Bean;
@ConditionalOnClass(Gson.class)
@AutoConfiguration
@AutoConfigureAfter(
name = {
"org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration",
"com.mingliqiye.utils.springboot.autoconfigure.JacksonAutoConfiguration",
}
)
public class GsonAutoConfiguration {
private static final Logger log = LoggerFactory.getLogger(
"MingliUtils-GsonAutoConfiguration"
);
public static GsonBuilder addTypeAdapter(GsonBuilder gsonBuilder) {
JsonStringConverter<DateTime> dateTimeJsonConverter =
new DateTimeJsonConverter();
JsonStringConverter<UUID> uuidJsonStringConverter =
new UUIDJsonStringConverter();
try {
return gsonBuilder
.registerTypeAdapter(
uuidJsonStringConverter.getTClass(),
dateTimeJsonConverter
.getGsonJsonStringConverterAdapter()
.getGsonTypeAdapter()
)
.registerTypeAdapter(
dateTimeJsonConverter.getTClass(),
dateTimeJsonConverter
.getGsonJsonStringConverterAdapter()
.getGsonTypeAdapter()
);
} finally {
log.info("MingliUtils GsonBuilder TypeAdapter add");
}
}
@Bean
public GsonBuilderCustomizer mingliGsonCustomizer() {
return GsonAutoConfiguration::addTypeAdapter;
}
@Bean
@ConditionalOnMissingBean
public JsonApi jsonApi(Gson gson) {
log.info(
"MingliUtils-JsonApiAutoConfiguration: GsonJsonApi bean is created."
);
return new GsonJsonApi(gson);
}
}

View File

@ -1,58 +0,0 @@
package com.mingliqiye.utils.springboot.autoconfigure;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mingliqiye.utils.json.JacksonJsonApi;
import com.mingliqiye.utils.json.JsonApi;
import com.mingliqiye.utils.json.converters.DateTimeJsonConverter;
import com.mingliqiye.utils.json.converters.UUIDJsonStringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
@ConditionalOnClass(ObjectMapper.class)
@AutoConfiguration
@AutoConfigureAfter(
name = {
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration",
}
)
public class JacksonAutoConfiguration {
private static final Logger log = LoggerFactory.getLogger(
"MingliUtils-JacksonAutoConfiguration"
);
public JacksonAutoConfiguration(ObjectMapper objectMapper) {
addModules(objectMapper);
log.info("MingliUtils Jackson Serializers created");
}
public static ObjectMapper addModules(ObjectMapper objectMapper) {
return objectMapper
.registerModule(
new DateTimeJsonConverter()
.getJacksonJsonStringConverterAdapter()
.getJacksonModule()
)
.registerModule(
new UUIDJsonStringConverter()
.getJacksonJsonStringConverterAdapter()
.getJacksonModule()
);
}
@Bean
@Primary
@ConditionalOnMissingBean
public JsonApi jsonApi(ObjectMapper objectMapper) {
log.info(
"MingliUtils-JsonApiAutoConfiguration: JacksonJsonApi bean is created."
);
return new JacksonJsonApi(objectMapper);
}
}

View File

@ -1,25 +0,0 @@
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);
}
}

View File

@ -1,25 +0,0 @@
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);
}
}

View File

@ -1,20 +0,0 @@
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);
}
}

View File

@ -1,20 +0,0 @@
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();
}
}

View File

@ -1,279 +0,0 @@
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>
* 实现了 AutoCloseableCloseable 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;
}
}

View File

@ -1,99 +0,0 @@
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;
}
}

View File

@ -1,98 +0,0 @@
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);
}
}

View File

@ -1,81 +0,0 @@
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);
}
}

View File

@ -15,19 +15,20 @@
* *
* ProjectName mingli-utils * ProjectName mingli-utils
* ModuleName mingli-utils.main * ModuleName mingli-utils.main
* CurrentFile Players.java * CurrentFile StreamEmptyException.java
* LastUpdate 2025-09-09 08:37:33 * LastUpdate 2025-09-20 13:24:07
* UpdateUser MingLiPro * UpdateUser MingLiPro
*/ */
package com.mingliqiye.utils.minecraft.slp; package com.mingliqiye.utils.stream;
import lombok.Data; public class StreamEmptyException extends java.lang.RuntimeException {
@Data public StreamEmptyException(String message) {
public class Players { super(message);
}
private int max; public StreamEmptyException(String message, Throwable cause) {
private int online; super(message, cause);
private PlayerSample[] sample; }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetIdable<T> extends Getable<T> {
T getId();
default T get() {
return getId();
}
}

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetKeyable<T> {
T getKey();
default T get() {
return getKey();
}
}

View File

@ -1,9 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface GetNameable<T> extends Getable<T> {
T getName();
default T get() {
return getName();
}
}

View File

@ -1,5 +0,0 @@
package com.mingliqiye.utils.stream.interfaces;
public interface Getable<T> {
T get();
}

View File

@ -1,271 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile StringUtil.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.string;
import com.mingliqiye.utils.collection.Lists;
import com.mingliqiye.utils.functions.P1RFunction;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 字符串工具类提供常用的字符串处理方法
*/
public class StringUtil {
/**
* 将对象转换为字符串表示形式
*
* @param obj 需要转换的对象可以为null
* @return 如果对象为null则返回空字符串否则返回对象的字符串表示
*/
public static String toString(Object obj) {
// 如果对象为null返回空字符串否则调用对象的toString方法
return obj == null ? "" : obj.toString();
}
/**
* 格式化字符串将格式字符串中的占位符{}替换为对应的参数值<br>
* 示例输出 {} StringUtil.format("{},{},{}", "666", "{}", "777") - "666,{},777"<br>
* 示例 StringUtil.format("{},{},{},{}", "666", "{}", "777") - "666,{},777,"<br>
* 没有实际{} 会替换为 "" 空字符串
*
* @param format 格式字符串使用{}作为占位符如果为null则返回null
* @param args 用于替换占位符的参数数组
* @return 格式化后的字符串
*/
public static String format(String format, Object... args) {
if (format == null) {
return null;
}
StringBuilder sb = new StringBuilder();
int placeholderCount = 0;
int lastIndex = 0;
int len = format.length();
for (int i = 0; i < len - 1; i++) {
if (format.charAt(i) == '{' && format.charAt(i + 1) == '}') {
// 添加前面的部分
sb.append(format, lastIndex, i);
// 替换为 MessageFormat 占位符 {index}
sb.append('{').append(placeholderCount).append('}');
placeholderCount++;
i++; // 跳过 '}'
lastIndex = i + 1;
}
}
// 添加剩余部分
sb.append(format.substring(lastIndex));
// 构造实际参数数组
Object[] actualArgs;
if (args.length < placeholderCount) {
actualArgs = new String[placeholderCount];
System.arraycopy(args, 0, actualArgs, 0, args.length);
for (int i = args.length; i < placeholderCount; i++) {
actualArgs[i] = "";
}
} else {
actualArgs = args;
}
// 如果没有占位符直接返回格式化后的字符串
if (placeholderCount == 0) {
return sb.toString();
}
try {
return MessageFormat.format(
sb.toString(),
(Object[]) Lists.toStringList(actualArgs)
);
} catch (IllegalArgumentException e) {
// 返回原始格式化字符串或抛出自定义异常视业务需求而定
return sb.toString();
}
}
/**
* 判断字符串是否为空
*
* @param str 待检查的字符串
* @return 如果字符串为null或空字符串则返回true否则返回false
*/
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
/**
* 使用指定的分隔符将多个对象连接成一个字符串
*
* @param spec 用作分隔符的字符串
* @param objects 要连接的对象数组
* @return 使用指定分隔符连接后的字符串
*/
public static String joinOf(String spec, String... objects) {
return join(spec, Arrays.asList(objects));
}
/**
* 将字符串按照指定分隔符分割成字符串列表并移除列表开头的空字符串元素
*
* @param str 待分割的字符串
* @param separator 用作分割符的字符串
* @return 分割后的字符串列表不包含开头的空字符串元素
*/
public static List<String> split(String str, String separator) {
List<String> data = new ArrayList<>(
Arrays.asList(str.split(separator))
);
// 移除列表开头的所有空字符串元素
while (!data.isEmpty() && data.get(0).isEmpty()) {
data.remove(0);
}
return data;
}
/**
* 将列表中的元素按照指定分隔符连接成字符串
*
* @param <P> 列表元素的类型
* @param separator 分隔符用于连接各个元素
* @param list 待连接的元素列表
* @param fun 转换函数用于将列表元素转换为字符串如果为null则使用toString()方法
* @return 连接后的字符串如果列表为空或null则返回空字符串
*/
public static <P> String join(
String separator,
List<P> list,
P1RFunction<P, String> fun
) {
// 处理空列表情况
if (list == null || list.isEmpty()) {
return "";
}
// 构建结果字符串
StringBuilder sb = StringUtil.stringBuilder(list.size() * 16);
for (int i = 0; i < list.size(); i++) {
P item = list.get(i);
// 将元素转换为字符串
String itemStr = fun == null
? (item == null ? "null" : item.toString())
: fun.call(item);
// 第一个元素直接添加其他元素先添加分隔符再添加元素
if (i == 0) {
sb.append(itemStr);
} else {
sb.append(separator).append(itemStr);
}
}
return sb.toString();
}
/**
* 使用指定分隔符连接字符串列表
*
* @param separator 分隔符不能为null
* @param list 字符串列表不能为null
* @return 连接后的字符串
* @throws IllegalArgumentException 当separator或list为null时抛出
*/
public static String join(String separator, List<String> list) {
if (separator == null) {
throw new IllegalArgumentException("Separator cannot be null");
}
if (list == null) {
throw new IllegalArgumentException("List cannot be null");
}
return join(separator, list, null);
}
/**
* 创建一个新的StringBuilder实例
*
* @param i 指定StringBuilder的初始容量
* @return 返回一个新的StringBuilder对象其初始容量为指定的大小
*/
public static StringBuilder stringBuilder(int i) {
return new StringBuilder(i);
}
/**
* 将字符串转换为Unicode编码格式
*
* @param str 待转换的字符串
* @return 转换后的Unicode编码字符串每个字符都以\\u开头的十六进制形式表示
*/
public static String stringToUnicode(String str) {
StringBuilder sb = new StringBuilder();
char[] c = str.toCharArray();
for (char value : c) {
sb.append(stringToUnicode(value));
}
return sb.toString();
}
/**
* 将字符转换为Unicode转义字符串
*
* @param c 需要转换的字符
* @return 返回格式为"\\uXXXX"的Unicode转义字符串其中XXXX为字符的十六进制Unicode码点
*/
public static String stringToUnicode(char c) {
return "\\u" + String.format("%04x", (int) c);
}
/**
* 将整数转换为Unicode字符串表示形式
*
* @param c 要转换的整数表示Unicode码点
* @return 返回格式为"\\uXXXX"的Unicode字符串其中XXXX是参数c的十六进制表示
*/
public static String stringToUnicode(Integer c) {
return "\\u" + Integer.toHexString(c);
}
/**
* 将Unicode编码字符串转换为普通字符串
* 该函数接收一个包含Unicode转义序列的字符串将其解析并转换为对应的字符序列
*
* @param unicode 包含Unicode转义序列的字符串格式如"\\uXXXX"其中XXXX为十六进制数
* @return 转换后的普通字符串包含对应的Unicode字符
*/
public static String unicodeToString(String unicode) {
StringBuilder sb = new StringBuilder();
// 按照Unicode转义符分割字符串得到包含十六进制编码的数组
String[] hex = unicode.split("\\\\u");
// 从索引1开始遍历因为分割后的第一个元素是转义符前面的内容可能为空
for (int i = 1; i < hex.length; i++) {
// 将十六进制字符串转换为整数作为字符的Unicode码点
int index = Integer.parseInt(hex[i], 16);
// 将Unicode码点转换为对应字符并添加到结果中
sb.append((char) index);
}
return sb.toString();
}
}

View File

@ -1,221 +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 SystemUtil.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.system;
import com.mingliqiye.utils.collection.Lists;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* 系统工具类提供操作系统类型判断和JDK版本检测功能
*
* @author MingLiPro
*/
public class SystemUtil {
private static final String osName = System.getProperties().getProperty(
"os.name"
);
/**
* 判断当前操作系统是否为Windows系统
*
* @return 如果是Windows系统返回true否则返回false
*/
public static boolean isWindows() {
return osName != null && osName.startsWith("Windows");
}
/**
* 判断当前操作系统是否为Mac系统
*
* @return 如果是Mac系统返回true否则返回false
*/
public static boolean isMac() {
return osName != null && osName.startsWith("Mac");
}
/**
* 判断当前操作系统是否为Unix/Linux系统
*
* @return 如果是Unix/Linux系统返回true否则返回false
*/
public static boolean isUnix() {
if (osName == null) {
return false;
}
return (
osName.startsWith("Linux") ||
osName.startsWith("AIX") ||
osName.startsWith("SunOS") ||
osName.startsWith("Mac OS X") ||
osName.startsWith("FreeBSD")
);
}
/**
* 获取JDK版本号
*
* @return JDK版本号字符串
*/
public static String getJdkVersion() {
return System.getProperty("java.specification.version");
}
/**
* 获取Java版本号的整数形式
*
* @return Java版本号的整数形式81117等
*/
public static Integer getJavaVersionAsInteger() {
String version = getJdkVersion();
if (version == null || version.isEmpty()) {
throw new IllegalStateException(
"Unable to determine Java version from property 'java.specification.version'"
);
}
String uversion;
if (version.startsWith("1.")) {
if (version.length() < 3) {
throw new IllegalStateException(
"Invalid Java version format: " + version
);
}
uversion = version.substring(2, 3);
} else {
if (version.length() < 2) {
throw new IllegalStateException(
"Invalid Java version format: " + version
);
}
uversion = version.substring(0, 2);
}
return Integer.parseInt(uversion);
}
/**
* 判断当前JDK版本是否大于8
*
* @return 如果JDK版本大于8返回true否则返回false
*/
public static boolean isJdk8Plus() {
return getJavaVersionAsInteger() > 8;
}
/**
* 获取本地IP地址数组
*
* @return 本地IP地址字符串数组
* @throws RuntimeException 当获取网络接口信息失败时抛出
*/
public static String[] getLocalIps() {
try {
List<String> ipList = new ArrayList<>();
Enumeration<NetworkInterface> interfaces =
NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
// 跳过回环接口和虚拟接口
if (
networkInterface.isLoopback() ||
networkInterface.isVirtual() ||
!networkInterface.isUp()
) {
continue;
}
Enumeration<InetAddress> addresses =
networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
// 只获取IPv4地址
if (address instanceof Inet4Address) {
ipList.add(address.getHostAddress());
}
}
}
return ipList.toArray(new String[0]);
} catch (SocketException e) {
throw new RuntimeException("Failed to get local IP addresses", e);
}
}
/**
* 获取本地IP地址列表
*
* @return 本地IP地址的字符串列表
*/
public static List<String> getLocalIpsByList() {
return Lists.newArrayList(getLocalIps());
}
/**
* 获取本地回环地址
*
* @return 回环地址字符串通常为"127.0.0.1"
*/
public static String[] getLoopbackIps() {
List<String> strings = new ArrayList<>(3);
try {
Enumeration<NetworkInterface> interfaces =
NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
// 只处理回环接口
if (networkInterface.isLoopback() && networkInterface.isUp()) {
Enumeration<InetAddress> addresses =
networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
strings.add(address.getHostAddress());
}
}
}
return strings.toArray(new String[0]);
} catch (SocketException e) {
// 可考虑添加日志记录
return new String[] { "127.0.0.1" };
}
}
/**
* 获取本地回环地址IP列表
*
* @return 本地回环地址IP字符串列表的副本
*/
public static List<String> getLoopbackIpsByList() {
// 将本地回环地址IP数组转换为列表并返回
return Lists.newArrayList(getLoopbackIps());
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Main.java
* LastUpdate 2025-09-12 12:19:48
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.test;
import com.mingliqiye.utils.version.VersionUtils;
public class Main {
public static void main(String[] args) {
System.out.println(VersionUtils.is("1.3", "1.2.3"));
}
}

View File

@ -1,538 +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 DateTime.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.time;
import com.mingliqiye.utils.jna.time.WinKernel32;
import com.mingliqiye.utils.system.SystemUtil;
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 lombok.Getter;
import lombok.Setter;
import lombok.var;
import org.jetbrains.annotations.NotNull;
/**
* 时间类用于处理日期时间的转换格式化等操作
* 提供了多种静态方法来创建 DateTime 实例并支持与 DateLocalDateTime 等类型的互转
*<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 WinKernel32 WIN_KERNEL_32;
private static final long FILETIME_EPOCH_OFFSET = -116444736000000000L;
private static final long NANOS_PER_100NS = 100;
static {
if (!SystemUtil.isJdk8Plus() && SystemUtil.isWindows()) {
WIN_KERNEL_32 = WinKernel32.load();
} else {
WIN_KERNEL_32 = 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 != null) {
byte[] fileTimeBuffer = new byte[8];
WIN_KERNEL_32.GetSystemTimePreciseAsFileTime(fileTimeBuffer);
long fileTime =
(long) (fileTimeBuffer[0] & 0xFF) |
((long) (fileTimeBuffer[1] & 0xFF) << 8) |
((long) (fileTimeBuffer[2] & 0xFF) << 16) |
((long) (fileTimeBuffer[3] & 0xFF) << 24) |
((long) (fileTimeBuffer[4] & 0xFF) << 32) |
((long) (fileTimeBuffer[5] & 0xFF) << 40) |
((long) (fileTimeBuffer[6] & 0xFF) << 48) |
((long) (fileTimeBuffer[7] & 0xFF) << 56);
long unixNanos =
(fileTime + FILETIME_EPOCH_OFFSET) * NANOS_PER_100NS;
Instant instant = Instant.ofEpochSecond(
unixNanos / 1_000_000_000L,
unixNanos % 1_000_000_000L
);
return DateTime.of(
instant.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());
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile 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);
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile 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; // 近似值
}

Some files were not shown because too many files have changed in this diff Show More