实战-全局唯一邀请码功能实现
無論什么APP需要做推廣功能,而推廣功能多多少少都離不開邀請碼。被邀請用戶下載APP登錄時輸入邀請碼,邀請碼所有者將獲得一定的好處,比如積分獎勵、現金獎勵或者免費試用(VIP)等特權。一套優秀的邀請碼生成機制不僅確保全局唯一性,還需要考慮到性能等問題。本篇文章帶大家探究一下基于Java的邀請碼生成。
邀請碼實現
邀請碼的特性
- 唯一性:確保每個用戶的邀請碼都是獨一無二的,這樣系統才能判定誰為邀請者,甚至可以根據邀請碼進行反向推導。
- 隨機性:不能讓用戶從邀請碼上輕易的看出生成的規則。
- 高效性:生成邀請碼的算法不能過于復雜,或耗費過度系統資源。
- 簡潔性:用戶可以方便的輸入,記錄,辨別是否輸入錯誤等。
平時我們看到的邀請碼一般有兩種類型:純數字、數字+字母(通常大寫),而邀請碼的長度通常在6位左右就是為了滿足簡潔性。
隨機生成邀請碼
無論是純數字還是數字加大寫字母形式,使用隨機算法生成一個邀請碼然后判斷此隨機碼是否已經被使用,如果被使用則重新生成。這可能是最初步的思路,但此種方法弊端甚多。
以6為隨機數為例說明。6位隨機數取0-9共10個數字,生成邀請碼的范圍為000000-999999,總數為10的6次方,也就是100萬。試想一下,如果有50萬的用戶,那么采用隨機數的生成,每次生成的重復概率將在50%以上,而且會越來越重復率越高,多么可怕的性能損耗。
當然,在用戶量比較少的情況下此種方法不是完全不可行。可以通過數據庫或redis預先生成一批邀請碼,當注冊新用戶或用戶使用邀請碼的時候將邀請碼分配給對應的用戶。此種補漏的方法雖然解決了一部分性能的問題,但從根本上還是需要消耗數據庫或redis資源,時間維度和空間維度都有一定的損耗。
base編碼方式實現
在網絡傳輸中,最常用的base編碼是base64編碼,那么我們就借鑒一下base64的編碼思路來生成邀請碼。
一般來說生成一個用戶的邀請碼需要一個唯一的輸入參數,這里就用用戶的ID(長整型數)來作為輸入參數,輸出結果為6為數字+大寫字母。同時,通過邀請碼可以反推出用戶的ID。
首先,指定6位邀請碼的數據格式:
6位邀請碼:0-9十個數字,26個大寫字母,在這其中再去除掉0和1,O和I防止它們兩兩混淆。這樣,總共獲得了32個可用字符。那么能生成的邀請碼總數為32的6次方,也就是1073741824個。10億+個邀請碼,在業務初期足夠用戶使用,如果隨著業務的發展可對位數進行擴充。
一般情況用戶ID或用戶編號都為長整型數且遞增,那么現在我們將用戶ID映射成一個6位的base32編碼。
/*** 邀請碼生成器,基本原理:<br/>* 1)入參用戶ID:1 <br/>* 2)使用自定義進制轉換之后為:V <br/>* 3)轉換未字符串,并在后面添加'A':VA <br/>* 4)在VA后面再隨機補足4位,得到:VAHKHE <br/>* 5)反向轉換時以'A'為分界線,'A'后面的不再解析 <br/>** @author zzs*/ public class ShareCodeUtils {/*** 自定義進制(0,1沒有加入,容易與o,l混淆),數組順序可進行調整增加反推難度,A用來補位因此此數組不包含A,共31個字符。*/private static final char[] BASE = new char[]{'H', 'V', 'E', '8', 'S', '2', 'D', 'Z', 'X', '9', 'C', '7', 'P','5', 'I', 'K', '3', 'M', 'J', 'U', 'F', 'R', '4', 'W', 'Y', 'L', 'T', 'N', '6', 'B', 'G', 'Q'};/*** A補位字符,不能與自定義重復*/private static final char SUFFIX_CHAR = 'A';/*** 進制長度*/private static final int BIN_LEN = BASE.length;/*** 生成邀請碼最小長度*/private static final int CODE_LEN = 6;/*** ID轉換為邀請碼** @param id* @return*/public static String idToCode(Long id) {char[] buf = new char[BIN_LEN];int charPos = BIN_LEN;// 當id除以數組長度結果大于0,則進行取模操作,并以取模的值作為數組的坐標獲得對應的字符while (id / BIN_LEN > 0) {int index = (int) (id % BIN_LEN);buf[--charPos] = BASE[index];id /= BIN_LEN;}buf[--charPos] = BASE[(int) (id % BIN_LEN)];// 將字符數組轉化為字符串String result = new String(buf, charPos, BIN_LEN - charPos);// 長度不足指定長度則隨機補全int len = result.length();if (len < CODE_LEN) {StringBuilder sb = new StringBuilder();sb.append(SUFFIX_CHAR);Random random = new Random();// 去除SUFFIX_CHAR本身占位之后需要補齊的位數for (int i = 0; i < CODE_LEN - len - 1; i++) {sb.append(BASE[random.nextInt(BIN_LEN)]);}result += sb.toString();}return result;}/*** 邀請碼解析出ID<br/>* 基本操作思路恰好與idToCode反向操作。** @param code* @return*/public static Long codeToId(String code) {char[] charArray = code.toCharArray();long result = 0L;for (int i = 0; i < charArray.length; i++) {int index = 0;for (int j = 0; j < BIN_LEN; j++) {if (charArray[i] == BASE[j]) {index = j;break;}}if (charArray[i] == SUFFIX_CHAR) {break;}if (i > 0) {result = result * BIN_LEN + index;} else {result = index;}}return result;}public static void main(String[] args) {String code = idToCode(1L);System.out.println(code);System.out.println(codeToId(code));}}以上方法通過31個字符長度的數組,外加一個分割字符“A”,完成了6位邀請碼的生成過程。同時,根據生成的邀請碼又可以反推出用戶ID(或用戶編號)。此種方法簡單高效,又確保了根據每個用戶ID生成的邀請碼的唯一性。
當然,可以通過打亂BASE數組中字符的順序讓產生的邀請碼更加隨機一些。如果想讓ID的復雜度更高,可以先將ID補全為指定位數,然后給它在指定位置加“鹽”或者調換位置等方式進行處理。但需要保證加鹽或調換之后ID的唯一性。
業務擴充
當業務不斷發展,如果10億的邀請碼依舊無法滿足業務需求,則可進行以下方式進行擴充:
- 將邀請碼位數進行擴充,比如變為7位、8位或更多位。
- 將BASE數組里面的數據進行擴充,比如講小寫字母也添加進來。
Github源代碼下載:源碼下載。
原文鏈接:https://www.choupangxia.com/topic/detail/58
關注微信公眾
更多技術、架構、管理等知識分享,請關注微信公眾號:程序新視界(ID:ershixiong_see_world)。
總結
以上是生活随笔為你收集整理的实战-全局唯一邀请码功能实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 跟着莫烦python 从零开始强化学习之
- 下一篇: 高等数学同济第七版课后答案上册