mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add ULID
This commit is contained in:
parent
9a3d6857db
commit
b5cd26822e
@ -52,36 +52,36 @@ public class Number128 extends Number implements Comparable<Number128>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取高位值
|
* 获取最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
*
|
*
|
||||||
* @return 高位值
|
* @return 最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
*/
|
*/
|
||||||
public long getMostSigBits() {
|
public long getMostSigBits() {
|
||||||
return mostSigBits;
|
return mostSigBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置高位值
|
* 设置最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
*
|
*
|
||||||
* @param hiValue 高位值
|
* @param hiValue 最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
*/
|
*/
|
||||||
public void setMostSigBits(final long hiValue) {
|
public void setMostSigBits(final long hiValue) {
|
||||||
this.mostSigBits = hiValue;
|
this.mostSigBits = hiValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取低位值
|
* 获取最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
*
|
*
|
||||||
* @return 地位值
|
* @return 最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
*/
|
*/
|
||||||
public long getLeastSigBits() {
|
public long getLeastSigBits() {
|
||||||
return leastSigBits;
|
return leastSigBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置低位值
|
* 设置最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
*
|
*
|
||||||
* @param leastSigBits 低位值
|
* @param leastSigBits 最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
*/
|
*/
|
||||||
public void setLeastSigBits(final long leastSigBits) {
|
public void setLeastSigBits(final long leastSigBits) {
|
||||||
this.leastSigBits = leastSigBits;
|
this.leastSigBits = leastSigBits;
|
||||||
|
@ -21,6 +21,7 @@ import org.dromara.hutool.core.util.RandomUtil;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参考:https://github.com/zjcscut/framework-mesh/blob/master/ulid4j/src/main/java/cn/vlts/ulid/ULID.java
|
* 参考:https://github.com/zjcscut/framework-mesh/blob/master/ulid4j/src/main/java/cn/vlts/ulid/ULID.java
|
||||||
@ -51,10 +52,68 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
private static final long OVERFLOW = 0x0000000000000000L;
|
private static final long OVERFLOW = 0x0000000000000000L;
|
||||||
|
|
||||||
// region ----- Factory methods
|
// region ----- Factory methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的ULID,使用当前系统时间戳和随机数
|
||||||
|
*
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
public static ULID of() {
|
public static ULID of() {
|
||||||
return of(System.currentTimeMillis(), RandomUtil.randomBytes(RANDOMNESS_BYTE_LEN));
|
return of(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的ULID,使用指定系统时间戳和随机数
|
||||||
|
*
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
|
public static ULID of(final long timestamp) {
|
||||||
|
return of(timestamp, RandomUtil.getRandom());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的ULID,使用指定系统时间戳和指定随机对象
|
||||||
|
*
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
* @param random {@link Random}
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
|
public static ULID of(final long timestamp, final Random random) {
|
||||||
|
return of(timestamp, RandomUtil.randomBytes(RANDOMNESS_BYTE_LEN, random));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的ULID,使用指定系统时间戳和指定填充数
|
||||||
|
*
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
* @param randomness 指定填充数
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
|
public static ULID of(final long timestamp, final byte[] randomness) {
|
||||||
|
// 时间戳最多为48 bit(6 bytes)
|
||||||
|
checkTimestamp(timestamp);
|
||||||
|
Assert.notNull(randomness);
|
||||||
|
// 随机数部分长度必须为80 bit(10 bytes)
|
||||||
|
Assert.isTrue(RANDOMNESS_BYTE_LEN == randomness.length, "Invalid randomness");
|
||||||
|
|
||||||
|
long msb = 0;
|
||||||
|
// 时间戳左移16位,低位补零准备填入部分随机数位,即16_bit_uint_random
|
||||||
|
msb |= timestamp << 16;
|
||||||
|
// randomness[0]左移0位填充到16_bit_uint_random的高8位,randomness[1]填充到16_bit_uint_random的低8位
|
||||||
|
msb |= (long) (randomness[0x0] & 0xff) << 8;
|
||||||
|
// randomness[1]填充到16_bit_uint_random的低8位
|
||||||
|
msb |= randomness[0x1] & 0xff;
|
||||||
|
|
||||||
|
return new ULID(new Number128(ByteUtil.toLong(randomness, 2, ByteOrder.BIG_ENDIAN), msb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个Crockford`s Base32的ULID
|
||||||
|
*
|
||||||
|
* @param ulidString Crockford`s Base32的ULID
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
public static ULID of(final String ulidString) {
|
public static ULID of(final String ulidString) {
|
||||||
Objects.requireNonNull(ulidString, "ulidString must not be null!");
|
Objects.requireNonNull(ulidString, "ulidString must not be null!");
|
||||||
if (ulidString.length() != 26) {
|
if (ulidString.length() != 26) {
|
||||||
@ -75,6 +134,12 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
return new ULID(new Number128(least, most));
|
return new ULID(new Number128(least, most));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从bytes解析ULID
|
||||||
|
*
|
||||||
|
* @param data bytes
|
||||||
|
* @return ULID
|
||||||
|
*/
|
||||||
public static ULID of(final byte[] data) {
|
public static ULID of(final byte[] data) {
|
||||||
Objects.requireNonNull(data, "data must not be null!");
|
Objects.requireNonNull(data, "data must not be null!");
|
||||||
if (data.length != 16) {
|
if (data.length != 16) {
|
||||||
@ -91,24 +156,6 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
return new ULID(new Number128(leastSignificantBits, mostSignificantBits));
|
return new ULID(new Number128(leastSignificantBits, mostSignificantBits));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ULID of(final long timestamp, final byte[] randomness) {
|
|
||||||
// 时间戳最多为48 bit(6 bytes)
|
|
||||||
checkTimestamp(timestamp);
|
|
||||||
Assert.notNull(randomness);
|
|
||||||
// 随机数部分长度必须为80 bit(10 bytes)
|
|
||||||
Assert.isTrue(RANDOMNESS_BYTE_LEN == randomness.length, "Invalid randomness");
|
|
||||||
|
|
||||||
long msb = 0;
|
|
||||||
// 时间戳左移16位,低位补零准备填入部分随机数位,即16_bit_uint_random
|
|
||||||
msb |= timestamp << 16;
|
|
||||||
// randomness[0]左移0位填充到16_bit_uint_random的高8位,randomness[1]填充到16_bit_uint_random的低8位
|
|
||||||
msb |= (long) (randomness[0x0] & 0xff) << 8;
|
|
||||||
// randomness[1]填充到16_bit_uint_random的低8位
|
|
||||||
msb |= randomness[0x1] & 0xff;
|
|
||||||
|
|
||||||
return new ULID(new Number128(ByteUtil.toLong(randomness, 2, ByteOrder.BIG_ENDIAN), msb));
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
private final Number128 idValue;
|
private final Number128 idValue;
|
||||||
@ -122,27 +169,37 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
this.idValue = number128;
|
this.idValue = number128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
|
*
|
||||||
|
* @return 最高有效位(Most Significant Bit),64 bit(8 bytes)
|
||||||
|
*/
|
||||||
public long getMostSignificantBits() {
|
public long getMostSignificantBits() {
|
||||||
return this.idValue.getMostSigBits();
|
return this.idValue.getMostSigBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
|
*
|
||||||
|
* @return 最低有效位(Least Significant Bit),64 bit(8 bytes)
|
||||||
|
*/
|
||||||
public long getLeastSignificantBits() {
|
public long getLeastSignificantBits() {
|
||||||
return this.idValue.getLeastSigBits();
|
return this.idValue.getLeastSigBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the timestamp component of ULID
|
* 获取ULID的时间戳部分
|
||||||
*
|
*
|
||||||
* @return the timestamp component
|
* @return 时间戳
|
||||||
*/
|
*/
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
return this.idValue.getMostSigBits() >>> 16;
|
return this.idValue.getMostSigBits() >>> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the randomness component of ULID
|
* 获取ULID的随机数部分
|
||||||
*
|
*
|
||||||
* @return the randomness component
|
* @return 随机数部分
|
||||||
*/
|
*/
|
||||||
public byte[] getRandomness() {
|
public byte[] getRandomness() {
|
||||||
final long msb = this.idValue.getMostSigBits();
|
final long msb = this.idValue.getMostSigBits();
|
||||||
@ -156,6 +213,11 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
return randomness;
|
return randomness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自增ULID
|
||||||
|
*
|
||||||
|
* @return 返回自增ULID
|
||||||
|
*/
|
||||||
public ULID increment() {
|
public ULID increment() {
|
||||||
final long msb = this.idValue.getMostSigBits();
|
final long msb = this.idValue.getMostSigBits();
|
||||||
final long lsb = this.idValue.getLeastSigBits();
|
final long lsb = this.idValue.getLeastSigBits();
|
||||||
@ -164,9 +226,27 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
if (newLsb == OVERFLOW) {
|
if (newLsb == OVERFLOW) {
|
||||||
newMsb += 1;
|
newMsb += 1;
|
||||||
}
|
}
|
||||||
return new ULID(new Number128(lsb, msb));
|
return new ULID(new Number128(newLsb, newMsb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一个有序的ULID
|
||||||
|
*
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
* @return 如果给定时间戳与当前ULID相同,则返回自增ULID,否则返回一个新的ULID
|
||||||
|
*/
|
||||||
|
public ULID nextMonotonic(final long timestamp) {
|
||||||
|
if (getTimestamp() == timestamp) {
|
||||||
|
return increment();
|
||||||
|
}
|
||||||
|
return of(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转为bytes值
|
||||||
|
*
|
||||||
|
* @return bytes值
|
||||||
|
*/
|
||||||
public byte[] toBytes() {
|
public byte[] toBytes() {
|
||||||
final long msb = this.idValue.getMostSigBits();
|
final long msb = this.idValue.getMostSigBits();
|
||||||
final long lsb = this.idValue.getLeastSigBits();
|
final long lsb = this.idValue.getLeastSigBits();
|
||||||
@ -181,12 +261,22 @@ public class ULID implements Comparable<ULID>, Serializable {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转为UUID
|
||||||
|
*
|
||||||
|
* @return UUID
|
||||||
|
*/
|
||||||
public UUID toUUID() {
|
public UUID toUUID() {
|
||||||
final long msb = this.idValue.getMostSigBits();
|
final long msb = this.idValue.getMostSigBits();
|
||||||
final long lsb = this.idValue.getLeastSigBits();
|
final long lsb = this.idValue.getLeastSigBits();
|
||||||
return new UUID(msb, lsb);
|
return new UUID(msb, lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转为JDK的UUID
|
||||||
|
*
|
||||||
|
* @return UUID
|
||||||
|
*/
|
||||||
public java.util.UUID toJdkUUID() {
|
public java.util.UUID toJdkUUID() {
|
||||||
final long msb = this.idValue.getMostSigBits();
|
final long msb = this.idValue.getMostSigBits();
|
||||||
final long lsb = this.idValue.getLeastSigBits();
|
final long lsb = this.idValue.getLeastSigBits();
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023. looly(loolly@aliyun.com)
|
||||||
|
* Hutool is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* https://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dromara.hutool.core.data.id;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.lang.generator.Generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ULID生成器
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public class ULIDGenerator implements Generator<String> {
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
return ULID.of().toString();
|
||||||
|
}
|
||||||
|
}
|
@ -186,8 +186,23 @@ public class RandomUtil {
|
|||||||
* @return bytes
|
* @return bytes
|
||||||
*/
|
*/
|
||||||
public static byte[] randomBytes(final int length) {
|
public static byte[] randomBytes(final int length) {
|
||||||
|
return randomBytes(length, getRandom());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机bytes
|
||||||
|
*
|
||||||
|
* @param length 长度
|
||||||
|
* @param random {@link Random}
|
||||||
|
* @return bytes
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static byte[] randomBytes(final int length, Random random) {
|
||||||
|
if (null == random) {
|
||||||
|
random = getRandom();
|
||||||
|
}
|
||||||
final byte[] bytes = new byte[length];
|
final byte[] bytes = new byte[length];
|
||||||
getRandom().nextBytes(bytes);
|
random.nextBytes(bytes);
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user