如何在Java中创建用户友好的唯一ID,UUID或其他唯一标识符

我通常使用UUID类生成唯一ID。 如果这些ID仅由技术系统使用,它们可以正常工作,它们不关心它们有多长:

System.out.println(UUID.randomUUID().toString()); > 67849f28-c0af-46c7-8421-94f0642e5d4d 

有没有一种很好的方法来创建用户友好的唯一ID(比如来自tinyurl的那些)比UUID稍短? 用例:您希望通过邮件向您的客户发送ID,然后客户访问您的网站并将该数字输入表单,如凭证ID。

我假设UUID在UUID的128位范围的整个范围内均等地生成。 那么仅仅使用较低的64位是圣人吗?

 System.out.println(UUID.randomUUID().getLeastSignificantBits()); 

欢迎任何反馈。

我假设UUID在UUID的128位范围的整个范围内均等地生成。

首先,您的假设可能不正确,具体取决于UUID类型(1,2,3或4)。 从Java UUID文档 :

存在这些全局标识符的不同变体。 该类的方法用于操纵Leach-Salz变体,尽管构造函数允许创建任何UUID变体(如下所述)。

变体2(Leach-Salz)UUID的布局如下:最重要的长度包括以下无符号字段:

 0xFFFFFFFF00000000 time_low 0x00000000FFFF0000 time_mid 0x000000000000F000 version 0x0000000000000FFF time_hi 

最不重要的长整数由以下无符号字段组成:

 0xC000000000000000 variant 0x3FFF000000000000 clock_seq 0x0000FFFFFFFFFFFF node 

variant字段包含一个标识UUID布局的值。 上述位布局仅对变量值为2的UUID有效,表示Leach-Salz变量。

version字段包含一个描述此UUID类型的值。 UUID有四种不同的基本类型:基于时间,DCE安全性,基于名称和随机生成的UUID。 这些类型的版本值分别为1,2,3和4。

做你正在做的事情的最好方法是生成一个随机字符串,代码看起来像这样( 源代码 ):

 public class RandomString { public static String randomstring(int lo, int hi){ int n = rand(lo, hi); byte b[] = new byte[n]; for (int i = 0; i < n; i++) b[i] = (byte)rand('a', 'z'); return new String(b, 0); } private static int rand(int lo, int hi){ java.util.Random rn = new java.util.Random(); int n = hi - lo + 1; int i = rn.nextInt(n); if (i < 0) i = -i; return lo + i; } public static String randomstring(){ return randomstring(5, 25); } /** * @param args */ public static void main(String[] args) { System.out.println(randomstring()); } } 

如果你非常担心碰撞或其他什么,我建议你对你的UUID进行base64编码,这应该减少它的大小。

故事的道德:不要依赖于UUID的各个部分,因为它们是全面设计的。 如果您确实需要依赖UUID的各个部分,请确保您熟悉特定的UUID类型和实现。

以下是另一种生成用户友好ID的方法:
http://thedailywtf.com/Articles/The-Automated-Curse-Generator.aspx

(但你应该选择坏词filter)

任何UUID / Guid只有16字节的数据。 这16个字节可以使用BASE64(或BASE64url)轻松编码,然后剥离字符串末尾的所有“=”字符。

这给出了一个漂亮的短字符串,它仍然保存与UUID / Guid相同的数据。 换句话说,如果有必要,可以从该数据重新创建UUID / Guid。

这是一种生成URL友好的22个字符的UUID的方法

 public static String generateShortUuid() { UUID uuid = UUID.randomUUID(); long lsb = uuid.getLeastSignificantBits(); long msb = uuid.getMostSignificantBits(); byte[] uuidBytes = ByteBuffer.allocate(16).putLong(msb).putLong(lsb).array(); // Strip down the '==' at the end and make it url friendly return Base64.encode(uuidBytes) .substring(0, 22) .replace("/", "_") .replace("+", "-"); } 

对于您的用例,最好跟踪注册用户的运行计数,并为每个值生成一个字符串标记,如下所示:

 public static String longToReverseBase62(long value /* must be positive! */) { final char[] LETTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); StringBuilder result = new StringBuilder(9); do { result.append(LETTERS[(int)(value % 62)]); value /= 62l; } while (value != 0); return result.toString(); } 

出于安全原因,如果你将值设置为非顺序的会更好,所以每次用户注册时,你都可以增加值,例如1024(这样可以生成uuids为2 ^ 64/2 ^ 10 = 2 ^ 54个用户肯定比你需要的更多:)

只为你 :) :

 private final static char[] idchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray(); private static String createId(int len) { char[] id = new char[len]; Random r = new Random(System.currentTimeMillis()); for (int i = 0; i < len; i++) { id[i] = idchars[r.nextInt(idchars.length)]; } return new String(id); } 

这个怎么样? 实际上,此代码最多返回13个字符(数字和小写字母)。

 import java.nio.ByteBuffer; import java.util.UUID; /** * Generate short UUID (13 characters) * * @return short UUID */ public static String shortUUID() { UUID uuid = UUID.randomUUID(); long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong(); return Long.toString(l, Character.MAX_RADIX); }