springboot 实现长链接转短链接

article/2025/10/9 18:57:56

实现结果: 

转换短链接api:

接口:http://127.0.0.1/api?url=urlencode('要缩短的网址')

例如:http://127.0.0.1/api?url=http%3a%2f%2fwww.baidu.com

返回:http://127.0.0.1/baidu

访问短链接即可还原原url;

转换原理: 将原url通过一系列方式,转换成6位短码(只要能不重复,随便怎么方式都行);将长短链接存入数据库,形成一条对应关系;访问短链接的时候,在数据库找到对应的长链接,并通过重定向实现原url的访问;(如果你的转换方式能过还原,也可以不要数据库,但必须保证转换后的短码不能重复)

核心代码参考 :https://www.cnblogs.com/latteyan/articles/5845117.html

实现步骤:

1.创建数据库(shorturl),创建一个表,存储长链接和与之对应的短链接;

CREATE TABLE `link` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`long_url` varchar(500) DEFAULT NULL COMMENT '长链接',`short_url` varchar(255) DEFAULT NULL COMMENT '短链接',PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

2.搭建springboot项目,搭建方式网上很多,自行查找;下图是项目构建完成的项目结构(public可以忽略):


3.逻辑层代码依次是:

entity:

package com.tips.entity;public class Link {private Integer id;private String longUrl;private String shortUrl;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLongUrl() {return longUrl;}public void setLongUrl(String longUrl) {this.longUrl = longUrl;}public String getShortUrl() {return shortUrl;}public void setShortUrl(String shortUrl) {this.shortUrl = shortUrl;}
}

dao:

package com.tips.mapper;import com.tips.entity.Link;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface LinkMapper {Link selectByPrimaryKey(Integer id);int insert(Link link);Link findByLongUrl(String longUrl);String findByShortUrl(String shortUrl);
}

service:

package com.tips.service;import com.tips.entity.Link;public interface LinkService {String save(Link link);String restoreUrl(String url);}

service.impl:

package com.tips.service.impl;

import com.tips.entity.Link;
import com.tips.mapper.LinkMapper;
import com.tips.service.LinkService;
import com.tips.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LinkServiceImpl  implements LinkService{@Autowired
    private LinkMapper linkMapper;

    /**
     * 转化url
     * 查询数据库是否已经存在 如果存在就返回数据库对应的短链接,如果不存在就查询一条新纪录并返回新的短链接
     * @param link
     * @return
     */
    @Override
    public String save(Link link) {String shortUrl = "http://127.0.0.1/";  
        String longUrl = link.getLongUrl();
        System.out.println(longUrl);
        Link link1 = linkMapper.findByLongUrl(longUrl);
        if(link1 == null) {shortUrl += this.gererateShortUrl(longUrl);
            link.setShortUrl(shortUrl);
            linkMapper.insert(link);
        }else{shortUrl = link1.getShortUrl();
        }return shortUrl;
    }@Override
    public String restoreUrl(String url) {return linkMapper.findByShortUrl(url);
    }/**
     * @param args
     */
    public static void main(String[] args) {String sLongUrl = "http://474515923.qzone.qq.com" ; //长链接
        LinkServiceImpl link = new LinkServiceImpl();
        String result = link.gererateShortUrl(sLongUrl);
        // 打印出结果
       System.out.println("短链接为: "+ result);
    }/**
     * 将长链接转换为短链接
     * @param url
     * @return
     */
    public String gererateShortUrl(String url) {// 可以自定义生成 MD5 加密字符传前的混合 KEY
        String key = "caron" ;
        // 要使用生成 URL 的字符
        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"

        };
        // 对传入网址进行 MD5 加密
        String sMD5EncryptResult = MD5Util.MD5(key+url);
        String hex = sMD5EncryptResult;

//        String[] resUrl = new String[4];
//        for ( int i = 0; i < 4; i++) {

            // 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
            String sTempSubString = hex.substring(2 * 8, 2 * 8 + 8);    //固定取第三组

            // 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界
            long lHexLong = 0x3FFFFFFF & Long.parseLong (sTempSubString, 16);
            String outChars = "" ;
            for ( int j = 0; j < 6; j++) {// 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引
                long index = 0x0000003D & lHexLong;
                // 把取得的字符相加
                outChars += chars[( int ) index];
                // 每次循环按位右移 5 位
                lHexLong = lHexLong >> 5;
            }// 把字符串存入对应索引的输出数组
//            resUrl[i] = outChars;
//        }
        return outChars;
    }
}

util:

package com.tips.util;import java.security.MessageDigest;public class MD5Util { // MD5加码。32位 public static String MD5(String inStr) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); return ""; } char[] charArray = inStr.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) byteArray[i] = (byte) charArray[i]; byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) hexValue.append("0"); hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } // 可逆的加密算法 public static String KL(String inStr) { // String s = new String(inStr); char[] a = inStr.toCharArray(); for (int i = 0; i < a.length; i++) { a[i] = (char) (a[i] ^ 't'); } String s = new String(a); return s; } // 加密后解密 public static String JM(String inStr) { char[] a = inStr.toCharArray(); for (int i = 0; i < a.length; i++) { a[i] = (char) (a[i] ^ 't'); } String k = new String(a); return k; } // 测试主函数 public static void main(String args[]) { String s = new String("a"); System.out.println("原始:" + s); System.out.println("MD5后:" + MD5(s)); System.out.println("MD5后再加密:" + KL(MD5(s))); System.out.println("解密为MD5后的:" + JM(KL(MD5(s)))); System.out.println("判断是否相同:" + MD5(s).equals(JM(KL(MD5(s))))); } 
} 

mapper:

<?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.tips.mapper.LinkMapper">
    <resultMap id="BaseResultMap" type="com.tips.entity.Link">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="long_url" jdbcType="VARCHAR" property="longUrl" />
        <result column="short_url" jdbcType="VARCHAR" property="shortUrl" />
    </resultMap>
    <sql id="Base_Column_List">
        id, long_url, short_url</sql>

    <!-- 根据长链接查询 -->
    <select id="findByLongUrl" parameterType="java.lang.String" resultMap="BaseResultMap">
        select<include refid="Base_Column_List" />
        from linkwhere long_url = #{longUrl,jdbcType=VARCHAR}</select>
    <!-- 根据短链接查询 -->
    <select id="findByShortUrl" parameterType="java.lang.String" resultType="java.lang.String">
        select long_url from linkwhere short_url = #{shortUrl,jdbcType=VARCHAR}</select>

    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select<include refid="Base_Column_List" />
        from linkwhere id = #{id,jdbcType=INTEGER}</select>

    <insert id="insert" parameterType="com.tips.entity.Link">
        insert into link (id, long_url, short_url)values (#{id,jdbcType=INTEGER}, #{longUrl,jdbcType=VARCHAR}, #{shortUrl,jdbcType=VARCHAR})</insert>



</mapper>

controller:

package com.tips.controller;import com.tips.entity.Link;
import com.tips.service.LinkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class LinkController {@Autowiredprivate LinkService linkService;/*** 生成短链接* @param url* @return Caron*/@RequestMapping("/api")@ResponseBodypublic Object save(String url){if (url == null || "".equals(url)){return null;}if(url.startsWith("http://") || url.startsWith("https://")){Link link = new Link();link.setLongUrl(url);return  linkService.save(link);}else{return "网址必须以http或https开头";}}/*** 301跳转* @param url* @return*/@RequestMapping("/{url}")public String restoreUrl(@PathVariable("url") String url){String restoreUrl = linkService.restoreUrl("http://cni.tips/"+url);if(restoreUrl != null && !"".equals(restoreUrl)){return "redirect:"+restoreUrl;}else{return "redirect:http://www.cnilink.com";
//            return  "forward:/404.html";    //如果要访问本地html,@RequestMapping("/{url}")前面必须加一层路径/aa/{url}}}}

application.properties:


pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>tips</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>tips</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

基本所有源码都贴出来了。跑起来试一下呗


http://chatgpt.dhexx.cn/article/1T3u7LWg.shtml

相关文章

长链接与短链接

1、Http协议 1.1 HTTP协议与TCP/IP协议的关系 HTTP的长连接和短连接本质上是TCP长连接和短连接。HTTP属于应用层协议&#xff0c;在传输层使用TCP协议&#xff0c;在网络层使用IP协议。IP协议主要解决网络路由和寻址问题&#xff0c;TCP协议主要解决如何在IP层之上可靠的传递…

长连接与短链接

短链接&#xff1a;客户端每次请求成功后&#xff0c;将关闭链接 长连接&#xff1a;客户端请求成功后&#xff0c;并不会立即关闭链接&#xff0c;适用于客户端请求较为频繁的情况 ———————————————————————————————————— 1. HTTP协议与TC…

如何实现 长链接变 短 链接?

短链接&#xff0c;通俗来说&#xff0c;就是将长的 URL 网址&#xff0c;通过程序计算等方式&#xff0c;转换为简短的网址字符串。 大家经常会收到一些莫名的营销短信&#xff0c;里面有一个非常短的链接让你跳转。新浪微博因为限制字数&#xff0c;所以也会经常见到这种看着…

微信:长链接转短链接

前言 微信复制出来的链接太长&#xff0c;想转短连接如何做&#xff1f; 将一条长链接转成短链接。 主要使用场景&#xff1a; 开发者用于生成二维码的原链接&#xff08;商品、支付二维码等&#xff09;太长导致扫码速度和成功率下降&#xff0c;将原长链接通过此接口转成短…

长链接 转换成 短链接

文章目录 参考来源思路方法一方法二 参考来源 豆瓣 短链接生成的算法原理 思路 方法一 一般会想到用哈希&#xff0c;这里可以用MD5码获取哈希值&#xff0c;但时MD5生成的串挺长的&#xff0c;这类要考虑怎么把它变短。 做法如下&#xff1a; 方法二 很好想的思路&…

长链接 转短链接URL的设计思路

最烂的回答 实现一个算法&#xff0c;将长地址转成短地址。实现长和短一一对应。然后再实现它的逆运算&#xff0c;将短地址还能换算回长地址。 这个回答看起来挺完美的&#xff0c;然后候选人也会说现在时间比较短&#xff0c;如果给我时间我去找这个算法就解决问题了。但是稍…

长链接转成短链接的原理和实现详解

一、为什么要设计短链接&#xff0c;短链接有什么好处&#xff1f; 1、链接变短&#xff0c;在对内容长度有限制的平台发文&#xff0c;可编辑的文字就变多了。 比如&#xff1a;微博&#xff0c;限定了只能发 140 个字&#xff0c;如果一串长链直接怼上去&#xff0c;其他可…

长链到短链转化

文章目录 1:为什么将长链转化为短链&#xff1f;2:短链跳转的基本原理3&#xff1a;将长链转化为短链&#xff08;Hash&#xff09;3.1:hash3.1.1:hash算法的选取3.1.2hash后还是有点长3.1.3:解决hash冲突 3.2:自增序列算法 1:为什么将长链转化为短链&#xff1f; 1、链接变短…

2022年最新Python学习路线图(内附视频资料)【六张图带你掌握Python技巧】

目录 一、基础语法学习 二、制定发展方向 三、编程实践 四、资料获取 五、学习路线图​ 一、基础语法学习 Python的基础语法包括两大部分&#xff0c;其一是函数式编程部分&#xff0c;其二是面向对象编程部分。函数式部分的内容还是比较简单的&#xff0c;包括列表、函数…

零基础Python学习路线图,小白的进阶之路!

近几年Python的受欢迎程度可谓是扶摇直上&#xff0c;当然了学习的人也是愈来愈多。一些学习Python的小白在学习初期&#xff0c;总希望能够得到一份Python学习路线图&#xff0c;小编经过多方汇总为大家汇总了一份Python学习路线图。 对于一个零基础的想学习python的朋友来说…

15张超详细的Python学习路线图,纯良心分享,零基础学习宝典

这是一篇 Python 入门指南&#xff0c;针对那些没有任何编程经验&#xff0c;从零开始学习 Python 的同学。不管你学习的出发点是兴趣驱动、拓展思维&#xff0c;还是工作需要、想要转行&#xff0c;都可以用此文作为一个参考。 在这个信息爆炸的时代&#xff0c;以 “Python入…

2020最新版Python学习路线图

Python学习路线图网上有很多版本&#xff0c;前川网的这套Python学习路线图是2020最新版的&#xff0c;是根据企业招聘的要求不断更新的学习路线图&#xff0c;对之前的Pyhton学习路线图做了一些调整和改变&#xff0c;想要用Python爬虫或者深度学习人工智能的看这套Python学习…

Python 学习之路

最近在疫情静默管理期间&#xff0c;刚好有时间可以学习一下Python&#xff0c;非常幸运&#xff0c;找到一本Eric Matthes的《Python Crash Course》Python编程从入门到实践&#xff0c;好好研究一下。基础的语法就是一带而过了&#xff0c;使用的Python3.8.10版本&#xff0c…

一文讲清Python的7大学习路线(建议收藏)

现如今铺天盖地都是来自学习Python的勇士&#xff0c;Python这个编程语言中最友好的语言早已不是高不可攀的状态了。 无论是业余爱好&#xff0c;还是专职求学&#xff0c;学习Python的朋友都在依靠着自己的方法&#xff0c;勤勤恳恳的学习着&#xff0c;但是学习有方向&#x…

超全的Python学习路线图

Python是一种编程语言 完成同一个任务&#xff0c;C语言要写1000行代码&#xff0c;Java只需要写100行&#xff0c;而Python可能只要20行。用Python完成项目&#xff0c;编写的代码量更少&#xff0c;代码简短可读性强&#xff0c;团队协作开发时读别人的代码速度会非常快&…

零基础Python学习路线图

Python学习路线图先奉上&#xff1a; Python教程_完全入门 推荐视频&#xff1a;https://www.bilibili.com/video/BV1jZ4y1p7zQ Python学习路线 第一阶段Python基础与Linux数据库 掌握Python基本语法规则及变量、逻辑控制、内置数据结构、文件操作、高级函数、模块、常用标…

Python学习路线图(2021最新版)

这是我最开始学Python时的一套学习路线&#xff0c;从入门到上手。&#xff08;不敢说精通&#xff0c;哈哈~&#xff09; 一、Python基础知识、变量、数据类型 二、Python条件结构、循环结构 三、Python函数 四、字符串 五、列表与元组 六、字典与集合 最后再送给大家一套免费…

python学习路线-思维导图

文章目录 1. python学习大纲2. python基础大纲2.1 python语言基础2.2 标准数据类型12.3 标准类型补充2.4 标准数据类型22.5 标准数据类型32.6 条件&循环2.7 计算机基础 3. python进阶大纲3.1 进阶条件&循环3.2 函数&模块3.3 面向对象3.4 补充知识3.5 文件对象3.6 异…

熬夜怒肝,保姆级Python学习路线,起飞!

想当初女朋友编程小白零基础&#xff0c;到如今在互联网大厂做算法工作&#xff0c;就是我带她漂进Python的海洋&#xff0c;从此一去不复返~ 我给她制订的学习路线十分适合萌新&#xff0c;总共分三步&#xff1a; 看视频 作项目 啃厚书 看视频 如果是零基础&#xff0c…

正确的Python学习路线图,来了!

国庆长假余额还剩最后一天啦&#xff0c;这两天陆续有很多新的同学加我微信&#xff0c;咨询问题。想学Python&#xff0c;但是Python的图书太多太多了&#xff0c;很容易从入门到放弃&#xff0c;咨询菜鸟哥能否推荐一些图书&#xff0c;然后由浅入深的阅读。今天我们就来说一…