generated from mingliqiye/lib-tem
Compare commits
5 Commits
1509597032
...
00c1be6387
| Author | SHA1 | Date | |
|---|---|---|---|
| 00c1be6387 | |||
| 2063d86097 | |||
| 2db24530d6 | |||
| 2bcd4b329c | |||
| a081744f14 |
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils
|
||||
* CurrentFile build.gradle.kts
|
||||
* LastUpdate 2025-09-21 15:36:59
|
||||
* LastUpdate 2026-01-08 11:10:03
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -69,14 +69,14 @@ dependencies {
|
||||
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.mindrot:jbcrypt:0.4")
|
||||
|
||||
compileOnly("org.springframework.boot:spring-boot-starter:2.7.14")
|
||||
compileOnly("com.fasterxml.jackson.core:jackson-databind:2.19.2")
|
||||
compileOnly("com.google.code.gson:gson:2.13.1")
|
||||
compileOnly("org.mybatis:mybatis:3.5.19")
|
||||
compileOnly("com.alibaba.fastjson2:fastjson2:2.0.58")
|
||||
compileOnly("io.netty:netty-all:4.1.130.Final")
|
||||
|
||||
compileOnly("com.baomidou:mybatis-plus-core:3.0.1")
|
||||
compileOnly("net.java.dev.jna:jna:5.17.0")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright 2025 mingliqiye
|
||||
# Copyright 2026 mingliqiye
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,13 +16,13 @@
|
||||
# ProjectName mingli-utils
|
||||
# ModuleName mingli-utils
|
||||
# CurrentFile gradle.properties
|
||||
# LastUpdate 2025-09-21 15:38:52
|
||||
# LastUpdate 2026-01-08 13:20:25
|
||||
# UpdateUser MingLiPro
|
||||
#
|
||||
JDKVERSIONS=1.8
|
||||
GROUPSID=com.mingliqiye.utils
|
||||
ARTIFACTID=mingli-utils
|
||||
VERSIONS=4.1.9
|
||||
VERSIONS=4.3.2
|
||||
signing.keyId=B22AA93B
|
||||
signing.password=
|
||||
signing.secretKeyRingFile=secret.gpg
|
||||
|
||||
42
src/main/kotlin/com/mingliqiye/utils/Main.kt
Normal file
42
src/main/kotlin/com/mingliqiye/utils/Main.kt
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2026 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.kt
|
||||
* LastUpdate 2026-01-06 14:04:14
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils
|
||||
|
||||
import com.mingliqiye.utils.network.NetworkEndpoint
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
fun main() {
|
||||
val byteBuffer = ByteBuffer.allocate(320)
|
||||
NetworkEndpoint
|
||||
.of("0:65532")
|
||||
.writeIpv4toByteBuffer(byteBuffer)
|
||||
|
||||
UUID.getMaxUUID().writeToByteBuffer(byteBuffer)
|
||||
|
||||
byteBuffer.flip()
|
||||
|
||||
println(NetworkEndpoint.ofIpv4(byteBuffer))
|
||||
println(UUID.of(byteBuffer))
|
||||
|
||||
}
|
||||
205
src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt
Normal file
205
src/main/kotlin/com/mingliqiye/utils/bytes/ByteBufferUtils.kt
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2026 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 ByteBufferUtils.kt
|
||||
* LastUpdate 2026-01-07 10:01:45
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@file:JvmName("ByteBufferUtil")
|
||||
|
||||
package com.mingliqiye.utils.bytes
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* 将字符串以指定字符集编码后写入 [ByteBuffer],并在末尾追加一个空字节(`0x00`)作为字符串终止符。
|
||||
*
|
||||
* 此方法适用于需要 C 风格字符串(null-terminated string)的协议或场景。
|
||||
*
|
||||
* @param string 要写入的字符串,不可为 null
|
||||
* @param charset 字符编码,默认为 [Charsets.UTF_8]
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
*/
|
||||
fun ByteBuffer.putString(string: String, charset: Charset = Charsets.UTF_8): ByteBuffer =
|
||||
this.put(string.toByteArray(charset)).put(0x00)
|
||||
|
||||
/**
|
||||
* 从 [ByteBuffer] 中读取一个以空字节(`0x00`)结尾的字符串。
|
||||
*
|
||||
* 该方法会持续读取字节,直到遇到第一个 `0x00`(null terminator)为止,并将之前读取的字节按指定字符集解码为字符串。
|
||||
* **注意**:此操作会修改缓冲区的位置(position),且不处理缓冲区越界情况(若无终止符会抛出异常)。
|
||||
*
|
||||
* @param charset 字符编码,默认为 [Charsets.UTF_8]
|
||||
* @return 解码后的字符串(不含终止符)
|
||||
* @throws BufferUnderflowException 如果缓冲区中没有足够的字节(即未找到终止符)
|
||||
*/
|
||||
fun ByteBuffer.getString(charset: Charset = Charsets.UTF_8): String {
|
||||
val data = ArrayList<Byte>()
|
||||
while (true) {
|
||||
val byte = this.get()
|
||||
if (byte == 0x00.toByte()) {
|
||||
break
|
||||
}
|
||||
data.add(byte)
|
||||
}
|
||||
return String(data.toByteArray(), charset)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 [ByteBuffer] 中剩余的全部字节读取为一个 [ByteArray]。
|
||||
*
|
||||
* 此方法会读取从当前位置到 limit 之间的所有字节,并推进 position。
|
||||
*
|
||||
* @return 包含剩余字节的新字节数组
|
||||
*/
|
||||
fun ByteBuffer.toByteArray(): ByteArray {
|
||||
val ba = ByteArray(this.remaining())
|
||||
this.get(ba)
|
||||
return ba
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个布尔列表(长度必须为 8)转换为 [ByteFlags] 并写入 [ByteBuffer]。
|
||||
*
|
||||
* 列表索引 0~7 分别对应位 b0~b7(b0 为最低有效位)。
|
||||
*
|
||||
* @param bit 长度为 8 的布尔列表,表示 8 个位的状态
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
* @throws IndexOutOfBoundsException 如果列表长度不足 8
|
||||
*/
|
||||
fun ByteBuffer.putByteFlags(
|
||||
bit: List<Boolean> = List(8) { false },
|
||||
): ByteBuffer = this.putByteFlags(
|
||||
ByteFlags(
|
||||
bit[0],
|
||||
bit[1],
|
||||
bit[2],
|
||||
bit[3],
|
||||
bit[4],
|
||||
bit[5],
|
||||
bit[6],
|
||||
bit[7],
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* 将一个布尔数组(长度必须为 8)转换为 [ByteFlags] 并写入 [ByteBuffer]。
|
||||
*
|
||||
* 数组索引 0~7 分别对应位 b0~b7(b0 为最低有效位)。
|
||||
*
|
||||
* @param bit 长度为 8 的布尔数组
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
* @throws IndexOutOfBoundsException 如果数组长度不足 8
|
||||
*/
|
||||
fun ByteBuffer.putByteFlags(
|
||||
bit: BooleanArray = BooleanArray(8),
|
||||
): ByteBuffer = this.putByteFlags(
|
||||
ByteFlags(
|
||||
bit[0],
|
||||
bit[1],
|
||||
bit[2],
|
||||
bit[3],
|
||||
bit[4],
|
||||
bit[5],
|
||||
bit[6],
|
||||
bit[7],
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* 将 [ByteFlags] 对象转换为字节并写入 [ByteBuffer]。
|
||||
*
|
||||
* @param byteFlags 要写入的位标志对象
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
*/
|
||||
fun ByteBuffer.putByteFlags(byteFlags: ByteFlags): ByteBuffer = this.put(byteFlags.toByte())
|
||||
|
||||
/**
|
||||
* 通过 8 个独立的布尔参数构造 [ByteFlags] 并写入 [ByteBuffer]。
|
||||
*
|
||||
* 参数顺序:`bit0`(LSB)到 `bit7`(MSB)。
|
||||
*
|
||||
* @param bit0 第 0 位(最低位)
|
||||
* @param bit1 第 1 位
|
||||
* @param bit2 第 2 位
|
||||
* @param bit3 第 3 位
|
||||
* @param bit4 第 4 位
|
||||
* @param bit5 第 5 位
|
||||
* @param bit6 第 6 位
|
||||
* @param bit7 第 7 位(最高位)
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
*/
|
||||
fun ByteBuffer.putByteFlags(
|
||||
bit0: Boolean = false,
|
||||
bit1: Boolean = false,
|
||||
bit2: Boolean = false,
|
||||
bit3: Boolean = false,
|
||||
bit4: Boolean = false,
|
||||
bit5: Boolean = false,
|
||||
bit6: Boolean = false,
|
||||
bit7: Boolean = false,
|
||||
): ByteBuffer = this.putByteFlags(
|
||||
ByteFlags(
|
||||
bit0,
|
||||
bit1,
|
||||
bit2,
|
||||
bit3,
|
||||
bit4,
|
||||
bit5,
|
||||
bit6,
|
||||
bit7,
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* 从 [ByteBuffer] 中读取一个字节,并将其解析为 [ByteFlags] 对象。
|
||||
*
|
||||
* @return 表示该字节各位状态的 [ByteFlags] 实例
|
||||
*/
|
||||
fun ByteBuffer.getByteFlags(): ByteFlags = ByteFlags(this.get())
|
||||
|
||||
/**
|
||||
* 从 [ByteBuffer] 中读取一个字节,并将其解释为布尔值。
|
||||
*
|
||||
* 约定:`0x01` 表示 `true`,其他值(包括 `0x00`)均视为 `false`。
|
||||
*
|
||||
* @return 布尔值
|
||||
*/
|
||||
fun ByteBuffer.getBoolean(): Boolean = this.get() == 0x01.toByte()
|
||||
|
||||
/**
|
||||
* 将布尔值写入 [ByteBuffer]。
|
||||
*
|
||||
* 约定:`true` 写为 `0x01`,`false` 写为 `0x00`。
|
||||
*
|
||||
* @param boolean 要写入的布尔值
|
||||
* @return 当前 [ByteBuffer] 实例(支持链式调用)
|
||||
*/
|
||||
fun ByteBuffer.putBoolean(boolean: Boolean): ByteBuffer = this.put(if (boolean) 0x01 else 0x00)
|
||||
|
||||
/**
|
||||
* 将当前字节数组包装为一个只读的 [ByteBuffer]。
|
||||
*
|
||||
* 使用 [ByteBuffer.wrap] 创建,position 初始为 0,limit 为数组长度。
|
||||
*
|
||||
* @return 包装后的 [ByteBuffer] 实例
|
||||
*/
|
||||
fun ByteArray.toByteBuffer(): ByteBuffer {
|
||||
return ByteBuffer.wrap(this)
|
||||
}
|
||||
460
src/main/kotlin/com/mingliqiye/utils/bytes/ByteFlags.kt
Normal file
460
src/main/kotlin/com/mingliqiye/utils/bytes/ByteFlags.kt
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright 2026 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 ByteFlags.kt
|
||||
* LastUpdate 2026-01-07 09:37:09
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.bytes
|
||||
|
||||
/**
|
||||
* 表示一个字节(8 位)的布尔标志集合。
|
||||
*
|
||||
* 每一位对应一个布尔值,其中:
|
||||
* - `b0` 表示最低有效位(LSB,bit 0,值为 0x01)
|
||||
* - `b7` 表示最高有效位(MSB,bit 7,值为 0x80)
|
||||
*
|
||||
* 该类支持从字节、布尔数组、二进制字符串等构造,并提供位操作、状态查询和格式化输出等功能。
|
||||
*/
|
||||
data class ByteFlags(
|
||||
/** 第 0 位(最低位,0x01) */
|
||||
var b0: Boolean = false,
|
||||
/** 第 1 位(0x02) */
|
||||
var b1: Boolean = false,
|
||||
/** 第 2 位(0x04) */
|
||||
var b2: Boolean = false,
|
||||
/** 第 3 位(0x08) */
|
||||
var b3: Boolean = false,
|
||||
/** 第 4 位(0x10) */
|
||||
var b4: Boolean = false,
|
||||
/** 第 5 位(0x20) */
|
||||
var b5: Boolean = false,
|
||||
/** 第 6 位(0x40) */
|
||||
var b6: Boolean = false,
|
||||
/** 第 7 位(最高位,0x80) */
|
||||
var b7: Boolean = false
|
||||
) {
|
||||
|
||||
/**
|
||||
* 通过一个 [Byte] 值构造 [ByteFlags] 实例。
|
||||
*
|
||||
* @param byte 用于初始化的字节值(仅使用低 8 位)
|
||||
*/
|
||||
constructor(byte: Byte) : this() {
|
||||
fromByte(byte)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从给定的 [Byte] 值解析并设置各个位标志。
|
||||
*
|
||||
* @param byte 要解析的字节
|
||||
*/
|
||||
fun fromByte(byte: Byte) {
|
||||
val value = byte.toInt() and 0xFF
|
||||
b0 = (value and 0x01) != 0
|
||||
b1 = (value and 0x02) != 0
|
||||
b2 = (value and 0x04) != 0
|
||||
b3 = (value and 0x08) != 0
|
||||
b4 = (value and 0x10) != 0
|
||||
b5 = (value and 0x20) != 0
|
||||
b6 = (value and 0x40) != 0
|
||||
b7 = (value and 0x80) != 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前标志状态转换为一个 [Byte] 值。
|
||||
*
|
||||
* @return 对应的字节值(范围 0x00 ~ 0xFF,以有符号字节形式返回)
|
||||
*/
|
||||
fun toByte(): Byte {
|
||||
var result = 0
|
||||
if (b0) result = result or 0x01
|
||||
if (b1) result = result or 0x02
|
||||
if (b2) result = result or 0x04
|
||||
if (b3) result = result or 0x08
|
||||
if (b4) result = result or 0x10
|
||||
if (b5) result = result or 0x20
|
||||
if (b6) result = result or 0x40
|
||||
if (b7) result = result or 0x80
|
||||
return result.toByte()
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引(0~7)获取对应位的布尔值。
|
||||
*
|
||||
* @param index 位索引(0 = LSB, 7 = MSB)
|
||||
* @return 该位是否为 true
|
||||
* @throws IndexOutOfBoundsException 如果索引不在 0~7 范围内
|
||||
*/
|
||||
operator fun get(index: Int): Boolean {
|
||||
return when (index) {
|
||||
0 -> b0
|
||||
1 -> b1
|
||||
2 -> b2
|
||||
3 -> b3
|
||||
4 -> b4
|
||||
5 -> b5
|
||||
6 -> b6
|
||||
7 -> b7
|
||||
else -> throw IndexOutOfBoundsException("索引必须在0-7之间")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引(0~7)设置对应位的布尔值。
|
||||
*
|
||||
* @param index 位索引(0 = LSB, 7 = MSB)
|
||||
* @param value 要设置的布尔值
|
||||
* @throws IndexOutOfBoundsException 如果索引不在 0~7 范围内
|
||||
*/
|
||||
operator fun set(index: Int, value: Boolean) {
|
||||
when (index) {
|
||||
0 -> b0 = value
|
||||
1 -> b1 = value
|
||||
2 -> b2 = value
|
||||
3 -> b3 = value
|
||||
4 -> b4 = value
|
||||
5 -> b5 = value
|
||||
6 -> b6 = value
|
||||
7 -> b7 = value
|
||||
else -> throw IndexOutOfBoundsException("索引必须在0-7之间")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有 8 个位设置为 `true`。
|
||||
*/
|
||||
fun setAll() {
|
||||
b0 = true
|
||||
b1 = true
|
||||
b2 = true
|
||||
b3 = true
|
||||
b4 = true
|
||||
b5 = true
|
||||
b6 = true
|
||||
b7 = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有 8 个位设置为 `false`。
|
||||
*/
|
||||
fun clearAll() {
|
||||
b0 = false
|
||||
b1 = false
|
||||
b2 = false
|
||||
b3 = false
|
||||
b4 = false
|
||||
b5 = false
|
||||
b6 = false
|
||||
b7 = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 对所有位执行逻辑取反(true ↔ false)。
|
||||
*/
|
||||
fun toggleAll() {
|
||||
b0 = !b0
|
||||
b1 = !b1
|
||||
b2 = !b2
|
||||
b3 = !b3
|
||||
b4 = !b4
|
||||
b5 = !b5
|
||||
b6 = !b6
|
||||
b7 = !b7
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换指定索引位的状态(true 变 false,反之亦然)。
|
||||
*
|
||||
* @param index 要切换的位索引(0~7)
|
||||
* @throws IndexOutOfBoundsException 如果索引无效
|
||||
*/
|
||||
fun toggle(index: Int) {
|
||||
this[index] = !this[index]
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否所有位都为 `true`。
|
||||
*
|
||||
* @return 若全部为 true 则返回 true,否则 false
|
||||
*/
|
||||
fun allTrue(): Boolean {
|
||||
return b0 && b1 && b2 && b3 && b4 && b5 && b6 && b7
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否所有位都为 `false`。
|
||||
*
|
||||
* @return 若全部为 false 则返回 true,否则 false
|
||||
*/
|
||||
fun allFalse(): Boolean {
|
||||
return !b0 && !b1 && !b2 && !b3 && !b4 && !b5 && !b6 && !b7
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计值为 `true` 的位数量。
|
||||
*
|
||||
* @return true 位的个数(0~8)
|
||||
*/
|
||||
fun countTrue(): Int {
|
||||
var count = 0
|
||||
if (b0) count++
|
||||
if (b1) count++
|
||||
if (b2) count++
|
||||
if (b3) count++
|
||||
if (b4) count++
|
||||
if (b5) count++
|
||||
if (b6) count++
|
||||
if (b7) count++
|
||||
return count
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计值为 `false` 的位数量。
|
||||
*
|
||||
* @return false 位的个数(0~8)
|
||||
*/
|
||||
fun countFalse(): Int = 8 - countTrue()
|
||||
|
||||
/**
|
||||
* 通过位名称(如 "b0"、"bit3" 等)获取对应位的值。
|
||||
*
|
||||
* 支持别名:`bN` 或 `bitN`(不区分大小写)。
|
||||
*
|
||||
* @param name 位的名称(例如 "b0", "BIT5")
|
||||
* @return 对应位的布尔值
|
||||
* @throws IllegalArgumentException 如果名称无效
|
||||
*/
|
||||
fun getByName(name: String): Boolean {
|
||||
return when (name.lowercase()) {
|
||||
"b0", "bit0" -> b0
|
||||
"b1", "bit1" -> b1
|
||||
"b2", "bit2" -> b2
|
||||
"b3", "bit3" -> b3
|
||||
"b4", "bit4" -> b4
|
||||
"b5", "bit5" -> b5
|
||||
"b6", "bit6" -> b6
|
||||
"b7", "bit7" -> b7
|
||||
else -> throw IllegalArgumentException("未知的位名称: $name")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前状态转换为标准二进制字符串(MSB 在前)。
|
||||
*
|
||||
* 例如:若 b7=true, b6=false, ..., b0=true,则返回 "10000001"
|
||||
*
|
||||
* @return 8 位二进制字符串(高位在左)
|
||||
*/
|
||||
fun toBinaryString(): String {
|
||||
return buildString {
|
||||
if (b7) append('1') else append('0')
|
||||
if (b6) append('1') else append('0')
|
||||
if (b5) append('1') else append('0')
|
||||
if (b4) append('1') else append('0')
|
||||
if (b3) append('1') else append('0')
|
||||
if (b2) append('1') else append('0')
|
||||
if (b1) append('1') else append('0')
|
||||
if (b0) append('1') else append('0')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前状态转换为十六进制字符串(带 0x 前缀,大写,两位)。
|
||||
*
|
||||
* 例如:若值为 10,则返回 "0x0A"
|
||||
*
|
||||
* @return 格式如 "0xXX" 的十六进制字符串
|
||||
*/
|
||||
fun toHexString(): String {
|
||||
return "0x" + (toByte().toInt() and 0xFF).toString(16).padStart(2, '0').uppercase()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前位状态转换为布尔数组。
|
||||
*
|
||||
* 数组顺序为 [b0, b1, b2, ..., b7](LSB 在前)。
|
||||
*
|
||||
* @return 长度为 8 的布尔数组
|
||||
*/
|
||||
fun toBooleanArray(): BooleanArray {
|
||||
return booleanArrayOf(b0, b1, b2, b3, b4, b5, b6, b7)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从布尔数组初始化位状态。
|
||||
*
|
||||
* 使用数组的前 8 个元素(索引 0~7),分别对应 b0~b7。
|
||||
*
|
||||
* @param array 布尔数组(长度至少为 8)
|
||||
* @throws IllegalArgumentException 如果数组长度不足 8
|
||||
*/
|
||||
fun fromBooleanArray(array: BooleanArray) {
|
||||
require(array.size >= 8) { "数组长度至少为8" }
|
||||
b0 = array[0]
|
||||
b1 = array[1]
|
||||
b2 = array[2]
|
||||
b3 = array[3]
|
||||
b4 = array[4]
|
||||
b5 = array[5]
|
||||
b6 = array[6]
|
||||
b7 = array[7]
|
||||
}
|
||||
|
||||
/**
|
||||
* 对两个 [ByteFlags] 执行按位“与”操作(AND)。
|
||||
*
|
||||
* 结果的每一位 = this位 && other位
|
||||
*
|
||||
* @param other 另一个 ByteFlags 实例
|
||||
* @return 新的 ByteFlags 实例,表示 AND 结果
|
||||
*/
|
||||
infix fun and(other: ByteFlags): ByteFlags {
|
||||
return ByteFlags(
|
||||
this.b0 && other.b0,
|
||||
this.b1 && other.b1,
|
||||
this.b2 && other.b2,
|
||||
this.b3 && other.b3,
|
||||
this.b4 && other.b4,
|
||||
this.b5 && other.b5,
|
||||
this.b6 && other.b6,
|
||||
this.b7 && other.b7
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对两个 [ByteFlags] 执行按位“或”操作(OR)。
|
||||
*
|
||||
* 结果的每一位 = this位 || other位
|
||||
*
|
||||
* @param other 另一个 ByteFlags 实例
|
||||
* @return 新的 ByteFlags 实例,表示 OR 结果
|
||||
*/
|
||||
infix fun or(other: ByteFlags): ByteFlags {
|
||||
return ByteFlags(
|
||||
this.b0 || other.b0,
|
||||
this.b1 || other.b1,
|
||||
this.b2 || other.b2,
|
||||
this.b3 || other.b3,
|
||||
this.b4 || other.b4,
|
||||
this.b5 || other.b5,
|
||||
this.b6 || other.b6,
|
||||
this.b7 || other.b7
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对两个 [ByteFlags] 执行按位“异或”操作(XOR)。
|
||||
*
|
||||
* 结果的每一位 = this位 != other位
|
||||
*
|
||||
* @param other 另一个 ByteFlags 实例
|
||||
* @return 新的 ByteFlags 实例,表示 XOR 结果
|
||||
*/
|
||||
infix fun xor(other: ByteFlags): ByteFlags {
|
||||
return ByteFlags(
|
||||
this.b0 != other.b0,
|
||||
this.b1 != other.b1,
|
||||
this.b2 != other.b2,
|
||||
this.b3 != other.b3,
|
||||
this.b4 != other.b4,
|
||||
this.b5 != other.b5,
|
||||
this.b6 != other.b6,
|
||||
this.b7 != other.b7
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对当前 [ByteFlags] 执行按位“非”操作(NOT)。
|
||||
*
|
||||
* 每一位取反。
|
||||
*
|
||||
* @return 新的 ByteFlags 实例,所有位取反
|
||||
*/
|
||||
operator fun not(): ByteFlags {
|
||||
return ByteFlags(
|
||||
!b0, !b1, !b2, !b3, !b4, !b5, !b6, !b7
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可读的字符串表示,包含二进制和十六进制形式。
|
||||
*
|
||||
* 示例:`ByteFlags(10100001 = 0xA1)`
|
||||
*
|
||||
* @return 字符串描述
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return "ByteFlags(${toBinaryString()} = ${toHexString()})"
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 创建一个所有位均为 `true` 的 [ByteFlags] 实例。
|
||||
*
|
||||
* @return 全 1 的 ByteFlags(值为 0xFF)
|
||||
*/
|
||||
fun allTrue(): ByteFlags {
|
||||
return ByteFlags(true, true, true, true, true, true, true, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个所有位均为 `false` 的 [ByteFlags] 实例。
|
||||
*
|
||||
* @return 全 0 的 ByteFlags(值为 0x00)
|
||||
*/
|
||||
fun allFalse(): ByteFlags {
|
||||
return ByteFlags()
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 8 位二进制字符串创建 [ByteFlags] 实例。
|
||||
*
|
||||
* 字符串格式:高位在前(MSB first),如 "10000001" 表示 b7=1, b0=1。
|
||||
*
|
||||
* @param binary 8 位二进制字符串(仅含 '0' 和 '1')
|
||||
* @return 对应的 ByteFlags 实例
|
||||
* @throws IllegalArgumentException 如果字符串长度不是 8 或包含非法字符
|
||||
*/
|
||||
fun fromBinaryString(binary: String): ByteFlags {
|
||||
require(binary.length == 8) { "二进制字符串长度必须为8" }
|
||||
require(binary.all { it == '0' || it == '1' }) { "二进制字符串只能包含0和1" }
|
||||
|
||||
return ByteFlags(
|
||||
binary[7] == '1', // b0 是最低位(对应字符串最后一位)
|
||||
binary[6] == '1',
|
||||
binary[5] == '1',
|
||||
binary[4] == '1',
|
||||
binary[3] == '1',
|
||||
binary[2] == '1',
|
||||
binary[1] == '1',
|
||||
binary[0] == '1' // b7 是最高位(对应字符串第一位)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从整数创建 [ByteFlags] 实例(仅使用低 8 位)。
|
||||
*
|
||||
* @param value 输入整数
|
||||
* @return 对应的 ByteFlags 实例
|
||||
*/
|
||||
fun fromInt(value: Int): ByteFlags {
|
||||
return ByteFlags((value and 0xFF).toByte())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile Main.kt
|
||||
* LastUpdate 2025-09-20 13:22:11
|
||||
* LastUpdate 2026-01-06 14:36:10
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("Main")
|
||||
@ -24,12 +24,7 @@
|
||||
package com.mingliqiye.utils.main
|
||||
|
||||
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
|
||||
import com.mingliqiye.utils.stream.SuperStream
|
||||
|
||||
fun main() {
|
||||
AutoConfiguration.printBanner()
|
||||
val data = SuperStream.of(Array(0) { 1 })
|
||||
|
||||
|
||||
println(data)
|
||||
}
|
||||
|
||||
43
src/main/kotlin/com/mingliqiye/utils/mybatis/CallType.kt
Normal file
43
src/main/kotlin/com/mingliqiye/utils/mybatis/CallType.kt
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2026 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 CallType.kt
|
||||
* LastUpdate 2026-01-07 19:06:59
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis
|
||||
|
||||
enum class CallType {
|
||||
/**
|
||||
* 通过索引访问结果集
|
||||
* 使用数字索引位置来获取结果集中的数据
|
||||
*/
|
||||
RESULTSET_INDEX,
|
||||
|
||||
/**
|
||||
* 通过名称访问结果集
|
||||
* 使用列名来获取结果集中的数据
|
||||
*/
|
||||
RESULTSET_NAME,
|
||||
|
||||
/**
|
||||
* 通过索引访问可调用语句
|
||||
* 使用数字索引位置来获取可调用语句中的数据
|
||||
*/
|
||||
CALLABLE_STATEMENT_INDEX
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2026 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 QuickBaseTypeHandler.kt
|
||||
* LastUpdate 2026-01-08 07:59:47
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis
|
||||
|
||||
import org.apache.ibatis.type.BaseTypeHandler
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
import java.sql.SQLException
|
||||
|
||||
/**
|
||||
* 抽象类 QuickBaseTypeHandler 是 MyBatis 的 BaseTypeHandler 的扩展,
|
||||
* 提供了统一处理数据库字段与 Java 类型之间转换的抽象方法。
|
||||
* 子类需要实现 getValue 和 setValue 方法来完成具体的类型转换逻辑。
|
||||
*
|
||||
* @param T 要处理的 Java 类型
|
||||
*/
|
||||
abstract class QuickBaseTypeHandler<T> : BaseTypeHandler<T>() {
|
||||
/**
|
||||
* 抽象方法,用于从数据库结果中获取并转换为 Java 类型 T。
|
||||
*
|
||||
* @param vg 值获取器,封装了 ResultSet 或 CallableStatement
|
||||
* @param ct 调用类型,标识当前是从 ResultSet 还是 CallableStatement 获取数据
|
||||
* @param ci 列索引(可为 null)
|
||||
* @param cn 列名(可为 null)
|
||||
* @return 转换后的 Java 类型 T 实例
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
abstract fun getValue(
|
||||
vg: QuickBaseTypeHandlerValueGetter,
|
||||
ct: CallType,
|
||||
ci: Int?,
|
||||
cn: String?
|
||||
): T
|
||||
|
||||
/**
|
||||
* 抽象方法,用于将 Java 类型 T 设置到 PreparedStatement 中。
|
||||
*
|
||||
* @param ps PreparedStatement 对象
|
||||
* @param index 参数索引位置
|
||||
* @param parameter Java 类型 T 的实例
|
||||
* @param jdbcType JDBC 类型
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
abstract fun setValue(ps: PreparedStatement, index: Int, parameter: T, jdbcType: JdbcType?)
|
||||
|
||||
/**
|
||||
* 实现 BaseTypeHandler 的 setNonNullParameter 方法,
|
||||
* 将非空参数设置到 PreparedStatement 中。
|
||||
*
|
||||
* @param ps PreparedStatement 对象
|
||||
* @param i 参数索引位置
|
||||
* @param parameter Java 类型 T 的实例(非空)
|
||||
* @param jdbcType JDBC 类型
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun setNonNullParameter(ps: PreparedStatement, i: Int, parameter: T, jdbcType: JdbcType?) {
|
||||
setValue(ps, i, parameter, jdbcType)
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现 BaseTypeHandler 的 getNullableResult 方法,
|
||||
* 通过列名从 ResultSet 中获取可能为 null 的结果。
|
||||
*
|
||||
* @param rs ResultSet 对象
|
||||
* @param columnName 数据库列名
|
||||
* @return 转换后的 Java 类型 T 实例(可能为 null)
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnName: String): T {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_NAME, null, columnName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现 BaseTypeHandler 的 getNullableResult 方法,
|
||||
* 通过列索引从 ResultSet 中获取可能为 null 的结果。
|
||||
*
|
||||
* @param rs ResultSet 对象
|
||||
* @param columnIndex 数据库列索引
|
||||
* @return 转换后的 Java 类型 T 实例(可能为 null)
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): T {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(null, rs), CallType.RESULTSET_INDEX, columnIndex, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现 BaseTypeHandler 的 getNullableResult 方法,
|
||||
* 通过列索引从 CallableStatement 中获取可能为 null 的结果。
|
||||
*
|
||||
* @param cs CallableStatement 对象
|
||||
* @param columnIndex 数据库列索引
|
||||
* @return 转换后的 Java 类型 T 实例(可能为 null)
|
||||
* @throws SQLException SQL 执行异常时抛出
|
||||
*/
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(cs: CallableStatement, columnIndex: Int): T {
|
||||
return getValue(QuickBaseTypeHandlerValueGetter(cs, null), CallType.CALLABLE_STATEMENT_INDEX, columnIndex, null)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2026 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 QuickBaseTypeHandlerValueGetter.kt
|
||||
* LastUpdate 2026-01-07 19:10:44
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis
|
||||
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.ResultSet
|
||||
|
||||
data class QuickBaseTypeHandlerValueGetter(var callableStatement: CallableStatement?, var resultSet: ResultSet?)
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,87 +16,48 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile DateTimeTypeHandler.kt
|
||||
* LastUpdate 2025-09-15 13:53:53
|
||||
* LastUpdate 2026-01-07 19:23:12
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("DateTimeConvertor")
|
||||
|
||||
package com.mingliqiye.utils.mybatis.typehandler.datetime
|
||||
|
||||
import com.mingliqiye.utils.mybatis.CallType
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandler
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandlerValueGetter
|
||||
import com.mingliqiye.utils.time.DateTime
|
||||
import org.apache.ibatis.type.BaseTypeHandler
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
import java.sql.SQLException
|
||||
import java.time.LocalDateTime
|
||||
|
||||
/**
|
||||
* 将LocalDateTime对象转换为DateTime对象
|
||||
*
|
||||
* @param localDateTime LocalDateTime对象
|
||||
* @return DateTime对象,如果localDateTime为null则返回null
|
||||
*/
|
||||
fun toDateTime(localDateTime: LocalDateTime?): DateTime? {
|
||||
return localDateTime?.let { DateTime.of(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将DateTime对象转换为LocalDateTime对象
|
||||
*
|
||||
* @param dateTime DateTime对象
|
||||
* @return LocalDateTime对象,如果dateTime为null则返回null
|
||||
*/
|
||||
fun toLocalDateTime(dateTime: DateTime?): LocalDateTime? {
|
||||
return dateTime?.toLocalDateTime()
|
||||
}
|
||||
import java.sql.Timestamp
|
||||
|
||||
/**
|
||||
* DateTime类型处理器,用于在数据库和Java对象之间转换DateTime类型
|
||||
* @author MingLiQiye
|
||||
* @date 2025/9/12
|
||||
*/
|
||||
@MappedTypes(DateTime::class)
|
||||
class DateTimeTypeHandler : BaseTypeHandler<DateTime>() {
|
||||
class DateTimeTypeHandler : QuickBaseTypeHandler<DateTime>() {
|
||||
|
||||
@Throws(SQLException::class)
|
||||
override fun setNonNullParameter(
|
||||
override fun getValue(
|
||||
vg: QuickBaseTypeHandlerValueGetter,
|
||||
ct: CallType,
|
||||
ci: Int?,
|
||||
cn: String?
|
||||
): DateTime {
|
||||
return DateTime.of(
|
||||
(when (ct) {
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getTimestamp(ci!!)
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getTimestamp(cn!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.callableStatement!!.getTimestamp(ci!!)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
override fun setValue(
|
||||
ps: PreparedStatement,
|
||||
i: Int,
|
||||
index: Int,
|
||||
parameter: DateTime,
|
||||
jdbcType: JdbcType?
|
||||
) {
|
||||
// 使用 setObject 允许传入 null,由数据库处理
|
||||
ps.setObject(i, toLocalDateTime(parameter))
|
||||
}
|
||||
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnName: String): DateTime? {
|
||||
// 安全类型转换和空检查
|
||||
return when (val value = rs.getObject(columnName)) {
|
||||
is LocalDateTime -> toDateTime(value)
|
||||
null -> null
|
||||
else -> throw SQLException("Expected LocalDateTime for column '$columnName', but got ${value.javaClass.name}")
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): DateTime? {
|
||||
return when (val value = rs.getObject(columnIndex)) {
|
||||
is LocalDateTime -> toDateTime(value)
|
||||
null -> null
|
||||
else -> throw SQLException("Expected LocalDateTime at column index $columnIndex, but got ${value.javaClass.name}")
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(SQLException::class)
|
||||
override fun getNullableResult(cs: CallableStatement, columnIndex: Int): DateTime? {
|
||||
return when (val value = cs.getObject(columnIndex)) {
|
||||
is LocalDateTime -> toDateTime(value)
|
||||
null -> null
|
||||
else -> throw SQLException("Expected LocalDateTime at column index $columnIndex, but got ${value.javaClass.name}")
|
||||
}
|
||||
ps.setTimestamp(index, Timestamp.valueOf(parameter.toLocalDateTime()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile MysqlUUIDBinaryTypeHandler.kt
|
||||
* LastUpdate 2026-01-07 19:30:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis.typehandler.mysql.uuid
|
||||
|
||||
import com.mingliqiye.utils.mybatis.CallType
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandler
|
||||
import com.mingliqiye.utils.mybatis.QuickBaseTypeHandlerValueGetter
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import com.mingliqiye.utils.uuid.mysqlToUuid
|
||||
import com.mingliqiye.utils.uuid.uuidToMysql
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.PreparedStatement
|
||||
|
||||
@MappedTypes(UUID::class)
|
||||
class MysqlUUIDBinaryTypeHandler : QuickBaseTypeHandler<UUID>() {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 将字节数组转换为UUID对象
|
||||
*
|
||||
* @param byteArray 字节数组
|
||||
* @return UUID对象,如果字节数组为null则返回null
|
||||
*/
|
||||
private fun toUUID(byteArray: ByteArray?): UUID? {
|
||||
return byteArray?.let { UUID.of(mysqlToUuid(it)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UUID对象转换为字节数组
|
||||
*
|
||||
* @param uuid UUID对象
|
||||
* @return 字节数组,如果UUID为null则返回null
|
||||
*/
|
||||
fun toByteArray(uuid: UUID?): ByteArray? {
|
||||
return uuid?.let { uuidToMysql(it.toBytes()) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getValue(
|
||||
vg: QuickBaseTypeHandlerValueGetter, ct: CallType, ci: Int?, cn: String?
|
||||
): UUID {
|
||||
return toUUID(
|
||||
when (ct) {
|
||||
CallType.RESULTSET_NAME -> vg.resultSet!!.getBytes(cn!!)
|
||||
CallType.RESULTSET_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
CallType.CALLABLE_STATEMENT_INDEX -> vg.resultSet!!.getBytes(ci!!)
|
||||
}
|
||||
)!!
|
||||
}
|
||||
|
||||
override fun setValue(
|
||||
ps: PreparedStatement, index: Int, parameter: UUID, jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setBytes(index, toByteArray(parameter))
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,279 +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 UUIDTypeHandler.kt
|
||||
* LastUpdate 2025-09-15 13:54:18
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("UUIDConvertor")
|
||||
|
||||
package com.mingliqiye.utils.mybatis.typehandler.uuid
|
||||
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import org.apache.ibatis.type.BaseTypeHandler
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedJdbcTypes
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
import java.util.UUID as JUUID
|
||||
|
||||
|
||||
/**
|
||||
* 将字节数组转换为UUID对象
|
||||
*
|
||||
* @param byteArray 字节数组
|
||||
* @return UUID对象,如果字节数组为null则返回null
|
||||
*/
|
||||
fun byteArraytoUUID(byteArray: ByteArray?): UUID? {
|
||||
return byteArray?.let { UUID.of(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UUID对象转换为字节数组
|
||||
*
|
||||
* @param uuid UUID对象
|
||||
* @return 字节数组,如果UUID为null则返回null
|
||||
*/
|
||||
fun uuidToByteArray(uuid: UUID?): ByteArray? {
|
||||
return uuid?.toBytes()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转换为UUID对象
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return UUID对象,如果字符串为null则返回null
|
||||
*/
|
||||
fun stringToUUID(str: String?): UUID? {
|
||||
return str?.let { UUID.of(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UUID对象转换为字符串
|
||||
*
|
||||
* @param uuid UUID对象
|
||||
* @return 字符串,如果UUID为null则返回null
|
||||
*/
|
||||
fun uuidToString(uuid: UUID?): String? {
|
||||
return uuid?.getString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将java UUID转换为UUID对象
|
||||
*
|
||||
* @param uuid JUUID java UUID
|
||||
* @return UUID对象,如果字符串为null则返回null
|
||||
*/
|
||||
fun juuidToUUID(uuid: JUUID?): UUID? {
|
||||
return uuid?.let { UUID(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UUID对象转换为java UUID
|
||||
*
|
||||
* @param uuid UUID对象
|
||||
* @return java UUID,如果UUID为null则返回null
|
||||
*/
|
||||
fun uuidToJuuid(uuid: UUID?): JUUID? {
|
||||
return uuid?.getUuid()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JDBC类型转换 UUID BINARY
|
||||
* @author MingLiQiye
|
||||
* @date 2025/9/12
|
||||
*/
|
||||
@MappedTypes(UUID::class)
|
||||
@MappedJdbcTypes(JdbcType.BINARY)
|
||||
class UUIDBinaryTypeHandler : BaseTypeHandler<UUID>() {
|
||||
/**
|
||||
* 设置非空参数到PreparedStatement中
|
||||
*
|
||||
* @param ps PreparedStatement对象
|
||||
* @param i 参数索引
|
||||
* @param parameter UUID参数值
|
||||
* @param jdbcType JDBC类型
|
||||
*/
|
||||
override fun setNonNullParameter(
|
||||
ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setBytes(i, uuidToByteArray(parameter))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列名获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnName 列名
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet, columnName: String
|
||||
): UUID? {
|
||||
return byteArraytoUUID(rs.getBytes(columnName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? {
|
||||
return byteArraytoUUID(rs.getBytes(columnIndex))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从CallableStatement中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param cs CallableStatement对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
cs: CallableStatement, columnIndex: Int
|
||||
): UUID? {
|
||||
return byteArraytoUUID(cs.getBytes(columnIndex))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JDBC类型转换 UUID String
|
||||
* @author MingLiQiye
|
||||
* @date 2025/9/12
|
||||
*/
|
||||
@MappedTypes(UUID::class)
|
||||
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||
class UUIDStringTypeHandler : BaseTypeHandler<UUID>() {
|
||||
/**
|
||||
* 设置非空参数到PreparedStatement中
|
||||
*
|
||||
* @param ps PreparedStatement对象
|
||||
* @param i 参数索引
|
||||
* @param parameter UUID参数值
|
||||
* @param jdbcType JDBC类型
|
||||
*/
|
||||
override fun setNonNullParameter(
|
||||
ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setString(i, uuidToString(parameter))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列名获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnName 列名
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet, columnName: String
|
||||
): UUID? {
|
||||
return stringToUUID(rs.getString(columnName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? {
|
||||
return stringToUUID(rs.getString(columnIndex))
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从CallableStatement中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param cs CallableStatement对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
cs: CallableStatement, columnIndex: Int
|
||||
): UUID? {
|
||||
return stringToUUID(cs.getString(columnIndex))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* JDBC类型转换 UUID java UUID
|
||||
* @author MingLiQiye
|
||||
* @date 2025/9/12
|
||||
*/
|
||||
@MappedTypes(UUID::class)
|
||||
@MappedJdbcTypes(JdbcType.OTHER)
|
||||
class UUIDTypeHandler : BaseTypeHandler<UUID>() {
|
||||
/**
|
||||
* 设置非空参数到PreparedStatement中
|
||||
*
|
||||
* @param ps PreparedStatement对象
|
||||
* @param i 参数索引
|
||||
* @param parameter UUID参数值
|
||||
* @param jdbcType JDBC类型
|
||||
*/
|
||||
override fun setNonNullParameter(
|
||||
ps: PreparedStatement, i: Int, parameter: UUID, jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setObject(i, parameter.getUuid())
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列名获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnName 列名
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet,
|
||||
columnName: String
|
||||
): UUID? {
|
||||
return juuidToUUID(rs.getObject(columnName, JUUID::class.java) as JUUID)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? {
|
||||
return juuidToUUID(rs.getObject(columnIndex, JUUID::class.java) as JUUID)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从CallableStatement中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param cs CallableStatement对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
cs: CallableStatement, columnIndex: Int
|
||||
): UUID? {
|
||||
return juuidToUUID(cs.getObject(columnIndex, JUUID::class.java) as JUUID)
|
||||
}
|
||||
}
|
||||
@ -1,119 +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 MysqlUUIDBinaryTypeHandler.kt
|
||||
* LastUpdate 2025-09-15 13:54:29
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.mybatis.typehandler.uuid.mysql
|
||||
|
||||
import com.mingliqiye.utils.uuid.UUID
|
||||
import com.mingliqiye.utils.uuid.mysqlToUuid
|
||||
import com.mingliqiye.utils.uuid.uuidToMysql
|
||||
import org.apache.ibatis.type.BaseTypeHandler
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
|
||||
/**
|
||||
* JDBC类型转换 UUID
|
||||
* @author MingLiQiye
|
||||
* @date 2025/9/12
|
||||
*/
|
||||
@MappedTypes(UUID::class)
|
||||
class MysqlUUIDBinaryTypeHandler : BaseTypeHandler<UUID>() {
|
||||
|
||||
/**
|
||||
* 将字节数组转换为UUID对象
|
||||
*
|
||||
* @param byteArray 字节数组
|
||||
* @return UUID对象,如果字节数组为null则返回null
|
||||
*/
|
||||
private fun toUUID(byteArray: ByteArray?): UUID? {
|
||||
return byteArray?.let { UUID.of(mysqlToUuid(it)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 将UUID对象转换为字节数组
|
||||
*
|
||||
* @param uuid UUID对象
|
||||
* @return 字节数组,如果UUID为null则返回null
|
||||
*/
|
||||
fun toByteArray(uuid: UUID?): ByteArray? {
|
||||
return uuid?.let { uuidToMysql(it.toBytes()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置非空参数到PreparedStatement中
|
||||
*
|
||||
* @param ps PreparedStatement对象
|
||||
* @param i 参数索引
|
||||
* @param parameter UUID参数值
|
||||
* @param jdbcType JDBC类型
|
||||
*/
|
||||
override fun setNonNullParameter(
|
||||
ps: PreparedStatement,
|
||||
i: Int,
|
||||
parameter: UUID,
|
||||
jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setBytes(i, toByteArray(parameter))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列名获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnName 列名
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet,
|
||||
columnName: String
|
||||
): UUID? {
|
||||
return toUUID(rs.getBytes(columnName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ResultSet中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param rs ResultSet对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(rs: ResultSet, columnIndex: Int): UUID? {
|
||||
return toUUID(rs.getBytes(columnIndex))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从CallableStatement中根据列索引获取可空的UUID结果
|
||||
*
|
||||
* @param cs CallableStatement对象
|
||||
* @param columnIndex 列索引
|
||||
* @return UUID对象或null
|
||||
*/
|
||||
override fun getNullableResult(
|
||||
cs: CallableStatement,
|
||||
columnIndex: Int
|
||||
): UUID? {
|
||||
return toUUID(cs.getBytes(columnIndex))
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2026 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 ClientScheduleReconnect.kt
|
||||
* LastUpdate 2026-01-08 10:45:37
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelFuture
|
||||
import io.netty.channel.ChannelFutureListener
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class ClientScheduleReconnect(
|
||||
protected val bootstrap: Bootstrap,
|
||||
protected var delay: Long = 10L,
|
||||
protected var timeUnit: TimeUnit = TimeUnit.SECONDS
|
||||
) {
|
||||
protected var isStop = false
|
||||
protected var channel: Channel? = null
|
||||
|
||||
|
||||
abstract fun onConnectedLog(channel: Channel)
|
||||
abstract fun onConnectFailedLog(cause: Throwable?)
|
||||
abstract fun onStoppedLog()
|
||||
abstract fun doConnect(): ChannelFuture
|
||||
|
||||
open fun updateReconnectDelay(newDelay: Long, newTimeUnit: TimeUnit) {
|
||||
require(newDelay > 0) { "Delay must be positive" }
|
||||
this.delay = newDelay
|
||||
this.timeUnit = newTimeUnit
|
||||
}
|
||||
|
||||
open fun connect() {
|
||||
doConnect().addListener(object : ChannelFutureListener {
|
||||
override fun operationComplete(future: ChannelFuture) {
|
||||
if (future.isSuccess) {
|
||||
onConnected(future.channel())
|
||||
} else {
|
||||
onConnectFailed(future.cause())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
open fun stop() {
|
||||
isStop = true
|
||||
disConnect()
|
||||
}
|
||||
|
||||
open fun disConnect() {
|
||||
channel?.close()
|
||||
channel = null
|
||||
}
|
||||
|
||||
|
||||
open fun scheduleReconnect() {
|
||||
if (isStop) {
|
||||
onStoppedLog()
|
||||
return
|
||||
}
|
||||
bootstrap.config().group().schedule({
|
||||
if (isStop) {
|
||||
onStoppedLog()
|
||||
return@schedule
|
||||
}
|
||||
connect()
|
||||
}, delay, timeUnit)
|
||||
}
|
||||
|
||||
open fun onConnected(channel: Channel) {
|
||||
this.channel = channel
|
||||
onConnectedLog(channel)
|
||||
channel.closeFuture().addListener { _ ->
|
||||
scheduleReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
open fun onConnectFailed(cause: Throwable?) {
|
||||
onConnectFailedLog(cause)
|
||||
scheduleReconnect()
|
||||
}
|
||||
|
||||
open fun isConnected(): Boolean {
|
||||
return channel?.isActive ?: false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2026 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 NamedThreadFactory.kt
|
||||
* LastUpdate 2026-01-08 13:21:00
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import io.netty.util.concurrent.FastThreadLocalThread
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
open class NamedThreadFactory(private val getName: NamedThreadFactoryNameGetter) : ThreadFactory {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
private val allThreadPoolNumber = AtomicInteger(0)
|
||||
|
||||
@FunctionalInterface
|
||||
fun interface NamedThreadFactoryNameGetter {
|
||||
fun getName(clazz: Class<out NamedThreadFactory>, poolNumber: Int, threadNumber: Int): String
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val defaultGetName =
|
||||
NamedThreadFactoryNameGetter { clazz, poolNumber, threadNumber -> "${clazz.simpleName}-$poolNumber-$threadNumber" }
|
||||
|
||||
@JvmStatic
|
||||
fun of(name: String): NamedThreadFactory {
|
||||
return NamedThreadFactory { a, b, c ->
|
||||
"$name-$c"
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun of(getter: NamedThreadFactoryNameGetter = defaultGetName): NamedThreadFactory {
|
||||
return NamedThreadFactory(getter)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val threadNumber = AtomicInteger(0)
|
||||
private val threadPoolNumber = allThreadPoolNumber.addAndGet(1)
|
||||
|
||||
open fun getThreadName(clazz: Class<out NamedThreadFactory>, poolNumber: Int, threadNumber: Int) =
|
||||
getName.getName(clazz, poolNumber, threadNumber)
|
||||
|
||||
override fun newThread(r: Runnable): Thread {
|
||||
return FastThreadLocalThread(
|
||||
null,
|
||||
r,
|
||||
getThreadName(this.javaClass, threadPoolNumber, threadNumber.addAndGet(1))
|
||||
)
|
||||
}
|
||||
}
|
||||
81
src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt
Normal file
81
src/main/kotlin/com/mingliqiye/utils/netty/NettyUtils.kt
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2026 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 NettyUtils.kt
|
||||
* LastUpdate 2026-01-07 10:00:31
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@file:JvmName("NettyUtils")
|
||||
|
||||
package com.mingliqiye.utils.netty
|
||||
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
/**
|
||||
* 将ByteBuffer转换为Netty的ByteBuf对象
|
||||
*
|
||||
* 该函数使用Netty库的Unpooled工具类将标准的java.nio.ByteBuffer包装成Netty的ByteBuf
|
||||
* 以便在Netty框架中使用
|
||||
*
|
||||
* @receiver ByteBuffer 需要转换的原始ByteBuffer对象
|
||||
* @return ByteBuf 转换后的Netty ByteBuf对象,该对象包装了原始的ByteBuffer
|
||||
*/
|
||||
fun ByteBuffer.toByteBuf(): ByteBuf {
|
||||
return Unpooled.wrappedBuffer(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Netty的ByteBuf对象转换为ByteBuffer
|
||||
*
|
||||
* 该函数通过ByteBuf的nioBuffer()方法将Netty的ByteBuf转换为标准的java.nio.ByteBuffer
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的原始ByteBuf对象
|
||||
* @return ByteBuffer 转换后的java.nio.ByteBuffer对象
|
||||
*/
|
||||
fun ByteBuf.toByteBuffer(): ByteBuffer {
|
||||
return this.nioBuffer()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Netty的ByteBuf对象转换为字节数组
|
||||
*
|
||||
* 该函数将ByteBuf中的可读字节读取到一个新的字节数组中
|
||||
*
|
||||
* @receiver ByteBuf 需要转换的原始ByteBuf对象
|
||||
* @return ByteArray 转换后的字节数组,包含ByteBuf中所有可读的字节数据
|
||||
*/
|
||||
fun ByteBuf.toByteArray(): ByteArray {
|
||||
val array = ByteArray(this.readableBytes())
|
||||
this.readBytes(array)
|
||||
return array
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为Netty的ByteBuf对象
|
||||
*
|
||||
* 该函数使用Netty库的Unpooled工具类将字节数组包装成Netty的ByteBuf
|
||||
* 以便在Netty框架中使用
|
||||
*
|
||||
* @receiver ByteArray 需要转换的原始字节数组
|
||||
* @return ByteBuf 转换后的Netty ByteBuf对象,该对象包装了原始的字节数组
|
||||
*/
|
||||
fun ByteArray.toByteBuf(): ByteBuf {
|
||||
return Unpooled.wrappedBuffer(this)
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,16 +16,18 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile AddressPort.kt
|
||||
* LastUpdate 2025-09-15 22:01:27
|
||||
* LastUpdate 2026-01-06 14:03:47
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.network
|
||||
|
||||
import com.mingliqiye.utils.string.join
|
||||
import java.io.Serializable
|
||||
import java.net.InetAddress
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
@ -80,6 +82,20 @@ class NetworkAddress private constructor(domip: String) : Serializable {
|
||||
return NetworkAddress(domip)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkAddress {
|
||||
val byteArray = ByteArray(4)
|
||||
byteBuffer.get(byteArray)
|
||||
return ofIpv4(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkAddress {
|
||||
return of(".".join(byteArray.map {
|
||||
(it.toInt() and 0xFF).toString()
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法,通过 InetAddress 创建 NetworkAddress 实例。
|
||||
*
|
||||
@ -182,6 +198,31 @@ class NetworkAddress private constructor(domip: String) : Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址转换为字节数组
|
||||
*
|
||||
* @return 返回表示IPv4地址的4字节数组
|
||||
* @throws NetworkException 当当前地址不是IPv4地址时抛出异常
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
// 验证地址类型是否为IPv4
|
||||
if (iPv != IPV4) {
|
||||
throw NetworkException("该地址 不是IPv4地址")
|
||||
}
|
||||
// 将IP地址字符串按点分割,转换为整数并进行位运算处理,最后转为字节数组
|
||||
return ip!!.split(".").map { it.toInt() and 0xFF }.map { it.toByte() }.toByteArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址写入到指定的ByteBuffer中
|
||||
*
|
||||
* @param byteBuffer 要写入的ByteBuffer对象,IPv4地址将以字节数组形式写入到该缓冲区
|
||||
* @return 返回写入了IPv4地址的ByteBuffer对象,便于链式调用
|
||||
*/
|
||||
fun writeIpv4ToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toIpv4ByteArray())
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前 NetworkAddress 转换为 InetAddress 对象。
|
||||
*
|
||||
@ -215,7 +256,54 @@ class NetworkPort : Serializable {
|
||||
this.port = port
|
||||
}
|
||||
|
||||
fun toByteArray(): ByteArray {
|
||||
val byteArray = ByteArray(2)
|
||||
byteArray[0] = (port shr 8 and 0xFF).toByte()
|
||||
byteArray[1] = (port and 0xFF).toByte()
|
||||
return byteArray
|
||||
}
|
||||
|
||||
fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(toByteArray())
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* 创建NetworkPort实例
|
||||
* @param port 端口号
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(port: Int): NetworkPort {
|
||||
return NetworkPort(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建NetworkPort实例
|
||||
* @param byteArray 包含端口信息的字节数组(长度至少为2)
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteArray: ByteArray): NetworkPort {
|
||||
// 将字节数组的前两个字节转换为端口号
|
||||
val port = ((byteArray[0].toInt() and 0xFF) shl 8) or (byteArray[1].toInt() and 0xFF)
|
||||
return of(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ByteBuffer创建NetworkPort实例
|
||||
* @param byteBuffer 包含端口信息的ByteBuffer
|
||||
* @return NetworkPort实例
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteBuffer: ByteBuffer): NetworkPort {
|
||||
val byteArray = ByteArray(2)
|
||||
byteBuffer.get(byteArray)
|
||||
return of(byteArray)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun testPort(port: Int) {
|
||||
// 验证端口号范围是否在0-65535之间
|
||||
if (port !in 0..65535) {
|
||||
@ -282,6 +370,42 @@ class NetworkEndpoint private constructor(
|
||||
return NetworkEndpoint(networkAddress, networkPort)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节数组创建IPv4网络端点
|
||||
*
|
||||
* @param byteArray 包含IPv4地址和端口信息的字节数组,前4个字节表示IP地址,后2个字节表示端口号
|
||||
* @return NetworkEndpoint对象,封装了IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteArray: ByteArray): NetworkEndpoint {
|
||||
// 提取前4个字节作为IP地址
|
||||
val address = ByteArray(4) {
|
||||
byteArray[it]
|
||||
}
|
||||
// 提取后2个字节作为端口号
|
||||
val portInt = ByteArray(2) {
|
||||
byteArray[it + 4]
|
||||
}
|
||||
return NetworkEndpoint(NetworkAddress.ofIpv4(address), NetworkPort.of(portInt))
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字节缓冲区创建IPv4网络端点实例
|
||||
*
|
||||
* 该方法从给定的ByteBuffer中读取数据,构建一个包含IPv4地址和端口的网络端点对象。
|
||||
* 该方法按照协议顺序从缓冲区中读取IPv4地址数据和端口数据。
|
||||
*
|
||||
* @param byteBuffer 包含IPv4地址和端口数据的字节缓冲区,缓冲区中的数据应按照先地址后端口的顺序排列
|
||||
* @return 返回一个NetworkEndpoint实例,包含从缓冲区解析出的IPv4地址和端口信息
|
||||
*/
|
||||
@JvmStatic
|
||||
fun ofIpv4(byteBuffer: ByteBuffer): NetworkEndpoint {
|
||||
return NetworkEndpoint(
|
||||
NetworkAddress.ofIpv4(byteBuffer),
|
||||
NetworkPort.of(byteBuffer)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据"host:port"格式的字符串创建NetworkEndpoint实例。
|
||||
* 例如:"127.0.0.1:8080"
|
||||
@ -327,7 +451,7 @@ class NetworkEndpoint private constructor(
|
||||
* @return 包含详细信息的字符串
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port},Endpoint=${toHostPortString()})"
|
||||
return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port})"
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,4 +471,39 @@ class NetworkEndpoint private constructor(
|
||||
fun port(): Int {
|
||||
return networkPort.port
|
||||
}
|
||||
|
||||
/**
|
||||
* 将网络地址和端口转换为IPv4字节数组
|
||||
*
|
||||
* 该函数将当前对象的网络地址转换为IPv4字节数组,并与端口字节数组合并,
|
||||
* 生成一个包含6个字节的数组,其中前4个字节为IPv4地址,后2个字节为端口号
|
||||
*
|
||||
* @return ByteArray 包含6个字节的数组,前4个字节为IPv4地址,后2个字节为端口号
|
||||
*/
|
||||
fun toIpv4ByteArray(): ByteArray {
|
||||
val ipv4ByteArray = networkAddress.toIpv4ByteArray()
|
||||
val portByteArray = networkPort.toByteArray()
|
||||
// 构建包含IPv4地址和端口的6字节数组
|
||||
val byteArray = ByteArray(6) {
|
||||
if (it < 4) {
|
||||
ipv4ByteArray[it]
|
||||
} else {
|
||||
portByteArray[it - 4]
|
||||
}
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IPv4地址和端口信息写入字节缓冲区
|
||||
*
|
||||
* 该函数依次将网络地址的IPv4表示和网络端口写入到指定的字节缓冲区中
|
||||
*
|
||||
* @param byteBuffer 要写入数据的目标字节缓冲区
|
||||
*/
|
||||
fun writeIpv4toByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
networkAddress.writeIpv4ToByteBuffer(byteBuffer)
|
||||
networkPort.writeToByteBuffer(byteBuffer)
|
||||
return byteBuffer
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -15,20 +15,15 @@
|
||||
*
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile StreamEmptyException.java
|
||||
* LastUpdate 2025-09-20 13:24:07
|
||||
* CurrentFile StreamEmptyException.kt
|
||||
* LastUpdate 2026-01-07 19:13:29
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
package com.mingliqiye.utils.stream;
|
||||
package com.mingliqiye.utils.stream
|
||||
|
||||
public class StreamEmptyException extends java.lang.RuntimeException {
|
||||
class StreamEmptyException : RuntimeException {
|
||||
constructor(message: String) : super(message)
|
||||
|
||||
public StreamEmptyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StreamEmptyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
constructor(message: String, cause: Throwable) : super(message, cause)
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,10 +16,10 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile MysqlUUIDv1.kt
|
||||
* LastUpdate 2025-09-15 22:32:50
|
||||
* LastUpdate 2026-01-08 08:22:14
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
@file:JvmName("MysqlUUIDv1")
|
||||
@file:JvmName("MysqlUUIDConvertor")
|
||||
|
||||
package com.mingliqiye.utils.uuid
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2025 mingliqiye
|
||||
* Copyright 2026 mingliqiye
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,7 @@
|
||||
* ProjectName mingli-utils
|
||||
* ModuleName mingli-utils.main
|
||||
* CurrentFile UUID.kt
|
||||
* LastUpdate 2025-09-19 20:22:27
|
||||
* LastUpdate 2026-01-08 13:21:00
|
||||
* UpdateUser MingLiPro
|
||||
*/
|
||||
|
||||
@ -234,6 +234,19 @@ class UUID : Serializable {
|
||||
return UUID(msb, lsb)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ByteBuffer创建UUID对象
|
||||
*
|
||||
* @param byteBuffer 包含UUID字节数据的ByteBuffer对象,必须包含至少16个字节的数据
|
||||
* @return 从ByteBuffer中读取的16个字节创建的UUID对象
|
||||
*/
|
||||
@JvmStatic
|
||||
fun of(byteBuffer: ByteBuffer): UUID {
|
||||
val byte = ByteArray(16)
|
||||
byteBuffer.get(byte)
|
||||
return UUID(byte)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 MySQL UUID 字节数组创建 UUID 实例。
|
||||
*
|
||||
@ -296,7 +309,6 @@ class UUID : Serializable {
|
||||
return UUID(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从字符串解析 UUID 字节数组。
|
||||
*
|
||||
@ -422,6 +434,10 @@ class UUID : Serializable {
|
||||
return data
|
||||
}
|
||||
|
||||
fun writeToByteBuffer(byteBuffer: ByteBuffer): ByteBuffer {
|
||||
return byteBuffer.put(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 UUID 的高位长整型部分。
|
||||
*
|
||||
@ -521,7 +537,7 @@ class UUID : Serializable {
|
||||
* @return MySQL 格式的 UUID 字节数组
|
||||
*/
|
||||
fun toMysql(): ByteArray {
|
||||
return mysqlToUuid(this.data)
|
||||
return uuidToMysql(this.data)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -530,7 +546,7 @@ class UUID : Serializable {
|
||||
* @return MySQL 格式的 UUID 实例
|
||||
*/
|
||||
fun toMysqlUUID(): UUID {
|
||||
return of(mysqlToUuid(this.data))
|
||||
return of(uuidToMysql(this.data))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -588,6 +604,15 @@ class UUID : Serializable {
|
||||
* @return 包含 UUID 和版本号的字符串
|
||||
*/
|
||||
override fun toString(): String {
|
||||
when (version) {
|
||||
1 -> {
|
||||
return "UUID(uuid=${getString()},version=${version},datetime=${getDateTime()},mac=${getMac()})"
|
||||
}
|
||||
|
||||
6, 7 -> {
|
||||
return "UUID(uuid=${getString()},version=${version},datetime=${getDateTime()})"
|
||||
}
|
||||
}
|
||||
return "UUID(uuid=${getString()},version=${version})"
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user