Spring Boot 快速实现短链接生成,从零到一完整教程
大家好,我是波特~
日常开发里,短链绝对是高频场景:短信营销、公众号分享、二维码跳转、数据统计…… 都离不开它。今天咱们不玩虚的,直接从 0 到 1用 Spring Boot 撸一个可上线的短链系统,包含数据库设计、核心算法、完整代码、性能优化,复制粘贴就能跑!
一、为什么要做短链系统?
先搞清楚需求,再写代码才不慌。
短链系统核心价值:
-
缩短长度:超长链接变精简,适配短信、微博、朋友圈字符限制
-
数据统计:按渠道生成短链,统计点击量、来源、地域、设备
-
安全可控:隐藏原始 URL,支持过期、禁用、访问限制
-
体验更好:二维码更简洁,用户更愿意点击
一句话:长链接负责业务,短链接负责传播。
二、系统整体设计
一个健壮的短链系统,必须包含这 5 块:
核心模块
-
短链生成:长 URL → 唯一短码(核心)
-
存储映射:短码 ↔ 长链接持久化
-
跳转服务:访问短码 302 重定向到原链接
-
过期 / 禁用:支持临时短链、违规下架
-
访问统计:PV、UV、来源、时间分布
关键技术选型
-
开发框架:Spring Boot
-
数据库:MySQL(持久化)
-
缓存:Redis(加速跳转、防击穿)
-
生成算法:雪花 ID + Base62
-
安全:URL 校验、黑名单、限流
三、数据库设计
先明确表结构设计思路:核心是存储“短码-长链接”的映射关系,同时记录短链的创建时间、过期时间、点击量、状态等信息,方便后续管控和统计;短码作为唯一索引,提升查询速度(跳转时需要根据短码快速查询长链接)。
短链主表:short_link
CREATE TABLE`short_link` (
`id`bigintNOT NULLw COMMENT'主键',
`short_code`varchar(11) NOTNULLCOMMENT'短链码',
`original_url`varchar(500) NOTNULLCOMMENT'原始长链接',
`expire_time` datetime DEFAULTNULLCOMMENT'过期时间',
`create_time` datetime DEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',
`click_count`intDEFAULT'0'COMMENT'点击次数',
`status`tinyintDEFAULT'1'COMMENT'1-正常 0-禁用',
PRIMARY KEY (`id`),
UNIQUEKEY`uk_short_code` (`short_code`)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='短链映射表';
-
short_code:唯一索引,跳转查询必加速 -
original_url:支持 500 长度,覆盖绝大多数链接 -
增加状态、点击量、过期时间,直接满足生产需求
四、短链生成算法:Base62
短链生成的核心的是“将长链接转换成唯一的短码”,目前主流有两种方案,咱们先对比分析,再选择最适合实战的方案:
1、哈希算法:对长链接进行哈希运算,得到固定长度的哈希值,再截取前几位作为短码。优点是实现简单,无需依赖数据库;缺点是存在哈希冲突(不同长链接可能生成相同短码),需要额外处理冲突(比如重试、拼接随机数),适合对唯一性要求不高的场景。
2、雪花 ID + Base62:无冲突、长度短、性能高。使用雪花 ID 后,短链(short_code)最大长度为 11 位。本文示例直接用方案 2。
Base62 是什么?
Base62 使用 [0-9][a-z][A-Z] 共 62 个字符编码,可生成短而唯一的字符串
Base62工具类
public class Base62Util {
privatestaticfinal String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
privatestaticfinalint SCALE = 62;
// 数字 → Base62字符串
public static String encode(long num) {
StringBuilder sb = new StringBuilder();
while (num > 0) {
int idx = (int) (num % SCALE);
sb.append(CHARS.charAt(idx));
num = num / SCALE;
}
return sb.reverse().toString();
}
}
五、Spring Boot 完整代码实现
1、pom.xml文件中的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
application.yml配置文件:
spring:
datasource:
url:jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false
username:root
password:pottercoding
jpa:
hibernate:
ddl-auto:update
show-sql:true
2、实体类
@Data
@Entity
@Table(name = "short_link")
publicclass ShortLink {
@Id
private Long id;
@Column(unique = true, nullable = false, length = 10)
private String shortCode;
@Column(nullable = false, length = 500)
private String originalUrl;
private LocalDateTime expireTime;
private LocalDateTime createTime = LocalDateTime.now();
private Integer clickCount = 0;
private Integer status = 1;
}
3、DAO 层
public interface ShortLinkRepository extends JpaRepository<ShortLink, Long> {
// 根据短码查询
ShortLink findByShortCode(String shortCode);
}
4、Service 层(核心逻辑)
@Service
@RequiredArgsConstructor
publicclass ShortLinkServiceImpl implements ShortLinkService {
privatefinal ShortLinkRepository repository;
/**
* 生成短链
*/
@Transactional
public String createShortLink(String originalUrl) {
// URL合法性校验
if (!UrlCheckUtil.isValidUrl(originalUrl)) {
thrownew RuntimeException("URL格式不合法");
}
ShortLink link = new ShortLink();
long id = IdUtil.getSnowflakeNextId();
link.setId(id);
link.setOriginalUrl(originalUrl);
// ID → Base62短码
String shortCode = Base62Util.encode(id);
link.setShortCode(shortCode);
repository.save(link);
// 返回完整短链
return"http://localhost:8080/" + shortCode;
}
/**
* 根据短码获取长链接
*/
public String getOriginalUrl(String shortCode) {
ShortLink link = repository.findByShortCode(shortCode);
if (link == null) {
thrownew RuntimeException("短链不存在");
}
if (link.getStatus() == 0) {
thrownew RuntimeException("短链已禁用");
}
if (link.getExpireTime() != null && LocalDateTime.now().isAfter(link.getExpireTime())) {
thrownew RuntimeException("短链已过期");
}
// 点击量+1(异步更优)
link.setClickCount(link.getClickCount() + 1);
repository.save(link);
return link.getOriginalUrl();
}
}
5、Controller 层
@RestController
@RequiredArgsConstructor
publicclass ShortLinkController {
privatefinal ShortLinkService shortLinkService;
/**
* 生成短链接口
*/
@PostMapping("/api/shorten")
public String shorten(@RequestParam String url) {
return shortLinkService.createShortLink(url);
}
/**
* 短链跳转
*/
@GetMapping("/{shortCode}")
public void redirect(@PathVariable String shortCode, HttpServletResponse response) throws IOException {
try {
String originalUrl = shortLinkService.getOriginalUrl(shortCode);
response.sendRedirect(originalUrl);
} catch (Exception e) {
response.getWriter().write(e.getMessage());
}
}
}
6、URL 校验工具
public class UrlCheckUtil {
private static final String REGEX = "^(https?|ftp)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
public static boolean isValidUrl(String url) {
return Pattern.matches(REGEX, url);
}
}
六、启动测试
启动项目后,调用生成接口:http://localhost:8080/api/shorten?url=https://www.pottercoding.cn,访问返回短链:http://localhost:8080/2r7p8jXzVPa,访问该短链可直接调整到我的个人网站,完美!


七、生产级优化
1、Redis 缓存加速:跳转是超高并发读,必须加 Redis:
-
短码 → 长链接缓存
-
过期时间和短链保持一致
2、布隆过滤器防缓存穿透:防止恶意请求不存在的短码打崩数据库。
3、点击量异步更新:用 @Async 或消息队列更新点击量,不影响跳转性能。
4、分布式部署:用雪花 ID替代自增 ID,支持多实例部署。
5、安全加固
-
黑名单过滤恶意 URL
-
接口限流防刷
-
短码随机打乱,避免遍历
代码地址,可直接下载运行:https://pan.baidu.com/s/19lhO7x2NCphUvkcd4swj6w?pwd=j6ux 提取码: j6ux
更多推荐




所有评论(0)