springboot 實現(xiàn)長鏈接轉(zhuǎn)短鏈接的示例代碼
實現(xiàn)結(jié)果:
轉(zhuǎn)換短鏈接api:
接口:http://127.0.0.1/api?url=urlencode('要縮短的網(wǎng)址')
例如:http://127.0.0.1/api?url=http%3a%2f%2fwww.baidu.com
返回:http://127.0.0.1/baidu
訪問短鏈接即可還原原url;
轉(zhuǎn)換原理: 將原url通過一系列方式,轉(zhuǎn)換成6位短碼(只要能不重復,隨便怎么方式都行);將長短鏈接存入數(shù)據(jù)庫,形成一條對應關系;訪問短鏈接的時候,在數(shù)據(jù)庫找到對應的長鏈接,并通過重定向?qū)崿F(xiàn)原url的訪問;(如果你的轉(zhuǎn)換方式能過還原,也可以不要數(shù)據(jù)庫,但必須保證轉(zhuǎn)換后的短碼不能重復)
實現(xiàn)步驟:
1.創(chuàng)建數(shù)據(jù)庫(shorturl),創(chuàng)建一個表,存儲長鏈接和與之對應的短鏈接;
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項目,搭建方式網(wǎng)上很多,自行查找;下圖是項目構(gòu)建完成的項目結(jié)構(gòu)(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; /** * 轉(zhuǎn)化url * 查詢數(shù)據(jù)庫是否已經(jīng)存在 如果存在就返回數(shù)據(jù)庫對應的短鏈接,如果不存在就查詢一條新紀錄并返回新的短鏈接 * <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); // 打印出結(jié)果 System.out.println("短鏈接為: "+ result); } /** * 將長鏈接轉(zhuǎn)換為短鏈接 * <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" }; // 對傳入網(wǎng)址進行 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 型來轉(zhuǎn)換,因為 Inteper .parseInt() 只能處理 31 位 , 首位為符號位 , 如果不用 long ,則會越界 long lHexLong = 0x3FFFFFFF & Long.parseLong (sTempSubString, 16); String outChars = "" ; for ( int j = 0; j < 6; j++) { // 把得到的值與 0x0000003D 進行位與運算,取得字符數(shù)組 chars 索引 long index = 0x0000003D & lHexLong; // 把取得的字符相加 outChars += chars[( int ) index]; // 每次循環(huán)按位右移 5 位 lHexLong = lHexLong >> 5; } // 把字符串存入對應索引的輸出數(shù)組 // 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; } // 測試主函數(shù) 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> <!-- 根據(jù)長鏈接查詢 --> <select id="findByLongUrl" parameterType="java.lang.String" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from link where long_url = #{longUrl,jdbcType=VARCHAR} </select> <!-- 根據(jù)短鏈接查詢 --> <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 "網(wǎng)址必須以http或https開頭"; } } /** * 301跳轉(zhuǎn) * @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 實現(xiàn)長鏈接轉(zhuǎn)短鏈接的示例代碼的文章就介紹到這了,更多相關springboot 長鏈接轉(zhuǎn)短鏈接內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java通過notify和wait實現(xiàn)線程間的通信功能
在軟件開發(fā)中,線程是實現(xiàn)并發(fā)執(zhí)行的重要手段,然而,線程之間的協(xié)作與通信卻是開發(fā)者必須重點考慮的挑戰(zhàn)之一,Java作為一種廣泛應用于多線程編程的語言,本文將深入探討Java中通過notify和wait實現(xiàn)線程間通信的機制,需要的朋友可以參考下2024-06-06Java CountDownLatch與CyclicBarrier及Semaphore使用教程
對于并發(fā)執(zhí)行,Java中的CountDownLatch是一個重要的類。為了更好的理解CountDownLatch這個類,本文將通過例子和源碼帶領大家深入解析CountDownLatch與CyclicBarrier及Semaphore的原理,感興趣的可以學習一下2023-01-01mybatis中如何實現(xiàn)一個標簽執(zhí)行多個sql語句
這篇文章主要介紹了mybatis中如何實現(xiàn)一個標簽執(zhí)行多個sql語句問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04Java中system.exit(0) 和 system.exit(1)區(qū)別
本文主要介紹了Java中system.exit(0) 和 system.exit(1)區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-05-05什么是 Java 的 CyclicBarrier(代碼示例)
CyclicBarrier 是多線程協(xié)同的利器,適合需要多次同步的場景,本文通過代碼示例講解什么是 Java 的 CyclicBarrier,感興趣的朋友一起看看吧2025-03-03