/* * 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)。
* 由于springboot 默认使用此构造函数构造UUID 导致致命BUG 废弃
* 下个大版本删除
* @deprecated 请使用 UUID.getTimeBased() */ @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(); } }