是否有任何方法从 String 生成相同的 UUID

我想知道是否有一种方法可以基于 String.生成相同的 UUID 我尝试用 UUID,它看起来不提供这个功能。

105108 次浏览

您可以通过这种方式使用 UUID 为您的输入 String 获得总是相同的 UUID:

 String aString="JUST_A_TEST_STRING";
String result = UUID.nameUUIDFromBytes(aString.getBytes()).toString();

UUID.nameUUIDFromBytes()只生成 MD5 UUID,但是 SHA1优于 MD5,如果向下兼容不是问题的话

下面的实用程序类生成 MD5 UUID 和 SHA-1 UUID。

package com.example;


import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;


/**
* Generates UUIDv3 (MD5) and UUIDv5 (SHA1).
*
* It is fully compliant with RFC-4122.
*/
public class HashUuid {


private static final int V3 = 3; // MD5
private static final int V5 = 5; // SHA-1


private static final String HASH_V3 = "MD5";
private static final String HASH_V5 = "SHA-1";


public static final UUID NAMESPACE_DNS = new UUID(0x6ba7b8109dad11d1L, 0x80b400c04fd430c8L);
public static final UUID NAMESPACE_URL = new UUID(0x6ba7b8119dad11d1L, 0x80b400c04fd430c8L);
public static final UUID NAMESPACE_OID = new UUID(0x6ba7b8129dad11d1L, 0x80b400c04fd430c8L);
public static final UUID NAMESPACE_X500 = new UUID(0x6ba7b8149dad11d1L, 0x80b400c04fd430c8L);


public static UUID v3(String name) {
return generate(V3, HASH_V3, null, name);
}


public static UUID v5(String name) {
return generate(V5, HASH_V5, null, name);
}


public static UUID v3(UUID namespace, String name) {
return generate(V3, HASH_V3, namespace, name);
}


public static UUID v5(UUID namespace, String name) {
return generate(V5, HASH_V5, namespace, name);
}


private static UUID generate(int version, String algorithm, UUID namespace, String name) {


MessageDigest hasher = hasher(algorithm);


if (namespace != null) {
ByteBuffer ns = ByteBuffer.allocate(16);
ns.putLong(namespace.getMostSignificantBits());
ns.putLong(namespace.getLeastSignificantBits());
hasher.update(ns.array());
}


hasher.update(name.getBytes(StandardCharsets.UTF_8));
ByteBuffer hash = ByteBuffer.wrap(hasher.digest());


final long msb = (hash.getLong() & 0xffffffffffff0fffL) | (version & 0x0f) << 12;
final long lsb = (hash.getLong() & 0x3fffffffffffffffL) | 0x8000000000000000L;


return new UUID(msb, lsb);
}


private static MessageDigest hasher(String algorithm) {
try {
return MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(String.format("%s not supported.", algorithm));
}
}


/**
* For tests!
*/
public static void main(String[] args) {


UUID namespace = UUID.randomUUID();
String name = "JUST_A_TEST_STRING";


System.out.println(String.format("UUID.nameUUIDFromBytes():     '%s'", UUID.nameUUIDFromBytes(name.getBytes())));
System.out.println();
System.out.println(String.format("HashUuid.v3(name):            '%s'", HashUuid.v3(name)));
System.out.println(String.format("HashUuid.v5(name):            '%s'", HashUuid.v5(name)));
System.out.println(String.format("HashUuid.v3(namespace, name): '%s'", HashUuid.v3(namespace, name)));
System.out.println(String.format("HashUuid.v5(namespace, name): '%s'", HashUuid.v5(namespace, name)));
}
}

This is the output:

UUID.nameUUIDFromBytes():     '9e120341-627f-32be-8393-58b5d655b751'


HashUuid.v3(name):            '9e120341-627f-32be-8393-58b5d655b751'
HashUuid.v5(name):            'e4586bed-032a-5ae6-9883-331cd94c4ffa'
HashUuid.v3(namespace, name): 'f0043437-723b-308f-a6c0-74ec36ddf9c2'
HashUuid.v5(namespace, name): '18a45fd8-8fab-5647-aad7-1d3264932180'

另外,你也可以使用 uuid-creator:

// Create a UUIDv5 (SHA1)
String name = "JUST_A_TEST_STRING";
UUID uuid = UuidCreator.getNameBasedSha1(name);

如果您正在寻找 Javascript 的替代方案,请参考 uuid-by-string,它也提供了使用 SHA-1或 MD5散列函数的选项。

你应该使用 UUID v5.

版本3和版本5的 UUID 是通过散列名称空间标识符和名称生成的。版本3使用 MD5作为哈希算法,版本5使用 SHA-1。1-维基百科

UUID v5需要 namespace。这个名称空间应该是 UUID v4,您可以只使用 在线生成。命名空间确保对于给定的输入,输出总是相同的。

可以找到 UUID v5的一个可能的实现 给你:

<!-- https://search.maven.org/artifact/com.github.f4b6a3/uuid-creator -->
<dependency>
<groupId>com.github.f4b6a3</groupId>
<artifactId>uuid-creator</artifactId>
<version>3.6.0</version>
</dependency>

它可用于以下方面:

UUID namespace = ; // todo generate a UUID v4.
String input = "input";
UUID uuid = UuidCreator.getNameBasedSha1(namespace, input);

(在某种程度上,名称空间的作用类似于随机数生成器的种子。相比之下,虽然种子应该是随机的,但我们的名称空间是常量。这就迫使我们的生成器总是为给定的输入产生相同的值。)