淘宝短链接业务

##淘宝短链接如何设计?

体验淘宝短链接业务场景

场景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();
        }
    }
}

你可能感兴趣的:(redis)