短鏈接生成算法

一、什麼是短鏈接? 

就是把平時長的網址鏈接,轉換成很短的網址鏈接。

二、短鏈接有什麼好處?  

  • 網址很短,便於社交傳播
  • 方便根據短鏈跟蹤統計

三、體驗短鏈接業務場景

場景1:推廣短信

以我收到的推廣短信爲例:

【AAS旗艦店】今晚0點雙旦狂歡,指定商品前一小時享8.5折,
下單即贈身體乳 https://s.tb.cn/y6.VpI6e -回T退訂

 打開瀏覽器,複製鏈接 https://s.tb.cn/y6.VpI6e 打開,就變成下面這個長鏈接了:

https://aashzp.m.tmall.com/?ajson=1&parentCatId=0&bc_fl_src=tbsms_crm_3705444440_isvsmg%241985808584440_8800958846

 

場景2:商品分享

自己生成一個分享,內容長下面這樣:

 97嘻就子小你他然就看是在上,
 https://m.tb.cn/h.fj1UAkD?sm=a8b47c  
【官方正品】HR/赫蓮娜 綠寶瓶精華PRO 100ml 修護緊緻保溼

 打開瀏覽器,複製鏈接 https://m.tb.cn/h.fj1UAkD?sm=a8b47c 打開,就變成下面這個長鏈接了:

https://h5.m.taobao.com/awp/core/detail.htm?ut_sk=1.XOjlkWoncxMDAAYygVvhI0CS_21380790_1640269776154.Copy.1&id=645568351481&sourceType=item&price=2580&suid=D06C2ECF-F76B-401E-B951-58E657BF8473&shareUniqueId=14249255760&un=f7b24c964aced77f0a62cb2c046d31df&share_crt_v=1&un_site=0&spm=a2159r.13376460.0.0&sp_tk=5bCx5a2Q5bCP5L2g5LuW54S25bCx55yL5piv5Zyo5LiK&bc_fl_src=share-104876817051551-2-2&cpp=1&shareurl=true&short_name=h.fj1UAkD&bxsign=scdj_6JfE23mjgVCqKKOMvDqdasx8u7jsYqqB5AS2EbXcIDDxw_La9PTd_pR4fYIKyQ8G-ZTCU815Kh8z9atg9rTw2yP3bKn8IugksOVSvcw-vOhZ4qhF7HHycnjD_ktg-5&sm=a8b47c&app=chrome  

 

四、算法實現過程

思路

/**
 * 短鏈接生成算法
 * <p>
 * 1. 將長鏈接網址MD5加密,生成32位字符,然後切割分爲4組 每組8個字節
 * 2. 對每組內8個字節處理,將它與0x3FFFFFFF301)位與運算,截取前30位二進制
 * 3. 30位二進制分爲6組,每段與0x0000003D位與運算,獲取數組chars數組的下標,就可以得到6位字符串
 * 4. 32位加密串可以獲取46位短鏈,可取裏面任意一個作爲長鏈接的短鏈
 */

效果如下

位與說明

0x3FFFFFFF 2進制:111111111111111111111111111111
0x3c181996 2進制:111100000110000001100110010110
0x3FFFFFFF & 0x3c181996 位與運算後:111100000110000001100110010110
0x0000003D 2進制:111101
0x0000003D 10進制:61

具體實現

/**
 * 短鏈接生成算法
 * <p>
 * 1. 將長鏈接網址MD5加密,生成32位字符,然後切割分爲4組 每組8個字節
 * 2. 對每組內8個字節處理,將它與0x3FFFFFFF301)位與運算,截取前30位二進制
 * 3. 30位二進制分爲6組,每段與0x0000003D位與運算,獲取數組chars數組的下標,就可以得到6位字符串
 * 4. 32位加密串可以獲取46位短鏈,可取裏面任意一個作爲長鏈接的短鏈
 */
public class ShortUrlGenerator {
    public static String[] chars = new String[]{
            "a", "b", "c", "d", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
            "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "A", "B", "C", "D", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    public static void main(String[] args) {
        // 長鏈接文本
        String longUrl = "https://h5.m.taobao.com/awp/core/detail.htm?ut_sk=1.XOjlkWoncxMDAAYygVvhI0CS_21380790_1640269776154.Copy.1&id=645568351481&sourceType=item&price=2580&suid=D06C2ECF-F76B-401E-B951-58E657BF8473&shareUniqueId=14249255760&un=f7b24c964aced77f0a62cb2c046d31df&share_crt_v=1&un_site=0&spm=a2159r.13376460.0.0&sp_tk=5bCx5a2Q5bCP5L2g5LuW54S25bCx55yL5piv5Zyo5LiK&bc_fl_src=share-104876817051551-2-2&cpp=1&shareurl=true&short_name=h.fj1UAkD&bxsign=scdS1njVAfx-0lliKyfKqmu-fQeyJFq1c_69OVO1RV1nXVSSffpMMvYQ7zQiJUAMBoqlM5EDiop5WS6Ei0gF5O6HpcwrhNpOkvbSZ322gDPdhPXmT-cpiKUDkvKmpC9CqCO&sm=a8b47c&app=chrome";
        System.out.println(longUrl);

        // 生成46位短鏈code
        List<String> shortCodes = shortUrl(longUrl);
        shortCodes.forEach(System.out::println);

        // 0x3FFFFFFF 2進制
        System.out.println(String.format("0x3FFFFFFF 2進制:%s", Long.toBinaryString(0x3FFFFFFF)));
        // 3c181996
        System.out.println(String.format("0x3c181996 2進制:%s", Long.toBinaryString(0x3c181996)));
        // 位與運算,有00 11
        System.out.println(String.format("0x3FFFFFFF & 0x3c181996 位與運算後:%s", Long.toBinaryString(0x3FFFFFFF & 0x3c181996)));

        System.out.println(String.format("0x0000003D 2進制:%s", Long.toBinaryString(0x0000003D)));
        System.out.println(String.format("0x0000003D 10進制:%s", Long.parseLong("0000003D", 16)));
    }

    /**
     * 生成短鏈code
     *
     * @param longUrl 長鏈接文本
     * @return 4組短鏈
     */
    private static List<String> shortUrl(String longUrl) {
        List<String> result = new ArrayList<>();

        // 先對長鏈接進行MD5加密,生成32位字符串
        String md5Encrypt = DigestUtils.md5Hex(longUrl);

        // 對加密字符串切割4組,每組8個字符
        for (int i = 0; i < 4; i++) {
            String temp = md5Encrypt.substring(i * 8, (i + 1) * 8);

            // 先轉爲16進制 就是在字符串前面加了0x
            // 然後與0x3FFFFFFF 進行位與運算,有00 11
            // 目的:截取前30位二進制
            long hexLong = 0x3FFFFFFF & Long.parseLong(temp, 16);

            StringBuffer outChar = new StringBuffer();
            // 把前面30位二進制拆分成6組,每組5位二進制
            for (int j = 0; j < 6; j++) {
                // 0x0000003D10進制是61,而61是數組chars數組的下標
                // 目的:保證下標在61                long index = 0x0000003D & hexLong;
                outChar.append(chars[(int) index]);

                // 按位向右移5位,30位的二進制  6次循環既可以結束
                hexLong = hexLong >> 5;
            }
            result.add(outChar.toString());
        }

        return result;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章