SourceCode Java

Java实现长链接转换短链接

Posted on 2021-07-23,3 min read
  • 一般比较多的长链接转短链接的方法是对URL计算MD5,然后对MD5取指定位数的随机值。但是这种会导致冲突,可能需要在处理冲突产生比较大的开销。
  • 可以使用类似雪花ID的方法来产生随机数,这样可以保证随机数的递增。
  • 思路如下:
    • 产生一个54位的long值,组成:机器id(3位) + 时间戳(41位) + 随机值(10位),一共54位

    • 然后没6位将其转化为64进制,每一位分别用:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-来替代。

    • 最后产生一个短链接。

    • 代码如下:

      import lombok.extern.slf4j.Slf4j;
      
      import java.util.concurrent.ThreadLocalRandom;
      
      @Slf4j
      public class ShortLink {
      
          public ShortLink(byte machineId) {
              this.machineId = machineId;
          }
      
          /**
           * 用于生成短链接的字符
           */
          private final static char[] AVAILABLE_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-".toCharArray();
          /**
           * 用于产生随机数
           */
          private final ThreadLocalRandom random = ThreadLocalRandom.current();
          /**
           * 末尾随机值所占位数
           */
          private final static int RANDOM_ID_COUNT = 1 << 10;
          /**
           * 机器id
           */
          private final byte machineId;
      
          public String nextShortLink(String url){
              return generateShortLink(machineId, url);
          }
      
          /**
           * 生成短链接
           * 组成:机器id(3位) + 时间戳(41位) + 随机值(10位),一共54位
           *
           * @param machineId 机器id
           * @param url       url
           * @return {@link String}
           */
          private String generateShortLink(byte machineId, String url) {
              long id = generateId(machineId, url);
              char[] chars = new char[9];
              chars[0] = AVAILABLE_CHARS[(int) (id & 0x3fL)];
              chars[1] = AVAILABLE_CHARS[(int) ((id & 0xfc0L) >> 6)];
              chars[2] = AVAILABLE_CHARS[(int) ((id & 0x3f000L) >> 12)];
              chars[3] = AVAILABLE_CHARS[(int) ((id & 0xfc0000L) >> 18)];
              chars[4] = AVAILABLE_CHARS[(int) ((id & 0x3f000000L) >> 24)];
              chars[5] = AVAILABLE_CHARS[(int) ((id & 0xfc0000000L) >> 30)];
              chars[6] = AVAILABLE_CHARS[(int) ((id & 0x3f000000000L) >> 36)];
              chars[7] = AVAILABLE_CHARS[(int) ((id & 0xfc0000000000L) >> 42)];
              chars[8] = AVAILABLE_CHARS[(int) ((id & 0x3f000000000000L) >> 48)];
              return new String(chars);
          }
      
          /**
           * 生成id,用于后续生成短网址
           *
           * @param machineId 机器id
           * @param url       url
           * @return {@link long}
           */
          private long generateId(byte machineId, String url) {
              if (machineId < 0 || machineId > 7) {
                  throw new RuntimeException("机器ID错误");
              }
              int hashCode = url.hashCode();
              long timestamp = System.currentTimeMillis();
              long randomId = hash(hashCode, timestamp) % RANDOM_ID_COUNT;
              log.info("机器id为:{},对应的二进制为:{};时间戳为:{},对应的二进制为:{};随机值为:{},对应的二进制为:{}"
                      , machineId, Long.toBinaryString(machineId), timestamp, Long.toBinaryString(timestamp), randomId, Long.toBinaryString(randomId));
              return ((long) machineId << 51) | (timestamp << 10) | (randomId);
          }
      
          /**
           * 计算一个hash,由于hash只有32位,所以要扩散
           *
           * @param hashcode  hashcode
           * @param timestamp 时间戳
           * @return long
           */
          private long hash(long hashcode, long timestamp) {
              long randomVal = random.nextLong(timestamp & hashcode);
              return randomVal ^ timestamp;
          }
      }
      
      

下一篇: 基于Netty的RPC框架→

loading...