短網址服務核心在於「長 URL → 短 Code」的雙向映射。本文對比兩大主流算法:MD5 截取(定長 5-6 位、極低碰撞、適合美觀需求)與自增序列 Base62(變長、零碰撞、無限容量、適合高吞吐),提供生產級 Java 實現與工程化建議。
N*6 個 1 組成的二進制掩碼 & 運算,得 N*6 位二進制。61 (0x3D) & 運算得索引(0-61),查字符表 0-9a-zA-Z 拼接。static final char[] DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
public String shorten(String longUrl, int len) {
String md5 = DigestUtils.md5Hex(longUrl);
long mask = Long.parseLong("1".repeat(len * 6), 2);
for (int i = 0; i < 4; i++) {
String sub = md5.substring(i * 8, (i + 1) * 8);
String bin = Long.toBinaryString(Long.parseLong(sub, 16) & mask);
bin = StringUtils.leftPad(bin, len * 6, '0');
StringBuilder sb = new StringBuilder();
for (int j = 0; j < len; j++) {
int idx = Integer.parseInt(bin.substring(j * 6, (j + 1) * 6), 2) & 61;
sb.append(DIGITS[idx]);
}
if (!exists(sb.toString())) return sb.toString();
}
return null;
}
AtomicLong 獲取唯一序列號。private AtomicLong seq = new AtomicLong(0);
private String toBase62(long n) {
StringBuilder sb = new StringBuilder();
do { sb.append(DIGITS[(int)(n % 62)]); n /= 62; } while (n > 0);
return sb.reverse().toString();
}
public String shorten(String longUrl) { return toBase62(seq.incrementAndGet()); }
| 維度 | MD5 算法 | 自增序列 |
|---|---|---|
| 存儲結構 | 雙向 Map / DB 唯一索引 | DB 自增主鍵 + 短碼唯一索引 |
| 分布式擴展 | 需分布式鎖去重 | 分段號段 / Snowflake ID |
| 短碼長度 | 固定 5-6 位 | 1 位起,隨業務增長 |
| 可讀性 | 亂碼風格 | 遞增可預測 |
選型建議:營銷活動、社交分享優先 MD5 固定短碼;內部系統、高併發寫入優先自增 Base62。兩者均可共存,按業務標記區分。