淘寶短鏈接業務

##淘寶短鏈接如何設計?

體驗淘寶短鏈接業務場景

場景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個場景,我們來總結:

  1. 先說下什麼是短鏈接?
    就是把普通網址,轉換成比較短的網址。
  2. 短鏈接有什麼好處?
  • 節省網址長度,便於社交化傳播。
  • 方便後臺跟蹤點擊量、統計。

案例實戰:SpringBoot+Redis高併發《短鏈接轉換器》

《短鏈接轉換器》的原理:

  1. 長鏈接轉換爲短鏈接
    實現原理:長鏈接轉換爲短鏈接加密串key,然後存儲於redis的hash結構中。
  2. 重定向到原始的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();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章