##淘寶短鏈接如何設計?
體驗淘寶短鏈接業務場景
場景1:淘寶短信
你們應該收到淘寶的短信
【天貓】有優惠啦!黃皮金煌芒果(水仙芒)帶箱10斤49.8元!
核薄無絲很甜喔!購買: c.tb.cn/c.ZzhFZ0 急鮮豐 退訂回TD
打開IE,輸入 c.tb.cn/c.ZzhFZ0 就轉變爲如下:
https://h5.m.taobao.com/ecrm/jump-to-app.html?scm=20140608.2928562577.LT_ITEM.1699166744&target_url=
http%3A%2F%2Fh5.m.taobao.com%2Fawp%2Fcore%2Fdetail.htm%3Fid%3D567221004504%26scm=20140607.2928562577.
LT_ITEM.1699166744&spm=a313p.5.1cfl9ch.947174560063&short_name=c.ZzhFZ0&app=chrome
場景2:淘寶APP分享URL
【這個#聚划算團購#寶貝不錯:【官方旗艦】步步高家教機S5英語小學初高中課本同步小天才平板
兒童點讀學習機智能學生平板電腦護眼旗艦店(分享自@手機淘寶android客戶端)】
https://m.tb.cn/h.eAE6vuE
點£擊☆鏈ㄣ接,再選擇瀏覽→噐咑ぺ鐦;或椱ァ製這句話€eyuf1YeAXFf€後打開👉淘宀┡ē👈
打開IE,輸入https://m.tb.cn/h.eAE6vuE 就轉變爲如下:
https://detail.tmall.com/item.htm?id=597254411409&price=3998-4398&sourceType=item&sourceType=item&suid=
4c8fc4d8-cb5e-40c0-b4b6-c4a06598781a&ut_sk=1.WmH11veugHoDAGWzSv+jAZg2_21646297_1574219840558.Copy.1&un
=ceed7d76bfbe7a3b4b68d5f77a161062&share_crt_v=1&spm=a2159r.13376460.0.0&sp_tk=4oKzaUU0SllFcWZuRjLigrM=
&cpp=1&shareurl=true&short_name=h.eF25Q3n&sm=505e90&app=chrome&sku_properties=1627207:28332
體驗了以上2個場景,我們來總結:
- 先說下什麼是短鏈接?
就是把普通網址,轉換成比較短的網址。 - 短鏈接有什麼好處?
- 節省網址長度,便於社交化傳播。
- 方便後臺跟蹤點擊量、統計。
案例實戰:SpringBoot+Redis高併發《短鏈接轉換器》
《短鏈接轉換器》的原理:
- 長鏈接轉換爲短鏈接
實現原理:長鏈接轉換爲短鏈接加密串key,然後存儲於redis的hash結構中。 - 重定向到原始的url
實現原理:通過加密串key到redis找出原始url,然後重定向出去
package com.agan.redis.service;
import org.apache.commons.codec.digest.DigestUtils;
/**
* 將長網址 md5 生成 32 位簽名串,分爲 4 段, 每段 8 個字節
* 對這四段循環處理, 取 8 個字節, 將他看成 16 進制串與 0x3fffffff(30位1) 與操作, 即超過 30 位的忽略處理
* 這 30 位分成 6 段, 每 5 位的數字作爲字母表的索引取得特定字符, 依次進行獲得 6 位字符串
* 總的 md5 串可以獲得 4 個 6 位串,取裏面的任意一個就可作爲這個長 url 的短 url 地址
*/
public class ShortUrlGenerator {
//26+26+10=62
public static final String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h",
"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
"u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z"};
/**
* 一個長鏈接URL轉換爲4個短KEY
*/
public static String[] shortUrl(String url) {
String key = "";
//對地址進行md5
String sMD5EncryptResult = DigestUtils.md5Hex(key + url);
System.out.println(sMD5EncryptResult);
String hex = sMD5EncryptResult;
String[] resUrl = new String[4];
for (int i = 0; i < 4; i++) {
//取出8位字符串,md5 32位,被切割爲4組,每組8個字符
String sTempSubString = hex.substring(i * 8, i * 8 + 8);
//先轉換爲16進賬,然後用0x3FFFFFFF進行位與運算,目的是格式化截取前30位
long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
String outChars = "";
for (int j = 0; j < 6; j++) {
//0x0000003D代表什麼意思?他的10進制是61,61代表chars數組長度62的0到61的座標。
//0x0000003D & lHexLong進行位與運算,就是格式化爲6位,即61內的數字
//保證了index絕對是61以內的值
long index = 0x0000003D & lHexLong;
outChars += chars[(int) index];
//每次循環按位移5位,因爲30位的二進制,分6次循環,即每次右移5位
lHexLong = lHexLong >> 5;
}
// 把字符串存入對應索引的輸出數組
resUrl[i] = outChars;
}
return resUrl;
}
public static void main(String[] args) {
// 長連接
String longUrl = "https://detail.tmall.com/item.htm?id=597254411409";
// 轉換成的短鏈接後6位碼,返回4個短鏈接
String[] shortCodeArray = shortUrl(longUrl);
for (int i = 0; i < shortCodeArray.length; i++) {
// 任意一個都可以作爲短鏈接碼
System.out.println(shortCodeArray[i]);
}
}
}
package com.agan.redis.controller;
import com.agan.redis.service.ShortUrlGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @author 阿甘
* @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220
* @version 1.0
* 注:如有任何疑問歡迎阿甘老師微信:agan-java 隨時諮詢老師。
*/
@RestController
@Slf4j
public class ShortUrlController {
@Autowired
private HttpServletResponse response;
@Autowired
private RedisTemplate redisTemplate;
private final static String SHORT_URL_KEY="short:url";
/**
* 長鏈接轉換爲短鏈接
* 實現原理:長鏈接轉換爲短加密串key,然後存儲在redis的hash結構中。
*/
@GetMapping(value = "/encode")
public String encode(String url) {
//一個長鏈接url轉換爲4個短加密串key
String [] keys= ShortUrlGenerator.shortUrl(url);
//任意取出其中一個,我們就拿第一個
String key=keys[0];
//用hash存儲,key=加密串,value=原始url
this.redisTemplate.opsForHash().put(SHORT_URL_KEY,key,url);
log.info("長鏈接={},轉換={}",url,key);
return "http://127.0.0.1:9090/"+key;
}
/**
* 重定向到原始的URL
* 實現原理:通過短加密串KEY到redis找出原始URL,然後重定向出去
*/
@GetMapping(value = "/{key}")
public void decode(@PathVariable String key) {
//到redis中把原始url找出來
String url=(String) this.redisTemplate.opsForHash().get(SHORT_URL_KEY,key);
try {
//重定向到原始的url
response.sendRedirect(url);
} catch (IOException e) {
e.printStackTrace();
}
}
}