minglipro 09792e2c3b
All checks were successful
Gitea Actions Build / Build (push) Successful in 53s
no message
2025-09-10 20:58:17 +08:00

286 lines
6.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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 UUID.java
* LastUpdate 2025-09-10 11:14:27
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.uuid;
import com.github.f4b6a3.uuid.UuidCreator;
import com.mingliqiye.utils.string.StringUtil;
import com.mingliqiye.utils.time.DateTime;
import com.mingliqiye.utils.time.DateTimeOffset;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.time.temporal.ChronoUnit;
import java.util.Locale;
import java.util.Objects;
import lombok.Data;
/**
* UUID 工具类,用于生成、解析和操作 UUID。
* 支持时间戳型 UUID版本1以及标准 UUID 的创建与转换。
*
* @author MingLiPro
*/
@Data
public class UUID implements Serializable {
/**
* 内部封装的 java.util.UUID 实例
*/
private java.util.UUID uuid;
/**
* 构造一个由指定高位和低位组成的 UUID。
*
* @param msb 高64位
* @param lsb 低64位
*/
public UUID(long msb, long lsb) {
uuid = new java.util.UUID(msb, lsb);
}
/**
* 构造一个基于当前时间的时间戳型 UUID版本1。<br>
* 由于springboot 默认使用此构造函数构造UUID 导致致命BUG 废弃<br>
* 下个大版本删除<br>
* @deprecated 请使用 <code>UUID.getTimeBased()</code>
*/
@Deprecated
public UUID() {
uuid = UUID.getTimeBased().GetUUID();
}
/**
* 使用给定的 java.util.UUID 对象构造一个新的 UUID 实例。
*
* @param uuid java.util.UUID 实例
*/
public UUID(java.util.UUID uuid) {
this.uuid = uuid;
}
/**
* 根据字符串表示的 UUID 构造一个新的 UUID 实例。
*
* @param uuid 字符串形式的 UUID
*/
public UUID(String uuid) {
this.uuid = java.util.UUID.fromString(uuid);
}
/**
* 获取一个基于当前时间生成的时间戳型 UUID版本1
*
* @return 时间戳型 UUID
*/
public static UUID getTimeBased() {
return new UUID(UuidCreator.getTimeBased());
}
/**
* 将字节数组转换为 UUID 实例。
*
* @param bytes 表示 UUID 的 16 字节数据
* @return 新建的 UUID 实例
*/
public static UUID of(byte[] bytes) {
if (bytes == null) {
return null;
}
ByteBuffer bb = ByteBuffer.wrap(bytes);
long msb = bb.getLong();
long lsb = bb.getLong();
return new UUID(msb, lsb);
}
/**
* 将字符串解析为 UUID 实例,如果解析失败则抛出 UUIDException。
*
* @param data UUID 字符串
* @return 解析后的 UUID 实例
* @throws UUIDException 如果解析失败
*/
public static UUID of(String data) {
if (data == null) {
return null;
}
try {
return new UUID(java.util.UUID.fromString(data));
} catch (Exception e) {
throw new UUIDException(e.getMessage(), e);
}
}
/**
* 将 UUID 转换为 16 字节的字节数组。
*
* @return 表示该 UUID 的字节数组
*/
public byte[] toBytes() {
if (this.uuid == null) {
return null;
}
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
/**
* 获取内部封装的 java.util.UUID 实例。
*
* @return java.util.UUID 实例
*/
public java.util.UUID GetUUID() {
return uuid;
}
/**
* 将 UUID 转换为字符串表示,默认使用小写格式。
*
* @return UUID 字符串
*/
public String toUUIDString() {
return toUUIDString(false);
}
/**
* 将 UUID 转换为字符串表示,并可选择是否使用大写。
*
* @param u 是否使用大写格式
* @return UUID 字符串
* @throws UUIDException 如果 uuid 为 null
*/
public String toUUIDString(boolean u) {
if (uuid == null) {
throw new UUIDException("uuid is null : NullPointerException");
}
if (u) {
return uuid.toString().toUpperCase(Locale.ROOT);
}
return uuid.toString();
}
/**
* 计算此 UUID 的哈希码。
*
* @return 哈希码值
*/
@Override
public int hashCode() {
return Objects.hash(uuid);
}
/**
* 判断两个 UUID 是否相等。
*
* @param o 比较对象
* @return 如果相等返回 true否则返回 false
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UUID uuid = (UUID) o;
return Objects.equals(this.uuid, uuid.uuid);
}
/**
* 返回此 UUID 的字符串表示包含版本信息和时间戳如果是版本1
*
* @return UUID 的详细字符串表示
*/
@Override
public String toString() {
if (uuid == null) {
return "UUID(null)";
}
return StringUtil.format(
"UUID(uuid={},version={})",
toUUIDString(true),
uuid.version()
);
}
/**
* 从时间戳型 UUID 中提取时间戳并转换为 DateTime 对象。
*
* @return 对应的 DateTime 对象;如果 uuid 为 null则返回 null
*/
public DateTime getDateTime() {
if (uuid == null) {
return null;
}
if (uuid.version() != 1) {
return null;
}
return DateTime.of(uuid.timestamp() / 10_000).add(
DateTimeOffset.of(-141427L, ChronoUnit.DAYS)
);
}
/**
* 从时间戳型 UUID 中提取 MAC 地址,默认使用冒号分隔符。
*
* @return MAC 地址字符串
* @throws UUIDException 如果 uuid 为 null
*/
public String extractMACFromUUID() {
return extractMACFromUUID(null);
}
/**
* 从时间戳型 UUID 中提取 MAC 地址,并允许自定义分隔符。
*
* @param spec 分隔符字符,默认为 ":"
* @return MAC 地址字符串
* @throws UUIDException 如果 uuid 为 null
*/
public String extractMACFromUUID(String spec) {
if (uuid == null) {
throw new UUIDException("uuid is null : NullPointerException");
}
if (spec == null) {
spec = ":";
}
long leastSigBits = uuid.getLeastSignificantBits();
long macLong = leastSigBits & 0xFFFFFFFFFFFFL;
byte[] macBytes = new byte[6];
// 提取 MAC 地址的每个字节
for (int i = 0; i < 6; i++) {
macBytes[5 - i] = (byte) (macLong >> (8 * i));
}
StringBuilder mac = new StringBuilder();
// 构造 MAC 地址字符串
for (int i = 0; i < 6; i++) {
mac.append(String.format("%02X", macBytes[i]));
if (i < 5) {
mac.append(spec);
}
}
return mac.toString();
}
}