{"id":29631058,"url":"https://github.com/llllllxy/tiny-url","last_synced_at":"2025-10-03T17:07:27.894Z","repository":{"id":225799602,"uuid":"766844574","full_name":"llllllxy/tiny-url","owner":"llllllxy","description":"📚tiny-turl 是一个基于 SpringBoot3 +Java17 开发的在线短链生成系统，支持Sass多租户模式管理，支持rest api远程调用生成短链，以及短链访问日志，访问量统计等数据分析功能。","archived":false,"fork":false,"pushed_at":"2025-06-27T03:38:44.000Z","size":4785,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-21T11:15:41.455Z","etag":null,"topics":["java","mysql","redis","springboot","url-shortener"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/llllllxy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-04T08:31:52.000Z","updated_at":"2025-07-04T00:34:27.000Z","dependencies_parsed_at":"2024-04-17T13:27:05.385Z","dependency_job_id":"ed4044e6-377b-4c83-a5e5-f116b4be36b9","html_url":"https://github.com/llllllxy/tiny-url","commit_stats":null,"previous_names":["llllllxy/tiny-url"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/llllllxy/tiny-url","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-url","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-url/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-url/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-url/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/llllllxy","download_url":"https://codeload.github.com/llllllxy/tiny-url/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/llllllxy%2Ftiny-url/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278196448,"owners_count":25946326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-03T02:00:06.070Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","mysql","redis","springboot","url-shortener"],"created_at":"2025-07-21T11:08:06.207Z","updated_at":"2025-10-03T17:07:27.877Z","avatar_url":"https://github.com/llllllxy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tiny-url\r\n# 在线短链接生成平台\r\n\r\n![SpringBoot](https://img.shields.io/badge/springboot-3.1.9-green.svg?style=flat-square)\r\n\u003ca href=\"https://github.com/llllllxy/tiny-url/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/llllllxy/tiny-url?style=flat-square\u0026logo=GitHub\"\u003e\u003c/a\u003e\r\n\u003ca href=\"https://github.com/llllllxy/tiny-url/network/members\"\u003e\u003cimg src=\"https://img.shields.io/github/forks/llllllxy/tiny-url?style=flat-square\u0026logo=GitHub\"\u003e\u003c/a\u003e\r\n\u003ca href=\"https://github.com/llllllxy/tiny-url/watchers\"\u003e\u003cimg src=\"https://img.shields.io/github/watchers/llllllxy/tiny-url?style=flat-square\u0026logo=GitHub\"\u003e\u003c/a\u003e\r\n\u003ca href=\"https://github.com/llllllxy/tiny-url/issues\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/llllllxy/tiny-url.svg?style=flat-square\u0026logo=GitHub\"\u003e\u003c/a\u003e\r\n\u003ca href=\"https://github.com/llllllxy/tiny-url/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/llllllxy/tiny-url.svg?style=flat-square\"\u003e\u003c/a\u003e\r\n\u003ca href='https://gitee.com/leisureLXY/tiny-url/stargazers'\u003e\u003cimg src='https://gitee.com/leisureLXY/tiny-url/badge/star.svg?theme=dark' alt='star'\u003e\u003c/img\u003e\u003c/a\u003e\r\n\u003ca href='https://gitee.com/leisureLXY/tiny-url/members'\u003e\u003cimg src='https://gitee.com/leisureLXY/tiny-url/badge/fork.svg?theme=dark' alt='fork'\u003e\u003c/img\u003e\u003c/a\u003e\r\n\r\n\r\n## 已实现功能\r\n1、将长链接转换成短链接，访问短链接时，302重定向至原始长链接\r\n\r\n2、支持设置短链的有效期限，生成短链访问二维码\r\n\r\n3、支持记录访问次数，访问日志\r\n\r\n4、使用布隆过滤器优化短链冲突问题，优化高并发下的性能表现\r\n\r\n5、支持多租户管理功能，租户注册后可拥有独立的后台数据管理功能（包括仪表盘、短链管理、访问日志管理、数据统计等）\r\n\r\n6、支持租户通过API调用方式生成短链接、禁用/启用短链接、更新短链有效期限、查看短链接信息等功能；提供成熟的API接口文档和鉴权方案（access_key + access_key_secret）\r\n\r\n## 计划实现功能\r\n1、超级管理员系统管理功能（用于管理租户）\r\n\r\n2、带访问密码的短链，访问时重定向到输入密码的页面，输入密码后方可访问\r\n\r\n3、带最大可用次数的短链，如设置访问限制100次，超出后则禁止访问\r\n\r\n## 部分界面展示\r\n首页\r\n![首页](src/main/resources/static/images/readme/首页.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\napi接口文档页\r\n![api接口文档页](src/main/resources/static/images/readme/api接口文档.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n关于我们页\r\n![关于我们页](src/main/resources/static/images/readme/关于我们.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n短链寻址失败时-404页\r\n![404页](src/main/resources/static/images/readme/example_404.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n短链寻址失败时-失效页\r\n![失效页](src/main/resources/static/images/readme/example_expire.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n租户登录页\r\n![租户登录](src/main/resources/static/images/readme/租户登录.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n租户注册页\r\n![租户注册](src/main/resources/static/images/readme/租户注册.png)\r\n\u003cbr/\u003e\u003cbr/\u003e\r\n租户后台数据管理\r\n![租户首页](src/main/resources/static/images/readme/租户首页.png)\r\n![仪表盘](src/main/resources/static/images/readme/仪表盘.png)\r\n![短链列表](src/main/resources/static/images/readme/短链管理.png)\r\n![数据统计](src/main/resources/static/images/readme/数据统计.png)\r\n![访问日志](src/main/resources/static/images/readme/访问日志.png)\r\n\r\n## 主要技术选型\r\n| 依赖                | 说明           |\r\n|-------------------|--------------|\r\n| SpringBoot 3.1.9  | 基础框架         |\r\n| Hikari            | 高性能数据库连接池 |\r\n| MyBatis-Plus      | MyBatis的增强ORM |\r\n| Redis             | 业务缓存、会话共享    |\r\n| Guava             | Hash算法、布隆过滤器 |\r\n| Layui             | 前端模板         |\r\n\r\n## 运行环境\r\n- Jdk17\r\n- MySQL5.6+\r\n- Redis3.0+\r\n\r\n## 启动部署教程\r\n\r\n1. 新建`MySQL`数据库并导入`resources/init`文件夹下的数据库脚本\r\n2. 修改配置文件中`application.yml`中`数据库`和`Redis`连接信息\r\n3. 运行启动类`TinyUrlApplication`，即可正常启动项目\r\n4. 平台首页地址：`http://localhost:9999/`\r\n5. 租户登录地址：`http://localhost:9999/page/tenant/login.html`  账户密码 `zhangsan / 123456`\r\n\r\n## 实现逻辑\r\n1、使用 MurmurHash 算法将原始长链接 hash 为 32 位散列值，将散列值转为 BASE62 编码 ，即为短链接。\r\n\r\n2、用户访问短链接时，在 Redis 中查找是否存在缓存，存在则刷新缓存时间，302 重定向至原始长链接，并自增短链接访问量，记录访问日志；\r\n缓存中不存在，则去数据库查找，查找成功则添加到 Redis 缓存，302 重定向至原始长链接，并自增短链接访问量，记录访问日志；\r\n数据库中若也不存在，则跳转到404页面；\r\n\r\n3、具体实现参考文章：[掘金-高性能短链设计](https://juejin.cn/post/6844904090602848270)\r\n\r\n## 部分技术介绍\r\n1、MurmurHash：MurmurHash 是一种非加密型哈希函数，适用于一般的哈希检索操作。\r\n与其它流行的MD5等哈希函数相比，对于规律性较强的 key，MurmurHash 的随机分布特征表现更良好。\r\n非加密意味着着相比 MD5，SHA 这些函数它的性能肯定更高（实际上性能是 MD5 等加密算法的十倍以上）。\r\nMurmurHash 有 32 bit、64 bit、128 bit 的实现，32 bit 已经足够表示近 43 亿个短链接。\r\n使用 Java 的话，在 Google 的 [guava](https://github.com/google/guava)\r\n或 [hutool](https://github.com/dromara/hutool) 中有相应实现，这里选择 guava 的实现。\r\n\r\n2、base62：MurmurHash 生成的哈希值最长有 10 位十进制数，为了进一步缩短短链接长度，可以将哈希值转为 base62 编码，这样最长就只有 6 个字符了。\r\n\r\n3、Redis：生成短链接后，通常在后续一段时间内此短链接的访问频率较高，则向 Redis 中添加带过期时间的缓存来减轻数据库压力。\r\n\r\n4、301 和 302 重定向的区别\r\n- 301，代表 **永久重定向**，也就是说第一次请求拿到长链接后，下次浏览器再去请求短链的话，不会向短网址服务器请求了，而是直接从浏览器的缓存里拿，这样在 server 层面就无法获取到短网址的点击数了，如果这个链接刚好是某个活动的链接，也就无法分析此活动的效果。所以我们一般不采用 301。\r\n- 302，代表 **临时重定向**，也就是说每次去请求短链都会去请求短网址服务器（除非响应中用 Cache-Control 或 Expired 暗示浏览器缓存）,这样就便于 server 统计点击数，所以虽然用 302 会给 server 增加一点压力，但在数据异常重要的今天，这点代码是值得的，所以推荐使用 302！\r\n\r\n5、多租户方案介绍：\r\n多租户技术，或称多重租赁技术，是一种软件架构技术。它探讨的是如何于多用户的环境下共用相同的系统或者程序组件，并且确保各个用户数据的隔离性。在云计算迅速发展的今天，多租户技术被广为运用于开发云各式服务，不论是 IaaS、PaaS 还是 SaaS，都可以看到多租户技术的影子，SaaS 应用与其它应用最大的差异特征就是多租户。\r\n\r\n多租户软件架构的设计目标：\r\n- 保证多个租户使用统一的SaaS云平台，同时对多个租户进行良好的隔离;\r\n- 能够保证SaaS云平台进行统一的升级,又不破坏各自的应用逻辑;\r\n- 支持业务数据的横向扩展,并能够支持某个租户单独扩展资源的能力;\r\n\r\n在多租户架构中，根据数据隔离情况可以分为以下三种情况：\r\n- 数据库分离\r\n- 共享数据库，schema分离\r\n- 共享数据库，共享schema\r\n\r\n多租户架构类型对比:\r\n\r\n| 多租户架构类型 | 优点 | 缺点 |\r\n| ------- | ------- | ------- |\r\n|     数据库分离    |   为不同的租户提供独立的数据库，有助于简化数据模型的扩展设计，满足不同租户的独特需求；如果出现故障，恢复数据比较简单   | 增多了数据库的安装数量，随之带来维护成本和购置成本的增加 |\r\n| 共享数据库,Schema独立 | 为安全性要求较高的租户提供了一定程度的逻辑数据隔离，并不是完全隔离；每个数据库可支持更多的租户数量 | 如果出现故障，数据恢复比较困难，因为恢复数据库将牵涉到其他租户的数据；如果需要跨租户统计数据，存在一定困难 |\r\n| 共享数据库，共享schema | 维护和购置成本最低，允许每个数据库支持的租户数量最多 | 隔离级别最低，安全性最低，需要在设计开发时加大对安全的开发量； 数据备份和恢复最困难，需要逐表逐条备份和还原 |\r\n\r\n本项目属于简单实现，故选用第三种方案","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllllllxy%2Ftiny-url","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllllllxy%2Ftiny-url","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllllllxy%2Ftiny-url/lists"}