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

时间:2011-01-12 08:28:28

标签: java random 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());

欢迎任何反馈。

7 个答案:

答案 0 :(得分:9)

  

我假设生成了UUID   同样通过整个范围   128位UUID范围。

首先,您的假设可能不正确,具体取决于UUID类型(1,2,3或4)。来自the Java UUID docs

  

存在不同的变体   这些全局标识符。方法   这个类的用于操纵   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  
  

变体字段包含值   它标识了布局   UUID。上面描述的位布局   仅对具有a的UUID有效   变量值为2,表示   Leach-Salz变种。

     

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

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

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());

        }

}

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

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

答案 1 :(得分:3)

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

(但你应该选择坏词过滤器)

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

这是一种生成对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(这样可以生成2 ^ 64/2的uuids ^ 10 = 2 ^ 54个用户肯定比你需要的更多:)

答案 4 :(得分:1)

在撰写本文时,该问题的标题是:

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

生成用户友好 ID的问题是一个主观的问题。如果您具有唯一值,则有多种方法可以将其格式化为“用户友好”格式,并且所有方法都归结为使用“用户友好” ID一对一映射唯一值-如果输入值是唯一,“用户友好” ID也将唯一。

此外,至少在每个随机值均独立于其他值生成的情况下,通常不可能创建也是唯一 random 值。此外,还有很多事情要问自己是否要生成唯一的标识符(这些标识符来自我的section on unique random identifiers):

  1. 应用程序能否轻松检查标识符在所需范围和范围内的唯一性(例如,检查是否已存在具有该标识符的文件或数据库记录)?
  2. 应用程序可以承受为不同资源生成相同标识符的风险吗?
  3. 标识符是否必须很难猜测,仅仅是“看起来随机”还是都不是?
  4. 最终用户是否必须输入标识符或以其他方式中继标识符?
  5. 一个标识符标识的资源是否对知道该标识符的任何人可用(即使没有登录或以某种方式未授权)?
  6. 标识符必须令人难忘吗?

在您的情况下,您有几个相互冲突的目标:您希望标识符是唯一的,随机的,并且易于最终用户键入。但是您应该考虑的其他事项是:

  • 是否允许其他用户在知道ID的情况下访问ID标识的资源?如果没有,那么将需要额外的访问控制或更长的密钥长度。
  • 您的应用程序可以承受重复密钥的风险吗?如果是这样,则可以完全随机地生成密钥(例如,通过加密RNG,例如Java中的java.security.SecureRandom)。如果不是这样,那么您的目标将很难实现,尤其是对于出于安全目的的密钥。

此外,如果您希望最终用户必须输入ID,则应考虑谨慎选择字符集或allowing typing mistakes to be detected

答案 5 :(得分:0)

仅限你:):

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);
}

答案 6 :(得分:0)

这个怎么样?实际上,此代码最多返回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);
}