短链接生成算法

一、什么是短链接? 

就是把平时长的网址链接,转换成很短的网址链接。

二、短链接有什么好处?  

  • 网址很短,便于社交传播
  • 方便根据短链跟踪统计

三、体验短链接业务场景

场景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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章