SpringBoot实现短链跳转

news2024/9/22 5:36:11

目录

1.背景介绍

2.短链跳转的意义    

3.SpringBoot中的代码实现

1.建议短链-长链的数据库表:t_url_map:

2.映射实体

3.Dao层实现

4.Service层实现

5.Controller层实现 

3.结果测试

4.问题


1.背景介绍

        短链跳转是一种通过将长链接转换为短链接的方式,以便在互联网上进行链接共享和传播的技术。通常情况下,长链接可能由于包含大量参数或者较长的路径而显得复杂且不易记忆,而短链则是将原始长链接通过特定算法转换为较短的链接,使得它更容易分享、传播和展示

        短链跳转服务通常由第三方提供,用户可以将需要缩短的长链接提交到该服务,服务会返回一个短链接,当用户访问这个短链接时,会被重定向到原始的长链接地址。这种服务通常还提供了统计功能,可以跟踪短链接被点击的次数访问来源等信息,帮助用户了解链接的传播效果。

        短链跳转服务有助于美化链接、节省空间、方便分享和统计链接访问情况,因此被广泛应用于社交媒体、微博客、推广活动等各种互联网应用场景中。

        比如在b站中,一个视频的网址原来是这样的:

        在移动端中,点击分享按钮,复制其链接:

       

        它会变成如下链接形式:

      【Cookie、Session、Token、JWT一次性讲完-哔哩哔哩】 https://b23.tv/0SMtYq6

        点击该链接后,你会发现浏览器的网址URL为原来的长链接形式,也就是说这其中发生了重定向 ,而这个过程就是这篇博客要提到的短链跳转了。

2.短链跳转的意义    

  1. 节省空间:长链接可能会很长,不方便分享或展示,通过短链跳转可以将长链接转换为短链接,节省字符空间。

  2. 美化链接:短链看起来更简洁、美观,对于需要展示给用户或发布到社交媒体等场景更具吸引力。

  3. 防止链接失效:某些长链接可能会因为过期、失效或变动而无法访问,通过短链跳转可以在后台进行管理和更新,保证链接的可访问性。

  4. 统计和跟踪:通过短链跳转服务可以对链接的点击量、来源、地域等信息进行统计和分析,帮助用户了解链接的受众和效果。

  5. 方便分享:短链更容易复制、粘贴和分享,适用于短信、微博、邮件等分享场景,提高分享效率。

  6. 隐藏原始链接:有时候希望隐藏原始链接的信息,通过短链跳转可以起到一定的保护作用,防止泄露敏感信息。

3.SpringBoot中的代码实现

        这里我们以快速入门为主,即主要实现长链到短链的映射逻辑。

1.建议短链-长链的数据库表:t_url_map:

2.映射实体
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.Instant;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UrlMap {


    private Long id;

    private String longUrl;

    private String shortUrl;

    private String username;

    private Instant expireTime;

    private Instant creationTime;



}

        这里要添加lombok依赖:

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
3.Dao层实现

        这里简单写三个关键的接口方法:根据长链找短链(若无则生成短链)、根据短链找长链(若无则跳转失败页面)、插入实体

import com.zhan.zhan215.Entity.UrlMap;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.time.Instant;
import java.util.List;


@Mapper
public interface UrlMapMapper {

    UrlMap findFirstByLongUrl(@Param("longUrl") String longUrl, @Param("username") String username);

    void saveUrlMap(UrlMap urlMap);

    UrlMap findByShortUrl(String shortUrl);


}

        对应的xml映射:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhan.zhan215.Dao.UrlMapMapper">

    <select id="findFirstByLongUrl" parameterType="string" resultType="com.zhan.zhan215.Entity.UrlMap">

        select *

        from t_url_map

        where longUrl =#{longUrl} and username = #{username}

        limit 1

    </select>

    <!-- 在Mapper XML文件中定义保存urlMap对象的方法 -->
    <insert id="saveUrlMap" parameterType="com.zhan.zhan215.Entity.UrlMap">
        INSERT INTO t_url_map (shortUrl, longUrl,username)
        VALUES (#{shortUrl}, #{longUrl},#{username})
    </insert>

    <select id="findByShortUrl"  parameterType="string" resultType="com.zhan.zhan215.Entity.UrlMap">

        select *

        from t_url_map

        where shortUrl = #{shortUrl} limit 1

    </select>
4.Service层实现
import com.zhan.zhan215.Dao.UrlMapMapper;
import com.zhan.zhan215.Entity.UrlMap;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;

@Service
public class UrlMapService {

    @Resource
    private UrlMapMapper urlMapMapper;


    // 编码
    public String encode(String longUrl,String username) {

        UrlMap urlMap = urlMapMapper.findFirstByLongUrl(longUrl,username);

        // 看看该长链接是否存在
        // 如果存在并且其对应用户名等于已有用户名,则直接给出短链接
        if (urlMap != null&&username.equals(urlMap.getUsername())) {
            return urlMap.getShortUrl();

        } else {
            // 如果不存在,则生成短链接
            UrlMap urlMap1 = new UrlMap();
            // 生成短链接
            String shortLink = generateShortLink(longUrl,username);
            // 保存短链接
            urlMap1.setLongUrl(longUrl);
            urlMap1.setShortUrl(shortLink);
            urlMap1.setUsername(username);
            urlMap1.setCreationTime(Instant.now());
            urlMapMapper.saveUrlMap(urlMap1);


            return shortLink;
        }
    }

    // 解码
    public String decode(String shortUrl){

        // 根据短链接获取长链接
        UrlMap byShortUrl = urlMapMapper.findByShortUrl(shortUrl);

        // 如果存在,返回长链接
        if(byShortUrl!=null){
            return byShortUrl.getLongUrl();
        }

        // 如果没有,返回首页(正常是返回一个失败页面)
        return "https://bilibili.com";

    }

    // 生成短链接
    public static String generateShortLink(String originalUrl,String username) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(originalUrl.getBytes());
            // 对原始URL进行MD5哈希计算

            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
                // 将字节数组转换为十六进制字符串
            }

            return sb.toString().substring(0, 8)+username;
            // 截取前8位,加上用户名(这里先简单默认用户名是4位数)
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }


}
5.Controller层实现 
import com.zhan.zhan215.Common.ResponseBean;
import com.zhan.zhan215.Service.UrlMapService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.RedirectView;

import javax.annotation.Resource;

@RestController
public class UrlMapController {

    @Resource
    private UrlMapService urlMapService;



    @PostMapping("/shorten")
    // 长链接转短连接,相当于实际项目中的点击“分享”,形成一条短连接
    public ResponseBean shorten(@RequestParam String longUrl,@RequestParam String username){

        String encode =  urlMapService.encode(longUrl,username);
        // 形成短链

        return ResponseBean.success(encode);

    }

    @GetMapping("redirect")
    //重定向
    public RedirectView redirectView(@RequestParam String shortUrl){

        String longUrl = urlMapService.decode(shortUrl);

        return new RedirectView(longUrl);
    }

}

相关的ResponseBean的返回结果集代码:

public class ResponseBean<T> {

    /** 200:操作成功  -1:操作失败**/

    // http 状态码
    private boolean success;

    // 返回的数据
    private T data;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static <T> ResponseBean<T> success(T data) {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(true);
        responseBean.setData(data);
        return responseBean;
    }

    public static <T> ResponseBean<T> error(T errorData) {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(false);
        responseBean.setData(errorData);
        return responseBean;
    }

    public static <T> ResponseBean<T> success() {
        ResponseBean<T> responseBean = new ResponseBean<>();
        responseBean.setSuccess(true);
        return responseBean;
    }

}

3.结果测试

        我们就拿刚刚那个b站的长链接作测试,即https://www.bilibili.com/video/BV18u4m1K7D4/?spm_id_from=333.1007.tianma.10-4-38.click&vd_source=1c7e32cfbc70017a24ee2c337620ff51

        

        可以看到短链接生成为1b9590bezhan,

        然后我们再用这条链接去测试能否跳转到原始链接:

        

        成功根据短链接定向到原始链接的网站了。

4.问题

        1.为什么生成短链接需要带上username参数?

         答:这里其实模仿的是不同用户对应同一个原始链接(或长链接)时,确保他们生成的短链接各不相同,这样可以方便后台追踪是由哪个用户分享的短链接,进而统计分享数。在表中LongUrl和shortUrl的对应关系为一对多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1481121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chrome浏览器新功能:节省内存,更方便查询内存占用情况

一、前言 Chrome浏览器一直被用户抱怨占用过多的内存&#xff0c;但是Google推出了Memory Saver功能来解决这个问题。该功能可以冻结不活跃的页面以节省内存。 现在&#xff0c;Google正在进一步开发这个功能&#xff0c;Chrome的Hover Cards功能将很快可以显示当前标签页使用了…

YOLOV8介绍

原文链接&#xff1a; 1、 详解YOLOv8网络结构/环境搭建/数据集获取/训练/推理/验证/导出 2、Yolov8的详解与实战 3、YOLOV8模型训练部署&#xff08;实战&#xff09;&#xff08;&#xff09;有具体部署和训练实现代码YOLOV8模型训练部署&#xff08;实战&#xff09;&…

bert 相似度任务训练,简单版本

目录 任务 代码 train.py predit.py 数据 任务 使用 bert-base-chinese 训练相似度任务&#xff0c;参考&#xff1a;微调BERT模型实现相似性判断 - 知乎 参考他上面代码&#xff0c;他使用的是 BertForNextSentencePrediction 模型&#xff0c;BertForNextSentencePred…

第三百七十六回

文章目录 1 .概念介绍2. 实现方法3. 示例代码 我们在上一章回中介绍了在页面之间共传递数据相关的内容&#xff0c;本章回中将介绍如何拦截路由.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 .概念介绍 本章回中介绍的路由拦截是指在路由运行过程中&#xff0c;对路由做…

01tire算法

01tire算法 #include<bits/stdc.h> using namespace std; #define maxn 210000 int a[maxn], ch[maxn][2], val[maxn], n, ans, tot; void insert(int x) {int now 0;for (int j 31; j > 0; j -- ){int pos ((x >> i) & 1);if (!ch[now][pos])ch[now][po…

elasticsearch7.17 terms聚合性能提升90%+

背景 ES7 相比于 ES6 有多个层面的优化&#xff0c;对于开源的ES而言&#xff0c;升级是必经之路。 ES的使用场景非常多&#xff0c;在升级过程中可能会遇到非预期的结果&#xff1b; 比如之前文章提到的典型案例&#xff1a;ES7.17版本terms查询性能问题 ES7.17版本terms查…

服务端向客户端推送数据的实现方案

在日常的开发中&#xff0c;我们经常能碰见服务端需要主动推送给客户端数据的业务场景&#xff0c;比如数据大屏的实时数据&#xff0c;比如消息中心的未读消息&#xff0c;比如聊天功能等等。 本文主要介绍SSE的使用场景和如何使用SSE。 服务端向客户端推送数据的实现方案有哪…

maven项目导入mysql依赖

最近在B站跟着狂神学习Mybatis&#xff0c;学到P2就卡住了&#xff0c;搭建的maven项目一直无法导入依赖&#xff0c;在网上查找了很多相关的解决方法&#xff0c;project structure不知道点进去多少回&#xff0c;始终无法解决&#xff0c;后来把responsity文件夹删除重置了一…

【代码随想录python笔记整理】第十六课 · 出现频率最高的字母

前言:本笔记仅仅只是对内容的整理和自行消化,并不是完整内容,如有侵权,联系立删。 一、哈希表初步 在之前的学习中,我们使用数组、字符串、链表等等,假如需要找到某个节点,则都要从头开始,逐一比较,直到找到为止。为了能够直接通过要查找的记录找到其存储位置,我们选…

RV1126芯片概述

RV1126芯片概述 前言1 主要特性2 详细参数 前言 1 主要特性 四核 ARM Cortex-A7 and RISC-V MCU250ms快速开机2.0Tops NPU14M ISP with 3帧 HDR支持3个摄像头同时输入4K H.264/H.265 视频编码和解码 2 详细参数

【王道数据结构】【chapter8排序】【P371t5】

编写一个算法&#xff0c;在基于单链表表示的待排序关键字序列上进行简单选择排序 #include <iostream> #include <time.h> #include <stdlib.h> typedef struct node{int data;struct node *next; }node,*pnode;pnode buynode(int x) {pnode tmp(pnode) mal…

2024腾讯云服务器8888元代金券领取、主机价格表新鲜出炉!

腾讯云优惠活动2024新春采购节活动上线&#xff0c;云服务器价格已经出来了&#xff0c;云服务器61元一年起&#xff0c;配置和价格基本上和上个月没什么变化&#xff0c;但是新增了8888元代金券和会员续费优惠&#xff0c;腾讯云百科txybk.com整理腾讯云最新优惠活动云服务器配…

遥感影像处理(ENVI+ChatGPT+python+ GEE)处理高光谱及多光谱遥感数据

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

【vue3】命令式组件封装,message封装示例;(函数式组件?)

仅做代码示例&#xff1b;当然改进的地方还是不少的&#xff0c;仅作为该类组件封装方式的初步启发&#xff1b; 理想大成肯定是想要像 饿了么 这些组件库一样。 有的人叫这函数式组件&#xff0c;有的人叫这命令式组件&#xff0c;我个人还是偏向于命令式组件的称呼。因为以vu…

【JVM】JVM相关机制

1. JVM内存区域划分 1.1 内存区域划分简介 内存区域划分&#xff1a;实际上JVM也是一个进程&#xff0c;进程运行时需要向操作系统申请一些系统资源&#xff08;内存就是典型的资源&#xff09;&#xff0c;这些内存空间就支撑着后续Java程序的运行&#xff0c;而这些内存又会…

php 支持mssqlserver

系统不支持:sqlsrv 需要一下几个环节 1.准备检测php版本 查看 VC 版本 查看操作系统位数&#xff1a;X86(32位) 和X64 2.下载php的sqlserver库 extensionphp_sqlsrv_74_nts_x64.dll extensionphp_pdo_sqlsrv_74_nts_x64.dll extensionphp_sqlsrv_74_nts_x64 extensionphp_…

用HTML5的<canvas>元素实现刮刮乐游戏

用HTML5的<canvas>元素实现刮刮乐 用HTML5的<canvas>元素实现刮刮乐&#xff0c;要求&#xff1a;将上面的“图层”的图像可用鼠标刮去&#xff0c;露出下面的“图层”的图像。 示例从简单到复杂。 简单示例 准备两张图像&#xff0c;我这里上面的图像top_imag…

【Spring】spring中怎么解决循环依赖的问题

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Spring ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 解决步骤 考虑 结语 我的其他博客 前言 在软件开发中&#xff0c;依赖注入是一种常见的设计模式&#xff0c;它可以帮助我们管…

探讨javascript的程序性能

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 本人会很热心的阐述自己的想法&#xff01;谢谢&#xff01;&#xff01;&#xff01; 文章目录 Web WorkerWorker之间通讯Worker销毁 Web Worker 当我们需要处理一些比较耗时的任务时&#xff0c;我们…

杭电OJ 2045 不容易系列之(3)—— LELE的RPG难题 C++

思路&#xff1a;我先模拟了一下1&#xff0c;2&#xff0c;3的情况&#xff0c;对应的是3 6 6&#xff0c;模拟到4的时候就有感觉了&#xff0c;1是不受到任何制约的&#xff0c;2到n-1是收到了前面一个的制约&#xff0c;n受到了n-1与1的制约&#xff0c;那么就可以去判断4 …