首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現短鏈接服務 (基於 Hashids 對稱加密)

     編輯:Java 相關知識

本文介紹如何使用 Java 實現短鏈接服務,核心採用 Hashids 庫進行對稱加密,將數據庫自增 ID 加密為短字符串,避免暴露業務規律。基於 Blade 輕量框架演示完整流程:數據庫設計、路由控制器、編解碼邏輯、URL 校驗。

為什麼需要短鏈接?

原始 URL 暴露自增 ID:


https://example.com/video/1
https://example.com/video/2
https://example.com/video/3

風險:爬蟲易遍歷、業務量洩露、安全隱患。短鏈接加密後:


https://short.ly/aB3dE9
https://short.ly/xY7kL2
https://short.ly/mN4pQ8

技術選型:Hashids

  • 對稱加密:雙向可逆,無需存儲映射表
  • 多語言支援:Java、JS、Python、PHP、Go 等
  • 可配置:鹽值、最小長度、字符集、分隔符
  • 無依賴、輕量、高性能

Maven 依賴:


<dependency>
    <groupId>org.hashids</groupId>
    <artifactId>hashids</artifactId>
    <version>1.0.3</version>
</dependency>

數據庫設計


CREATE TABLE `t_short_url` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `long_url` TEXT NOT NULL,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

完整控制器實現 (Blade 框架風格)


import com.blade.kit.Hashids;
import com.blade.kit.StringKit;
import com.blade.mvc.annotation.Path;
import com.blade.mvc.annotation.Route;
import com.blade.mvc.http.HttpMethod;
import com.blade.mvc.http.Request;
import com.blade.mvc.http.Response;
import com.blade.mvc.ui.RestResponse;

import java.util.regex.Pattern;

@Path
public class ShortUrlController {

    // 鹽值:項目級機密,防止碰撞與逆向
    private static final Hashids HASHIDS = new Hashids("my-project-salt-xyz", 6);
    
    // 簡單內存模型,實際替換為 ORM (MyBatis/JPA/ActiveRecord)
    private final UrlModel urlModel = new UrlModel();
    
    // URL 正則校驗
    private static final Pattern URL_PATTERN = Pattern.compile(
        "^(https?|ftp)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]$"
    );

    /**
     * 短鏈接跳轉:/abc123 → 解碼 ID → 查詢長鏈接 → 302 重定向
     */
    @Route("/:key")
    public void redirect(Request request, Response response) {
        String key = request.pathParam(":key").replaceAll("[^A-Za-z0-9]", "");
        
        long[] numbers = HASHIDS.decode(key);
        if (numbers == null || numbers.length == 0) {
            response.text("短鏈接不存在");
            return;
        }
        
        int id = (int) numbers[0];
        UrlModel url = urlModel.findById(id);
        if (url == null || url.getLongUrl() == null) {
            response.text("短鏈接不存在");
            return;
        }
        
        response.redirect(url.getLongUrl());
    }

    /**
     * 首頁:顯示創建表單
     */
    @Route(value = "/", method = HttpMethod.GET)
    public String index() {
        return "index.html";  // 模板頁面
    }

    /**
     * 創建短鏈接:POST / → 驗證 URL → 存儲 → 編碼 ID → 返回短碼
     */
    @Route(value = "/", method = HttpMethod.POST)
    public String create(Request request, Response response) {
        String longUrl = request.query("url");
        
        // 1. URL 格式校驗
        if (!isValidUrl(longUrl)) {
            request.attribute("error", "請輸入有效的 URL (以 https:// 或 https:// 開頭)");
            return "index.html";
        }
        
        // 2. 存儲長鏈接,獲取自增 ID
        Integer id = urlModel.insert().param("long_url", longUrl).executeAndCommit();
        if (id == null || id == 0) {
            request.attribute("error", "創建失敗,請重試");
            return "index.html";
        }
        
        // 3. Hashids 編碼 ID → 短碼
        String hash = HASHIDS.encode(id);
        
        // 4. 返回結果 (模板顯示)
        request.attribute("short_code", hash);
        request.attribute("short_url", request.uri() + hash);
        request.attribute("long_url", longUrl);
        
        return "index.html";
    }

    private boolean isValidUrl(String url) {
        return StringKit.isNotBlank(url) && URL_PATTERN.matcher(url).find();
    }
}

UrlModel 簡單實現 (ActiveRecord 風格)


public class UrlModel {
    private Integer id;
    private String longUrl;
    private Timestamp createdAt;
    
    // 查詢
    public UrlModel findById(int id) {
        // 實際: SELECT * FROM t_short_url WHERE id = ?
        return new UrlModel(); // 模擬
    }
    
    // 插入
    public ActiveRecordBuilder insert() {
        return new ActiveRecordBuilder(this);
    }
    
    // 內部構建器
    public static class ActiveRecordBuilder {
        private UrlModel model;
        public ActiveRecordBuilder(UrlModel m) { this.model = m; }
        public ActiveRecordBuilder param(String key, Object val) { 
            if ("long_url".equals(key)) model.longUrl = (String) val;
            return this; 
        }
        public Integer executeAndCommit() {
            // 實際: INSERT INTO t_short_url (long_url) VALUES (?)
            // 返回自增 ID
            model.id = 12345; // 模擬
            return model.id;
        }
    }
    
    // Getters/Setters
    public Integer getId() { return id; }
    public String getLongUrl() { return longUrl; }
}

前端頁面示例 (index.html)





    短鏈接生成器
    
    


    

短鏈接生成器

#if(error)
${error}
#end
#if(short_code)
生成成功!
原始鏈接: ${long_url}
短鏈接: ${short_url}
短碼: ${short_code}
#end

Hashids 核心參數配置


// 構造函數完整簽名
public Hashids(String salt)                           // 默認最小長度 0, 默認字符集
public Hashids(String salt, int minHashLength)        // 指定最小長度
public Hashids(String salt, int minHashLength, String alphabet) // 自定義字符集

// 常用配置示例
Hashids h1 = new Hashids("salt");           // 默認
Hashids h2 = new Hashids("salt", 6);        // 最短 6 字符
Hashids h3 = new Hashids("salt", 8, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); // 自定義字符集

編解碼示例


Hashids hashids = new Hashids("my-salt", 6);

// 編碼單個 ID
String encoded = hashids.encode(12345);        // "jR7x9A"
String encoded2 = hashids.encode(1, 2, 3);     // 支援多數字編碼

// 解碼
long[] decoded = hashids.decode("jR7x9A");     // [12345]
long[] decoded2 = hashids.decode(encoded2);    // [1, 2, 3]

// 編碼十六進制
String hexEncoded = hashids.encodeHex("507f1f77bcf86cd799439011"); // 支援 MongoDB ObjectId
String hexDecoded = hashids.decodeHex(hexEncoded);

生產環境擴展建議

總結

Hashids 通過對稱加密將數字 ID 轉為短字符串,實現了「無狀態、可逆、無映射表」的短鏈接服務。核心優勢在於簡單高效,配合 Blade/Spring Boot 等框架可快速構建生產可用的短鏈接系統。關鍵注意:鹽值必須保密且穩定,一旦更改所有歷史短鏈接將失效。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
需求解決方案
高併發寫入Redis 預生成 ID 段 + 異步寫入 DB
訪問統計Redis 計數器 + 定時持久化
自定義短碼用戶提交 alias,唯一性檢查後存儲
過期/失效表添加 expire_at,定時任務清理
防惡意刷短IP 限流、驗證碼、登錄才能創建
分佈式部署統一鹽值配置中心、DB 主從/分庫分表
監控告警Prometheus 監控 QPS、延遲、錯誤率