springboot 实现长链接转短链接的示例代码

 更新时间:2024年09月15日 10:18:27   作者:鹏鹏博客  
短链接服务通过将长URL转换成6位短码,并存储长短链接对应关系到数据库中,用户访问短链接时,系统通过查询数据库并重定向到原始URL,实现快速访问,本文就来介绍一下如何使用,感兴趣的可以了解一下

实现结果: 

转换短链接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的访问;(如果你的转换方式能过还原,也可以不要数据库,但必须保证转换后的短码不能重复)

实现步骤:

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
     * 查询数据库是否已经存在 如果存在就返回数据库对应的短链接,如果不存在就查询一条新纪录并返回新的短链接
     * <strong>@param </strong>link
     * <strong>@return
</strong><strong>     </strong>*/
    @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);
    }

    /**
     * <strong>@param </strong>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);
    }

    /**
     * 将长链接转换为短链接
     * <strong>@param </strong>url
     * <strong>@return
</strong><strong>     </strong>*/
    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 link
        where long_url = #{longUrl,jdbcType=VARCHAR}
    </select>
    <!-- 根据短链接查询 -->
    <select id="findByShortUrl" parameterType="java.lang.String" resultType="java.lang.String">
        select long_url from link
        where short_url = #{shortUrl,jdbcType=VARCHAR}
    </select>

    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from link
        where 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 {

    @Autowired
    private LinkService linkService;

    /**
     * 生成短链接
     * @param url
     * @return Caron
     */
    @RequestMapping("/api")
    @ResponseBody
    public 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>

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

到此这篇关于springboot 实现长链接转短链接的示例代码的文章就介绍到这了,更多相关springboot  长链接转短链接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis-Plus使用ActiveRecord(AR)实现CRUD

    MyBatis-Plus使用ActiveRecord(AR)实现CRUD

    本文将结合实例代码,介绍MyBatis-Plus使用ActiveRecord(AR)实现CRUD,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • JavaWeb servlet实现下载与上传功能的方法详解

    JavaWeb servlet实现下载与上传功能的方法详解

    这篇文章主要介绍了JavaWeb servlet实现下载与上传功能的方法,结合实例形式详细分析了JavaWeb servlet实现下载与上传功能的原理、实现方法与操作注意事项,需要的朋友可以参考下
    2020-04-04
  • Java中字符串转时间与时间转字符串的操作详解

    Java中字符串转时间与时间转字符串的操作详解

    Java 的 java.time 包提供了强大的日期和时间处理功能,通过 DateTimeFormatter 可以轻松地在日期时间对象和字符串之间进行转换,下面小编给大家详细介绍一下Java中字符串转时间与时间转字符串的操作,需要的朋友可以参考下
    2025-04-04
  • SpringBoot最简单的定时任务@Scheduler的使用及解读

    SpringBoot最简单的定时任务@Scheduler的使用及解读

    这篇文章主要介绍了SpringBoot最简单的定时任务@Scheduler的使用及解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-03-03
  • Java设置Excel页面的配置指南

    Java设置Excel页面的配置指南

    本指南将深入探讨如何在Java代码中精细化控制Excel的页面设置,帮助你告别打印噩梦,轻松打造出媲美手动操作的专业级报表,快跟随小编一起学习一下吧
    2025-10-10
  • java代理模式(jdk proxy)

    java代理模式(jdk proxy)

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;这篇文章主要介绍了Java 中的三种代理模式,需要的朋友可以参考下,希望能帮助到你
    2021-07-07
  • springboot中配置logback-spring.xml的方法

    springboot中配置logback-spring.xml的方法

    文章介绍了如何在SpringBoot项目中配置logback-spring.xml文件来进行日志管理,包括如何定义日志输出方式、日志级别以及如何根据不同的环境配置不同的日志格式,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • SpringMvc中容器加载的过程源码详解

    SpringMvc中容器加载的过程源码详解

    这篇文章主要介绍了SpringMvc中容器加载的过程源码详解,springmvc是基于spring的一个web层框架,同样也是web层框架的有struts,struts2等等,但是struts因为漏洞等问题,被慢慢淘汰了,现在基本都在用springmvc,需要的朋友可以参考下
    2023-11-11
  • java报错之springboot3+vue2项目web服务层报错总结

    java报错之springboot3+vue2项目web服务层报错总结

    java入门学习,随手记录一下开发过程中产生的报错,有些错误是网上搜索再加上自己尝试,随手引用了一些其他人的记录,也是留给自己看的,或是希望能对其他初学者有帮助

    2023-06-06
  • Java查看和修改线程优先级操作详解

    Java查看和修改线程优先级操作详解

    JAVA中每个线程都有优化级属性,默认情况下,新建的线程和创建该线程的线程优先级是一样的。本文将为大家详解Java查看和修改线程优先级操作的方法,需要的可以参考一下
    2022-08-08

最新评论