一、什么是短链接?
就是把平时长的网址链接,转换成很短的网址链接。
二、短链接有什么好处?
- 网址很短,便于社交传播
- 方便根据短链跟踪统计
三、体验短链接业务场景
场景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个字节处理,将它与0x3FFFFFFF(30位1)位与运算,截取前30位二进制 * 3. 将30位二进制分为6组,每段与0x0000003D位与运算,获取数组chars数组的下标,就可以得到6位字符串 * 4. 32位加密串可以获取4组6位短链,可取里面任意一个作为长链接的短链 */
效果如下
位与说明
0x3FFFFFFF 2进制:111111111111111111111111111111
0x3c181996 2进制:111100000110000001100110010110
0x3FFFFFFF & 0x3c181996 位与运算后:111100000110000001100110010110
0x0000003D 2进制:111101
0x0000003D 10进制:61
具体实现
/** * 短链接生成算法 * <p> * 1. 将长链接网址MD5加密,生成32位字符,然后切割分为4组 每组8个字节 * 2. 对每组内8个字节处理,将它与0x3FFFFFFF(30位1)位与运算,截取前30位二进制 * 3. 将30位二进制分为6组,每段与0x0000003D位与运算,获取数组chars数组的下标,就可以得到6位字符串 * 4. 32位加密串可以获取4组6位短链,可取里面任意一个作为长链接的短链 */ 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); // 生成4组6位短链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))); // 位与运算,有0出0 全1出1 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 进行位与运算,有0出0 全1出1 // 目的:截取前30位二进制 long hexLong = 0x3FFFFFFF & Long.parseLong(temp, 16); StringBuffer outChar = new StringBuffer(); // 把前面30位二进制拆分成6组,每组5位二进制 for (int j = 0; j < 6; j++) { // 0x0000003D的10进制是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; } }