Skip to content
forked from Alkaids/shortcut

又一个轮子,短网址转换工具。基于 twitter 的雪花算法,给新增的转换请求发号,得到短地址,并生成二维码。

License

Notifications You must be signed in to change notification settings

RipperTs/shortcut

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


Shortcut

基于 Spring Boot 的高性能短地址生成服务,使用 Twitter 雪花算法生成唯一短地址,支持密码保护、二维码生成和过期时间设置。


GitHub GitHub code size in bytes Java Version Spring Boot

环境要求

  • Java: 8+
  • Maven: 3.0+
  • Redis: 4.0+

快速开始

1. 克隆项目

git clone https://github.com/RipperTs/shortcut.git
cd shortcut

2. 配置 Redis

修改 src/main/resources/application.yml 中的 Redis 配置:

spring:
  redis:
    host: your-redis-host
    port: 6379
    password: your-redis-password

3. 构建运行

# 跳过测试构建
mvn -Dmaven.test.skip=true clean package

# 运行应用
java -jar target/shortcut-0.0.1-SNAPSHOT.jar

# 或直接 Maven 运行
mvn spring-boot:run

4. 访问服务

5. 主页面

main.png

功能特性

✅ 已实现功能

  • 🔗 短地址生成: 基于雪花算法的高性能短地址生成
  • 🔒 密码保护: 支持为URL转换设置密码验证
  • 📱 二维码生成: 自动生成对应的二维码图片
  • 🔍 布隆过滤器: 高效判断URL是否已存在
  • 🌐 自定义域名: 支持配置自定义短地址域名
  • 🎨 Web界面: 现代化的前端界面,支持加载指示器
  • 🔄 反向查询: 支持通过短地址查询原始URL
  • 🌍 跨域支持: 内置CORS配置,支持跨域请求
  • 📄 错误处理: 自定义404错误页面和全局异常处理
  • 高性能: QPS 可达 4000+
  • 🛡️ 异常处理: 全局异常拦截和处理
  • ✔️ URL校验: 完善的URL格式验证
  • 🗂️ 缓存配置: 支持自定义Redis缓存前缀
  • 过期时间设置: 支持为短地址设置自定义过期时间,使用Redis TTL机制自动清理

🚧 计划功能

  • 令牌桶限流
  • URL访问统计
  • 批量URL转换

配置说明

基础配置

# 服务端口
server:
  port: 9527

# 自定义域名配置
common:
  domain: http://your-domain.com

安全配置

# 密码保护配置
security:
  passwords: 
    - admin123      # 支持多个密码
    - convert2024

缓存配置

# Redis缓存配置
cache:
  prefix: shortcut_  # 缓存key前缀

架构设计

核心原理

参考知乎上这篇文章的短地址生成方法,主要包含两个步骤:

  1. 实现唯一ID发号器 - 使用Twitter雪花算法生成不重复的Long型ID
  2. 进制转换 - 将Long型ID转换为62进制字符串作为短地址

雪花算法结构

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 
  • 1位符号位: 固定为0(正数)
  • 41位时间戳: 毫秒级时间戳,可使用69年
  • 10位机器标识: 支持1024个节点部署
  • 12位序列号: 同一毫秒内可生成4096个ID

核心组件

控制器层

  • MainController: URL转换、二维码生成、密码验证
  • RedirectController: 短地址重定向
  • IndexController: 前端页面渲染

服务层

  • UrlConvertService: URL转换核心服务接口
  • UrlConvertServiceImpl: 服务实现,集成布隆过滤器和Redis存储

工具类

  • SnowFlake: Twitter雪花算法实现
  • NumericConvertUtils: 62进制转换工具
  • QRcodeUtils: 基于ZXing的二维码生成工具
  • Validator: URL格式校验工具
  • BloomFilter: 布隆过滤器实现

配置类

  • SecurityProperties: 密码验证配置
  • CacheProperties: Redis缓存前缀配置
  • RedisConfiguration: Redis连接配置

处理流程

  1. URL转换流程:

    用户提交base64编码URL → 密码验证 → base64解码 → URL格式校验 
    → 布隆过滤器判重 → 雪花算法生成ID → 62进制转换 
    → Redis存储映射 → 返回短地址
    
  2. 短地址访问流程:

    访问短地址 → 解析短码 → Redis查询编码URL → base64解码 → 302重定向
    
  3. 二维码生成:

    接收URL参数 → 使用ZXing生成二维码 → 返回图片流
    

数据存储

  • Redis存储结构: {prefix}{shortCode} → base64EncodedUrl
  • 布隆过滤器: 基于base64编码URL快速判断是否已存在,减少Redis查询
  • 编码机制: 存储时使用base64编码,访问时自动解码

API 接口

1. URL转换

POST /convert
Content-Type: application/json

{
  "url": "aHR0cHM6Ly9leGFtcGxlLmNvbQ==",
  "password": "admin123",
  "expireTime": 3600
}

参数说明:

  • url: 必填,经过 base64编码 的URL字符串
  • password: 选填,转换密码(如果系统启用了密码保护)
  • expireTime: 选填,过期时间(秒),最小值10秒

编码示例:

// 原始URL: https://example.com
// Base64编码后: aHR0cHM6Ly9leGFtcGxlLmNvbQ==
const originalUrl = "https://example.com";
const encodedUrl = btoa(encodeURIComponent(originalUrl));

2. 短地址反查

POST /revert
Content-Type: application/json

{
  "shortUrl": "7TDp0rS917i"
}

返回: 解码后的原始URL

3. 二维码生成

GET /qrcode?url=https://example.com

注意: 二维码接口可以直接使用原始URL,无需base64编码。

4. 检查密码验证状态

GET /password-enabled

返回: {"code":200,"message":"SUCCESS","data":true}

测试配置

Options options = new OptionsBuilder()
    .include(BenchmarkTest.class.getName() + ".*")
    .warmupIterations(1)        // 预热轮数
    .warmupTime(TimeValue.seconds(1))
    .measurementIterations(5)   // 测试轮数
    .measurementTime(TimeValue.seconds(5))
    .forks(1)                   // 进程数
    .threads(16)                // 线程数
    .build();

测试结果

Benchmark                      Mode  Cnt    Score    Error  Units
BenchmarkTest.httprequest     thrpt    5  1948.349 ± 2028.032  ops/s
BenchmarkTest.serviceRequest  thrpt    5  3945.100 ± 1185.980  ops/s
  • HTTP请求: QPS约2000,通过OkHttp发送POST请求测试
  • 服务直调: QPS约4000,直接调用服务方法测试

优化建议

  • 进制转换部分存在不必要的类型转换,可进一步优化
  • 可考虑使用连接池优化Redis连接
  • 布隆过滤器参数可根据实际数据量调优

部署说明

Docker 部署

方式一:Docker Compose(推荐)

前提条件:确保已构建好 jar 文件

mvn -Dmaven.test.skip=true clean package

使用 docker-compose 一键部署

# 启动服务(包含应用和Redis)
docker-compose up -d

# 查看日志
docker-compose logs -f

# 停止服务
docker-compose down

docker-compose.yml 配置

version: '3.8'

services:
  redis:
    image: registry.cn-hangzhou.aliyuncs.com/ripper/redis:7-alpine
    container_name: shortcut-redis
    restart: unless-stopped
    command: redis-server --requirepass 123456
    volumes:
      - ./redis-data:/data
    networks:
      - shortcut-network

  shortcut:
    image: registry.cn-hangzhou.aliyuncs.com/ripper/shortcut:latest
    container_name: shortcut-app
    restart: unless-stopped
    ports:
      - "9527:9527"
    environment:
      # Redis配置
      - SPRING_REDIS_HOST=redis
      - SPRING_REDIS_PORT=6379
      - SPRING_REDIS_PASSWORD=123456
      # 服务配置
      - SERVER_PORT=9527
      - COMMON_DOMAIN=http://localhost:9527
      # 缓存配置
      - CACHE_PREFIX=shortcut_
      # 安全配置
      - SECURITY_PASSWORDS[0]=admin123
      - SECURITY_PASSWORDS[1]=convert2024
    depends_on:
      - redis
    networks:
      - shortcut-network

networks:
  shortcut-network:
    driver: bridge

环境变量配置说明

  • 所有 application.yml 中的配置都可通过环境变量覆盖
  • 转换规则:spring.redis.hostSPRING_REDIS_HOST
  • 数组配置:security.passwords[0]SECURITY_PASSWORDS[0]

方式二:单独构建镜像

Dockerfile

FROM registry.cn-hangzhou.aliyuncs.com/ripper/openjdk:8-jdk-alpine
WORKDIR /app
COPY target/shortcut-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 9527
ENTRYPOINT ["java", "-jar", "app.jar"]

构建和运行

# 构建镜像
docker build -t shortcut:latest .

# 运行容器(需要外部Redis)
docker run -p 9527:9527 \
  -e SPRING_REDIS_HOST=your-redis-host \
  -e SPRING_REDIS_PASSWORD=your-redis-password \
  shortcut:latest

生产环境配置

# 生产环境建议配置
server:
  port: 80
  
spring:
  redis:
    host: redis-server
    port: 6379
    password: ${REDIS_PASSWORD}
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
        min-idle: 5

common:
  domain: https://your-domain.com

security:
  passwords: 
    - ${CONVERT_PASSWORD}

cache:
  prefix: prod_shortcut_

致谢

感谢以下开源项目和资源:

许可证

本项目基于 MIT License 开源。


更新日志

v2.2.0 (最新)

  • 新增过期时间功能: 支持为短地址设置自定义过期时间
  • 🔧 API增强: /convert 接口新增 expireTime 参数
  • 🎨 UI优化: 前端页面增加过期时间输入框,支持时钟图标和友好提示
  • 🛡️ 逻辑优化: 修复布隆过滤器与过期key的处理逻辑
  • 性能提升: 过期数据使用Redis TTL机制自动清理

v2.1.0

  • ✨ 新增CORS跨域支持
  • ✨ 新增自定义404错误页面
  • 🔧 重构API接口,统一使用JSON请求体
  • 🎨 完善全局异常处理机制
  • 🔒 移除删除功能,提升安全性

v2.0.0

  • ✨ 新增密码保护功能
  • ✨ 新增短地址反向查询接口
  • ✨ 新增缓存前缀配置
  • 🎨 优化Web界面,增加加载指示器
  • 🔧 完善配置项和异常处理

v1.0.0

  • 🎉 基础短地址生成功能
  • 🎉 二维码生成功能
  • 🎉 布隆过滤器优化
  • 🎉 性能基准测试

About

又一个轮子,短网址转换工具。基于 twitter 的雪花算法,给新增的转换请求发号,得到短地址,并生成二维码。

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 56.1%
  • CSS 15.0%
  • JavaScript 14.8%
  • HTML 13.8%
  • Dockerfile 0.3%