SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn)
1.背景介紹
短鏈跳轉(zhuǎn)是一種通過將長鏈接轉(zhuǎn)換為短鏈接的方式,以便在互聯(lián)網(wǎng)上進(jìn)行鏈接共享和傳播的技術(shù)。通常情況下,長鏈接可能由于包含大量參數(shù)或者較長的路徑而顯得復(fù)雜且不易記憶,而短鏈則是將原始長鏈接通過特定算法轉(zhuǎn)換為較短的鏈接,使得它更容易分享、傳播和展示。
短鏈跳轉(zhuǎn)服務(wù)通常由第三方提供,用戶可以將需要縮短的長鏈接提交到該服務(wù),服務(wù)會返回一個短鏈接,當(dāng)用戶訪問這個短鏈接時,會被重定向到原始的長鏈接地址。這種服務(wù)通常還提供了統(tǒng)計功能,可以跟蹤短鏈接被點(diǎn)擊的次數(shù)、訪問來源等信息,幫助用戶了解鏈接的傳播效果。
短鏈跳轉(zhuǎn)服務(wù)有助于美化鏈接、節(jié)省空間、方便分享和統(tǒng)計鏈接訪問情況,因此被廣泛應(yīng)用于社交媒體、微博客、推廣活動等各種互聯(lián)網(wǎng)應(yīng)用場景中。
比如在b站中,一個視頻的網(wǎng)址原來是這樣的:
在移動端中,點(diǎn)擊分享按鈕,復(fù)制其鏈接:
它會變成如下鏈接形式:
【Cookie、Session、Token、JWT一次性講完-嗶哩嗶哩】 https://b23.tv/0SMtYq6
點(diǎn)擊該鏈接后,你會發(fā)現(xiàn)瀏覽器的網(wǎng)址URL為原來的長鏈接形式,也就是說這其中發(fā)生了重定向 ,而這個過程就是這篇博客要提到的短鏈跳轉(zhuǎn)了。
2.短鏈跳轉(zhuǎn)的意義
- 節(jié)省空間:長鏈接可能會很長,不方便分享或展示,通過短鏈跳轉(zhuǎn)可以將長鏈接轉(zhuǎn)換為短鏈接,節(jié)省字符空間。
- 美化鏈接:短鏈看起來更簡潔、美觀,對于需要展示給用戶或發(fā)布到社交媒體等場景更具吸引力。
- 防止鏈接失效:某些長鏈接可能會因?yàn)檫^期、失效或變動而無法訪問,通過短鏈跳轉(zhuǎn)可以在后臺進(jìn)行管理和更新,保證鏈接的可訪問性。
- 統(tǒng)計和跟蹤:通過短鏈跳轉(zhuǎn)服務(wù)可以對鏈接的點(diǎn)擊量、來源、地域等信息進(jìn)行統(tǒng)計和分析,幫助用戶了解鏈接的受眾和效果。
- 方便分享:短鏈更容易復(fù)制、粘貼和分享,適用于短信、微博、郵件等分享場景,提高分享效率。
- 隱藏原始鏈接:有時候希望隱藏原始鏈接的信息,通過短鏈跳轉(zhuǎn)可以起到一定的保護(hù)作用,防止泄露敏感信息。
3.SpringBoot中的代碼實(shí)現(xiàn)
這里我們以快速入門為主,即主要實(shí)現(xiàn)長鏈到短鏈的映射邏輯。
1.建議短鏈-長鏈的數(shù)據(jù)庫表:t_url_map:
2.映射實(shí)體
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層實(shí)現(xiàn)
這里簡單寫三個關(guān)鍵的接口方法:根據(jù)長鏈找短鏈(若無則生成短鏈)、根據(jù)短鏈找長鏈(若無則跳轉(zhuǎn)失敗頁面)、插入實(shí)體
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); }
對應(yīng)的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層實(shí)現(xiàn)
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); // 看看該長鏈接是否存在 // 如果存在并且其對應(yīng)用戶名等于已有用戶名,則直接給出短鏈接 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){ // 根據(jù)短鏈接獲取長鏈接 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進(jìn)行MD5哈希計算 StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { sb.append(String.format("%02x", b)); // 將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串 } return sb.toString().substring(0, 8)+username; // 截取前8位,加上用戶名(這里先簡單默認(rèn)用戶名是4位數(shù)) } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } }
5.Controller層實(shí)現(xiàn)
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") // 長鏈接轉(zhuǎn)短連接,相當(dāng)于實(shí)際項(xiàng)目中的點(diǎn)擊“分享”,形成一條短連接 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); } }
相關(guān)的ResponseBean的返回結(jié)果集代碼:
public class ResponseBean<T> { /** 200:操作成功 -1:操作失敗**/ // http 狀態(tài)碼 private boolean success; // 返回的數(shù)據(jù) 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; } }
4.結(jié)果測試
我們就拿剛剛那個b站的長鏈接作測試,即https://www.bilibili.com/video/BV18u4m1K7D4/?spm_id_from=333.1007.tianma.10-4-38.click&vd_source=1c7e32cfbc70017a24ee2c337620ff51
可以看到短鏈接生成為1b9590bezhan,
然后我們再用這條鏈接去測試能否跳轉(zhuǎn)到原始鏈接:
成功根據(jù)短鏈接定向到原始鏈接的網(wǎng)站了。
5.問題
1.為什么生成短鏈接需要帶上username參數(shù)?
答:這里其實(shí)模仿的是不同用戶對應(yīng)同一個原始鏈接(或長鏈接)時,確保他們生成的短鏈接各不相同,這樣可以方便后臺追蹤是由哪個用戶分享的短鏈接,進(jìn)而統(tǒng)計分享數(shù)。在表中LongUrl和shortUrl的對應(yīng)關(guān)系為一對多
以上就是SpringBoot短鏈接跳轉(zhuǎn)的代碼實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot短鏈接跳轉(zhuǎn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring簡單MVC實(shí)現(xiàn)方法(URL映射及其參數(shù)使用、查詢(id、其他參數(shù))、增加)
這篇文章主要介紹了spring簡單MVC實(shí)現(xiàn)方法(URL映射及其參數(shù)使用、查詢(id、其他參數(shù))、增加),方法參數(shù)使用包括在無注解下獲取參數(shù),使用@RequestParam 獲取參數(shù)的方法,每種方法講解的非常詳細(xì),需要的朋友可以參考下2024-01-01jboss( WildFly)上運(yùn)行 springboot程序的步驟詳解
這篇文章主要介紹了jboss( WildFly)上運(yùn)行 springboot程序的步驟詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02Java 中組合模型之對象結(jié)構(gòu)模式的詳解
這篇文章主要介紹了Java 中組合模型之對象結(jié)構(gòu)模式的詳解的相關(guān)資料,希望通過本文能幫助到大家理解應(yīng)用對象結(jié)構(gòu)模型,需要的朋友可以參考下2017-09-09MyBatis-Plus模糊查詢特殊字符串轉(zhuǎn)義的實(shí)現(xiàn)
使用MyBatis中的模糊查詢時,當(dāng)查詢關(guān)鍵字中包括有_、\、%時,查詢關(guān)鍵字失效,本文主要介紹了MyBatis-Plus模糊查詢特殊字符串轉(zhuǎn)義的實(shí)現(xiàn),感興趣的可以了解一下2024-06-06Java Swing BoxLayout箱式布局的實(shí)現(xiàn)代碼
這篇文章主要介紹了Java Swing BoxLayout箱式布局的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12