├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── docs
└── images
│ └── 短信.png
├── mini-link-common
├── pom.xml
└── src
│ └── main
│ ├── frontend-deploy
│ ├── Dockerfile
│ ├── deployment-frontend.yml
│ ├── docker-compose.yml
│ ├── nginx.conf
│ └── service-frontend.yml
│ └── java
│ └── com
│ └── minilink
│ ├── MyBatisPlusGenerator.java
│ ├── adapter
│ ├── KafkaMsgAdapter.java
│ ├── LinkUrlAdapter.java
│ └── UserAdapter.java
│ ├── annotation
│ └── NoLogin.java
│ ├── config
│ ├── GlobalExceptionConfig.java
│ ├── MetaObjectConfig.java
│ ├── MyThreadPoolExecutor.java
│ ├── MybatisPlusConfig.java
│ ├── RedisConfig.java
│ ├── SnowFlakeConfig.java
│ └── SwaggerConfig.java
│ ├── constant
│ ├── CommonConstant.java
│ ├── KafkaConstant.java
│ ├── RedisConstant.java
│ └── RegexConstant.java
│ ├── enums
│ ├── BusinessCodeEnum.java
│ └── EmailEnum.java
│ ├── exception
│ └── BusinessException.java
│ ├── interceptor
│ ├── LoginInterceptor.java
│ └── LoginInterceptorHandler.java
│ ├── pojo
│ ├── dto
│ │ ├── LinkUrlSaveDTO.java
│ │ ├── LoginDTO.java
│ │ └── RegisterDTO.java
│ ├── entity
│ │ ├── EmailParamEntity.java
│ │ └── VisitShortLinkMsg.java
│ ├── po
│ │ ├── LinkGroup.java
│ │ ├── LinkUrlTob.java
│ │ ├── LinkUrlToc.java
│ │ └── LinkUser.java
│ └── vo
│ │ ├── LinkUrlTobVO.java
│ │ └── UserVO.java
│ └── util
│ ├── EncryptUtil.java
│ ├── HttpServletUtil.java
│ ├── IpUtil.java
│ ├── JwtUtil.java
│ ├── RandomUtil.java
│ ├── SnowFlakeUtil.java
│ └── resp
│ ├── BaseResponse.java
│ └── R.java
├── mini-link-core
├── Dockerfile
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── minilink
│ │ ├── MiniLinkCoreApplication.java
│ │ ├── controller
│ │ ├── LinkGroupController.java
│ │ ├── LinkUrlTobController.java
│ │ └── LinkUrlTocController.java
│ │ ├── mapper
│ │ ├── LinkGroupMapper.java
│ │ ├── LinkUrlTobMapper.java
│ │ └── LinkUrlTocMapper.java
│ │ ├── service
│ │ ├── LinkGroupService.java
│ │ ├── LinkUrlTobService.java
│ │ ├── LinkUrlTocService.java
│ │ └── impl
│ │ │ ├── LinkGroupServiceImpl.java
│ │ │ ├── LinkUrlTobServiceImpl.java
│ │ │ └── LinkUrlTocServiceImpl.java
│ │ ├── sharding
│ │ ├── ShardingConfigFactory.java
│ │ ├── ShardingElement.java
│ │ └── algorithm
│ │ │ ├── LinkTocDatabaseShardingAlgorithm.java
│ │ │ └── LinkTocTableShardingAlgorithm.java
│ │ ├── store
│ │ ├── LinkGroupStore.java
│ │ ├── LinkUrlTobStore.java
│ │ ├── LinkUrlTocStore.java
│ │ └── impl
│ │ │ ├── LinkGroupStoreImpl.java
│ │ │ ├── LinkUrlTobStoreImpl.java
│ │ │ └── LinkUrlTocStoreImpl.java
│ │ └── util
│ │ └── LinkUrlUtil.java
│ └── resources
│ ├── application-dev.yml
│ ├── application.yml
│ ├── deploy
│ ├── deployment-core.yml
│ ├── service-core.yml
│ └── sql
│ │ └── mini_link_core.sql
│ ├── mapper
│ ├── LinkGroupMapper.xml
│ ├── LinkUrlMapper.xml
│ └── LinkUrlTocMapper.xml
│ └── sharding-dev.yaml
├── mini-link-data
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── minilink
│ │ ├── MiniLinkDataApplication.java
│ │ ├── controller
│ │ └── ShortLinkStatisticsController.java
│ │ ├── mapper
│ │ └── ShortLinkStatisticsMapper.java
│ │ └── service
│ │ ├── ShortLinkStatisticsService.java
│ │ └── impl
│ │ └── ShortLinkStatisticsServiceImpl.java
│ └── resources
│ ├── application-dev.yml
│ ├── application.yml
│ └── deploy
│ ├── clickhouse.sql
│ ├── deployment-data.yml
│ └── service-data.yml
├── mini-link-flink
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── minilink
│ ├── app
│ ├── dwd
│ │ └── DwdClickLinkApp.java
│ ├── dwm
│ │ ├── DwmLinkWideLogApp.java
│ │ └── DwmUniqueVisitorApp.java
│ ├── dws
│ │ └── DwsClickLinkApp.java
│ ├── func
│ │ ├── DeviceMapFunction.java
│ │ ├── LocationMapFunction.java
│ │ ├── VisitorStateRichMapFunction.java
│ │ └── VisitorUniqueRichFilterFunction.java
│ └── sink
│ │ └── ClickHouseSink.java
│ ├── constant
│ └── KafkaConstant.java
│ ├── enums
│ └── VisitorStateEnum.java
│ ├── pojo
│ └── VisitShortLinkLog.java
│ └── util
│ ├── AMapUtil.java
│ ├── DateTimeUtil.java
│ ├── FlinkKafkaUtil.java
│ ├── OkHttpUtil.java
│ └── UserAgentUtil.java
├── mini-link-gateway
├── Dockerfile
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── minilink
│ │ └── MiniLinkGatewayApplication.java
│ └── resources
│ ├── application-dev.yml
│ ├── application.yml
│ └── deploy
│ ├── deployment-gateway.yml
│ ├── ingress-nginx.yml
│ └── service-gateway.yml
├── mini-link-user
├── Dockerfile
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── minilink
│ │ ├── MiniLinkUserApplication.java
│ │ ├── config
│ │ ├── CaptchaConfig.java
│ │ └── MinioConfig.java
│ │ ├── controller
│ │ ├── UserAssistController.java
│ │ ├── UserFormController.java
│ │ └── UserInfoController.java
│ │ ├── mapper
│ │ └── LinkUserMapper.java
│ │ ├── service
│ │ ├── UserAssistService.java
│ │ ├── UserFormService.java
│ │ ├── UserInfoService.java
│ │ └── impl
│ │ │ ├── UserAssistServiceImpl.java
│ │ │ ├── UserFormServiceImpl.java
│ │ │ └── UserInfoServiceImpl.java
│ │ ├── store
│ │ ├── LinkUserStore.java
│ │ └── impl
│ │ │ └── LinkUserStoreImpl.java
│ │ ├── strategy
│ │ └── email
│ │ │ ├── AbstractEmailStrategy.java
│ │ │ ├── EmailStrategyFactory.java
│ │ │ └── handler
│ │ │ └── RegisterEmailHandler.java
│ │ └── util
│ │ └── EmailUtil.java
│ └── resources
│ ├── application-dev.yml
│ ├── application.yml
│ ├── deploy
│ ├── deployment-user.yml
│ ├── mini_link_user.sql
│ └── service-user.yml
│ └── mapper
│ └── LinkUserMapper.xml
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributor Covenant Code of Conduct
3 |
4 | ## Our Pledge
5 |
6 | In the interest of fostering an open and welcoming environment, we as
7 | contributors and maintainers pledge to making participation in our project, and
8 | our community a harassment-free experience for everyone, regardless of age, body
9 | size, disability, ethnicity, gender identity and expression, level of experience,
10 | education, socio-economic status, nationality, personal appearance, race,
11 | religion, or sexual identity and orientation.
12 |
13 | ## Our Standards
14 |
15 | Examples of behavior that contributes to creating a positive environment
16 | include:
17 |
18 | * Using welcoming and inclusive language
19 | * Being respectful of differing viewpoints and experiences
20 | * Gracefully accepting constructive criticism
21 | * Focusing on what is best for the community
22 | * Showing empathy towards other community members
23 |
24 | Examples of unacceptable behavior by participants include:
25 |
26 | * The use of sexualized language or imagery and unwelcome sexual attention or
27 | advances
28 | * Trolling, insulting/derogatory comments, and personal or political attacks
29 | * Public or private harassment
30 | * Publishing others' private information, such as a physical or electronic
31 | address, without explicit permission
32 | * Other conduct which could reasonably be considered inappropriate in a
33 | professional setting
34 |
35 | ## Our Responsibilities
36 |
37 | Project maintainers are responsible for clarifying the standards of acceptable
38 | behavior and are expected to take appropriate and fair corrective action in
39 | response to any instances of unacceptable behavior.
40 |
41 | Project maintainers have the right and responsibility to remove, edit, or
42 | reject comments, commits, code, wiki edits, issues, and other contributions
43 | that are not aligned to this Code of Conduct, or to ban temporarily or
44 | permanently any contributor for other behaviors that they deem inappropriate,
45 | threatening, offensive, or harmful.
46 |
47 | ## Scope
48 |
49 | This Code of Conduct applies both within project spaces and in public spaces
50 | when an individual is representing the project or its community. Examples of
51 | representing a project or community include using an official project e-mail
52 | address, posting via an official social media account, or acting as an appointed
53 | representative at an online or offline event. Representation of a project may be
54 | further defined and clarified by project maintainers.
55 |
56 | ## Enforcement
57 |
58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
59 | reported by contacting the project team at https://knowstreaming.com/support-center . All
60 | complaints will be reviewed and investigated and will result in a response that
61 | is deemed necessary and appropriate to the circumstances. The project team is
62 | obligated to maintain confidentiality with regard to the reporter of an incident.
63 | Further details of specific enforcement policies may be posted separately.
64 |
65 | Project maintainers who do not follow or enforce the Code of Conduct in good
66 | faith may face temporary or permanent repercussions as determined by other
67 | members of the project's leadership.
68 |
69 | ## Attribution
70 |
71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
72 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
73 |
74 | [homepage]: https://www.contributor-covenant.org
75 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | # ✨系统介绍
9 |
10 | Mini Link 是一套用于将长链接压缩为短链接系统,访问用户可以通过短链接快速分享、访问源地址。支持多种使用场景,包括社交媒体分享、营销活动跟踪、数据分析等。
11 |
12 | 系统基于 SpringBoot 3.2 + SpringCloud Alibaba 2023 等主流技术实现的高并发、高性能、海量数据短链接平台。
13 |
14 | 通过 Kafka + Flink + ClickHouse 实现访问行为数据实时数仓,完成海量数据清洗、计算、聚合,提供多维度数据统计面板功能。
15 |
16 |
17 | 商业使用场景:
18 | 1. **在线广告**
19 | 2. **社交媒体**
20 | 3. **电商平台**
21 | 4. **......**
22 |
23 | 
24 |
25 |
26 | 短链接优点:
27 |
28 | 1. **缩短长链接字符数量,简洁美观**
29 | 2. **降低营销短信字数,降低费用成本**
30 | 3. **简化图形二维码生成复杂度**
31 | 4. **隐藏链接业务参数,提高数据安全性**
32 | 5. **方便统计运营数据,挖掘数据价值**
33 | 6. **......**
34 |
35 | # 🚀项目架构
36 |
37 | ## 模块划分
38 |
39 | ```
40 | mini-link
41 | ├── mini-link-common --- 公共通用
42 | ├── mini-link-core --- 短链接模块
43 | ├── mini-link-data --- 大数据统计看板
44 | ├── mini-link-flink --- 大数据实时计算
45 | ├── mini-link-gateway --- 服务网关
46 | └── mini-link-user --- 用户模块
47 | ```
48 |
49 | ## 服务端
50 |
51 | | 技术 | 说明 | 官网 |
52 | |----------------------|-----------|------------------------------------------------------------------------------|
53 | | JDK17 | Java开发工具 | https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html |
54 | | Spring Boot | Spring脚手架 | https://spring.io/projects/spring-boot |
55 | | Spring Cloud Alibaba | 微服务框架 | https://github.com/alibaba/spring-cloud-alibaba |
56 | | MySQL | 关系型数据库 | https://github.com/mysqljs/mysql |
57 | | Redis | KV数据库 | https://github.com/redis/redis |
58 | | MyBatis-Plus | ORM框架 | https://baomidou.com/ |
59 | | XXL-JOB | 定时调度 | https://github.com/xuxueli/xxl-job |
60 | | MinIO | 文件存储 | https://github.com/minio/minio |
61 | | ShardingSphere | 分库分表 | https://github.com/apache/shardingsphere |
62 | | Lombok | JavaBean库 | https://github.com/projectlombok/lombok |
63 | | Kafka | 消息队列 | https://github.com/apache/kafka |
64 | | Flink | 流处理框架 | https://github.com/apache/flink |
65 | | ClickHouse | OLAP数据仓库 | https://github.com/ClickHouse/ClickHouse |
66 |
67 | ## 前端
68 |
69 | | 技术 | 说明 | 官网 |
70 | |-------------|----------|---------------------------------|
71 | | Vue | 前端框架 | https://vuejs.org/ |
72 | | Vue-router | 路由框架 | https://router.vuejs.org/ |
73 | | Vuex | 全局状态管理框架 | https://vuex.vuejs.org/ |
74 | | ElementPlus | 前端UI框架 | https://element-plus.org/ |
75 | | TypeScript | 微软开源语言 | https://www.typescriptlang.org/ |
76 | | Axios | HTTP请求库 | https://github.com/axios/axios |
77 | | Echarts | 数据图表 | https://v-charts.js.org/ |
78 |
79 | ## 运维
80 |
81 | | 技术 | 说明 | 官网 |
82 | |---------------|--------|---------------------------------------------|
83 | | Docker | 镜像容器 | https://www.docker.com/ |
84 | | Kubernetes | 容器编排工具 | https://kubernetes.io/ |
85 | | Ingress-Nginx | 负载均衡器 | https://github.com/kubernetes/ingress-nginx |
86 | | Gitlab | 代码仓库 | https://github.com/gitlabhq/gitlabhq |
87 | | Harbor | 镜像仓库 | https://github.com/axios/axios |
88 | | Jenkins | 自动化发布 | https://github.com/jenkinsci/jenkins |
89 | | Prometheus | 数据采集 | https://github.com/prometheus/prometheus |
90 | | Grafana | 数据可视化 | https://github.com/grafana/grafana |
91 | | Logstash | 日志采集 | https://github.com/elastic/logstash |
92 | | Kibana | 日志可视化 | https://github.com/elastic/kibana |
93 |
94 | # 🎉贡献名单
95 |
96 |
97 |
98 |
99 |
100 | | 姓名 | Github | 公司 |
101 | |:---:|:-----------------------------:|:--------------------:|
102 | | 徐志斌 | https://github.com/Binx98 | PARAVERSE TECHNOLOGY |
103 | | Joy | https://github.com/Joydevelop | 保密 |
104 | | 陈辰 | https://github.com/ | SBI BITS |
105 | | 刘贤壮 | https://github.com/ | 江苏中车数字 |
106 |
--------------------------------------------------------------------------------
/docs/images/短信.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Binx98/mini-link/77beb09be961aae244a5befed9676f45f7b721c5/docs/images/短信.png
--------------------------------------------------------------------------------
/mini-link-common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | com.minilink
6 | mini-link
7 | 0.0.1-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | com.minilink
12 | mini-link-common
13 | 0.0.1-SNAPSHOT
14 | mini-link-common
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-web
20 |
21 |
22 | com.alibaba.cloud
23 | spring-cloud-starter-alibaba-nacos-discovery
24 |
25 |
26 | mysql
27 | mysql-connector-java
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-data-redis
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-validation
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-aop
40 |
41 |
42 | io.jsonwebtoken
43 | jjwt
44 |
45 |
46 | com.baomidou
47 | mybatis-plus-spring-boot3-starter
48 |
49 |
50 | com.baomidou
51 | mybatis-plus-generator
52 |
53 |
54 | com.baomidou
55 | mybatis-plus-jsqlparser
56 |
57 |
58 | org.springframework.boot
59 | spring-boot-starter-freemarker
60 |
61 |
62 | org.projectlombok
63 | lombok
64 |
65 |
66 | org.springdoc
67 | springdoc-openapi-starter-webmvc-ui
68 |
69 |
70 | javax.xml.bind
71 | jaxb-api
72 |
73 |
74 | org.springframework.kafka
75 | spring-kafka
76 |
77 |
78 | cn.hutool
79 | hutool-all
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/frontend-deploy/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.24.0
2 | MAINTAINER 徐志斌
3 | COPY ./dist /usr/share/nginx/html
4 | COPY nginx.conf /etc/nginx/nginx.conf
5 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/frontend-deploy/deployment-frontend.yml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: frontend-deployment
5 | namespace: mini-link-namespace
6 | labels:
7 | app: frontend-label
8 | spec:
9 | replicas: 3
10 | selector:
11 | matchLabels:
12 | app: frontend-label
13 | template:
14 | metadata:
15 | labels:
16 | app: frontend-label
17 | spec:
18 | containers:
19 | - name: frontend
20 | image: 镜像仓库内网IP:端口/minilink/mini-link-frontend:1.0
21 | imagePullPolicy: Always
22 | ports:
23 | - containerPort: 80
24 | resources:
25 | requests:
26 | memory: 300Mi
27 | cpu: 200m
28 | limits:
29 | memory: 500Mi
30 | cpu: 400m
31 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/frontend-deploy/docker-compose.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Binx98/mini-link/77beb09be961aae244a5befed9676f45f7b721c5/mini-link-common/src/main/frontend-deploy/docker-compose.yml
--------------------------------------------------------------------------------
/mini-link-common/src/main/frontend-deploy/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | events {
4 | worker_connections 1024;
5 | }
6 |
7 | http {
8 | include mime.types;
9 | default_type application/octet-stream;
10 | sendfile on;
11 | keepalive_timeout 65;
12 |
13 | server {
14 | listen 80;
15 | server_name localhost;
16 |
17 | location / {
18 | root /usr/share/nginx/html;
19 | try_files $uri $uri/ /index.html;
20 | index index.html index.htm;
21 | }
22 |
23 | location /api/ {
24 | proxy_http_version 1.1;
25 | proxy_set_header Host $host;
26 | proxy_set_header X-Real-IP $remote_addr;
27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
28 | proxy_set_header Connection "";
29 | # 这里用的是 K8S Service 服务名访问方式
30 | proxy_pass http://backend-service.prod-env.svc.cluster.local:8080;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/frontend-deploy/service-frontend.yml:
--------------------------------------------------------------------------------
1 | kind: Service
2 | apiVersion: v1
3 | metadata:
4 | name: frontend-service
5 | namespace: mini-link-namespace
6 | labels:
7 | app: frontend-label
8 | spec:
9 | selector:
10 | app: frontend-label
11 | type: ClusterIP
12 | ports:
13 | - protocol: TCP
14 | port: 80
15 | targetPort: 80
16 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/MyBatisPlusGenerator.java:
--------------------------------------------------------------------------------
1 | package com.minilink;
2 |
3 | import com.baomidou.mybatisplus.annotation.FieldFill;
4 | import com.baomidou.mybatisplus.annotation.IdType;
5 | import com.baomidou.mybatisplus.generator.FastAutoGenerator;
6 | import com.baomidou.mybatisplus.generator.config.OutputFile;
7 | import com.baomidou.mybatisplus.generator.config.rules.DateType;
8 | import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
9 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
10 | import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
11 | import com.baomidou.mybatisplus.generator.fill.Column;
12 |
13 | import java.sql.Types;
14 | import java.util.Collections;
15 |
16 | /**
17 | * @Author 徐志斌
18 | * @Date: 2024/12/6 14:52
19 | * @Version 1.0
20 | * @Description: MyBatis-Plus 代码生成器
21 | */
22 | public class MyBatisPlusGenerator {
23 | public static void main(String[] args) {
24 | String url = "jdbc:mysql://localhost:3306/mini_link_core_0?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
25 | String username = "root";
26 | String password = "123456";
27 | String projectPath = System.getProperty("user.dir");
28 | FastAutoGenerator.create(url, username, password)
29 | .globalConfig(builder -> {
30 | builder.author("徐志斌")
31 | .dateType(DateType.TIME_PACK)
32 | .commentDate("yyyy-MM-dd")
33 | .outputDir(projectPath + "/src/main/java")
34 | .disableOpenDir();
35 | })
36 | .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
37 | int typeCode = metaInfo.getJdbcType().TYPE_CODE;
38 | if (typeCode == Types.SMALLINT || typeCode == Types.TINYINT) {
39 | return DbColumnType.INTEGER;
40 | }
41 | return typeRegistry.getColumnType(metaInfo);
42 | }))
43 | .packageConfig(builder -> {
44 | builder.parent("com.minilink")
45 | .controller("controller")
46 | .entity("pojo.po")
47 | .service("service")
48 | .serviceImpl("service.impl")
49 | .mapper("mapper")
50 | .xml("mapper.xml")
51 | .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mapper"))
52 | .build();
53 | })
54 | .strategyConfig(builder -> {
55 | builder.enableCapitalMode()
56 | .enableSkipView()
57 | .disableSqlFilter()
58 | .addInclude("link_url_toc_0")
59 | .entityBuilder().enableFileOverride().enableLombok()
60 | .enableChainModel()
61 | .enableRemoveIsPrefix()
62 | .enableTableFieldAnnotation()
63 | .logicDeleteColumnName("deleted")
64 | .logicDeletePropertyName("deleted")
65 | .naming(NamingStrategy.underline_to_camel)
66 | .columnNaming(NamingStrategy.underline_to_camel)
67 | .idType(IdType.ASSIGN_ID)
68 | .formatFileName("%s")
69 | .addTableFills(new Column("create_time", FieldFill.INSERT))
70 | .addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE))
71 | .addTableFills(new Column("deleted", FieldFill.INSERT))
72 | .controllerBuilder()
73 | .enableFileOverride()
74 | .enableHyphenStyle()
75 | .enableRestStyle()
76 | .formatFileName("%sController")
77 | .serviceBuilder()
78 | .enableFileOverride()
79 | .formatServiceFileName("%sService")
80 | .formatServiceImplFileName("%sServiceImpl")
81 | .mapperBuilder()
82 | .enableFileOverride()
83 | .enableBaseColumnList()
84 | .enableBaseResultMap()
85 | .formatMapperFileName("%sMapper")
86 | .formatXmlFileName("%sMapper");
87 | }).templateEngine(new FreemarkerTemplateEngine())
88 | .templateConfig(builder -> {
89 | builder.controller("/templates/controller.java").service("/templates/service.java")
90 | .serviceImpl("/templates/serviceImpl.java")
91 | .build();
92 | }).execute();
93 | System.out.println("=========================代码生成器执行成功!=========================");
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/adapter/KafkaMsgAdapter.java:
--------------------------------------------------------------------------------
1 | package com.minilink.adapter;
2 |
3 | import com.minilink.pojo.entity.VisitShortLinkMsg;
4 | import com.minilink.util.IpUtil;
5 |
6 | import java.time.LocalDateTime;
7 |
8 | /**
9 | * @Author: 徐志斌
10 | * @CreateTime: 2024-12-20 11:20
11 | * @Description: Kafka 队列消息适配器
12 | * @Version: 1.0
13 | */
14 | public class KafkaMsgAdapter {
15 | public static VisitShortLinkMsg buildVisitShortLinkMsg(Long accountId, String userAgentStr, String shortLinkCode) {
16 | VisitShortLinkMsg msg = new VisitShortLinkMsg();
17 | msg.setAccountId(accountId);
18 | msg.setIp(IpUtil.getIpAddr());
19 | msg.setUserAgent(userAgentStr);
20 | msg.setShortLinkCode(shortLinkCode);
21 | msg.setVisitTime(LocalDateTime.now());
22 | return msg;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/adapter/LinkUrlAdapter.java:
--------------------------------------------------------------------------------
1 | package com.minilink.adapter;
2 |
3 | import com.minilink.pojo.po.LinkUrlTob;
4 | import com.minilink.pojo.po.LinkUrlToc;
5 | import com.minilink.pojo.vo.LinkUrlTobVO;
6 |
7 | import java.time.LocalDateTime;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * @Author: 徐志斌
13 | * @CreateTime: 2024-12-13 13:21
14 | * @Description: 链接-适配器
15 | * @Version: 1.0
16 | */
17 | public class LinkUrlAdapter {
18 | public static LinkUrlTob buildLinkUrlTobPO(Long accountId, Long groupId, String title, String icon,
19 | String domain, String shortLinkCode, String shortLink,
20 | String longLink, LocalDateTime expiredTime) {
21 | LinkUrlTob linkUrl = new LinkUrlTob();
22 | linkUrl.setAccountId(accountId);
23 | linkUrl.setGroupId(groupId);
24 | linkUrl.setTitle(title);
25 | linkUrl.setIcon(icon);
26 | linkUrl.setDomain(domain);
27 | linkUrl.setShortLinkCode(shortLinkCode);
28 | linkUrl.setShortLink(shortLink);
29 | linkUrl.setLongLink(longLink);
30 | linkUrl.setExpiredTime(expiredTime);
31 | return linkUrl;
32 | }
33 |
34 | public static LinkUrlToc buildLinkUrlTocPO(Long id, Long accountId, String shortLinkCode,
35 | String shortLink, String longLink, LocalDateTime expiredTime) {
36 | LinkUrlToc linkUrl = new LinkUrlToc();
37 | linkUrl.setId(id);
38 | linkUrl.setAccountId(accountId);
39 | linkUrl.setShortLinkCode(shortLinkCode);
40 | linkUrl.setShortLink(shortLink);
41 | linkUrl.setLongLink(longLink);
42 | linkUrl.setExpiredTime(expiredTime);
43 | return linkUrl;
44 | }
45 |
46 | public static LinkUrlTobVO buildLinkUrlTobVO(LinkUrlTob linkUrlTob) {
47 | LinkUrlTobVO linkUrl = new LinkUrlTobVO();
48 | linkUrl.setTitle(linkUrlTob.getTitle());
49 | linkUrl.setGroupId(linkUrlTob.getGroupId());
50 | linkUrl.setAccountId(linkUrlTob.getAccountId());
51 | linkUrl.setShortLink(linkUrlTob.getShortLink());
52 | linkUrl.setQrCode(linkUrlTob.getQrCode());
53 | linkUrl.setLongLink(linkUrlTob.getLongLink());
54 | linkUrl.setExpiredTime(linkUrlTob.getExpiredTime());
55 | return linkUrl;
56 | }
57 |
58 | public static List buildLinkUrlTobVOList(List urlTobList) {
59 | List result = new ArrayList<>();
60 | for (LinkUrlTob urlTob : urlTobList) {
61 | LinkUrlTobVO linkUrl = new LinkUrlTobVO();
62 | linkUrl.setTitle(urlTob.getTitle());
63 | linkUrl.setGroupId(urlTob.getGroupId());
64 | linkUrl.setAccountId(urlTob.getAccountId());
65 | linkUrl.setShortLink(urlTob.getShortLink());
66 | linkUrl.setQrCode(urlTob.getQrCode());
67 | linkUrl.setLongLink(urlTob.getLongLink());
68 | linkUrl.setExpiredTime(urlTob.getExpiredTime());
69 | result.add(linkUrl);
70 | }
71 | return result;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/adapter/UserAdapter.java:
--------------------------------------------------------------------------------
1 | package com.minilink.adapter;
2 |
3 | import com.minilink.pojo.po.LinkUser;
4 | import com.minilink.pojo.vo.UserVO;
5 |
6 | /**
7 | * @Author 徐志斌
8 | * @Date: 2024/12/8 15:08
9 | * @Version 1.0
10 | * @Description: 账户相关-适配器
11 | */
12 | public class UserAdapter {
13 | public static LinkUser buildUserPO(Long accountId, String nickName, String avatar,
14 | String email, String password, String salt) {
15 | LinkUser userPO = new LinkUser();
16 | userPO.setAccountId(accountId);
17 | userPO.setNickName(nickName);
18 | userPO.setAvatar(avatar);
19 | userPO.setEmail(email);
20 | userPO.setPassword(password);
21 | userPO.setSalt(salt);
22 | return userPO;
23 | }
24 |
25 | public static LinkUser buildUserPO(Long accountId, String nickName, String avatar, String email) {
26 | LinkUser userPO = new LinkUser();
27 | userPO.setAccountId(accountId);
28 | userPO.setNickName(nickName);
29 | userPO.setAvatar(avatar);
30 | userPO.setEmail(email);
31 | return userPO;
32 | }
33 |
34 | public static UserVO buildUserVO(LinkUser userPO) {
35 | UserVO userVO = new UserVO();
36 | userVO.setEmail(userPO.getEmail());
37 | userVO.setNickName(userPO.getNickName());
38 | userVO.setAvatar(userPO.getAvatar());
39 | userVO.setCreateTime(userPO.getCreateTime());
40 | return userVO;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/annotation/NoLogin.java:
--------------------------------------------------------------------------------
1 | package com.minilink.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @Author: 徐志斌
7 | * @CreateTime: 2024-12-20 11:48
8 | * @Description: 免登录注解
9 | * @Version: 1.0
10 | */
11 | @Target({ElementType.METHOD, ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Documented
14 | public @interface NoLogin {
15 | }
16 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/config/GlobalExceptionConfig.java:
--------------------------------------------------------------------------------
1 | package com.minilink.config;
2 |
3 | import com.minilink.enums.BusinessCodeEnum;
4 | import com.minilink.exception.BusinessException;
5 | import com.minilink.util.resp.R;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.validation.BindException;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 | import org.springframework.web.bind.annotation.RestControllerAdvice;
10 | import org.springframework.web.method.annotation.HandlerMethodValidationException;
11 |
12 | /**
13 | * @Author 徐志斌
14 | * @Date: 2024/12/6 11:08
15 | * @Version 1.0
16 | * @Description: 全局异常处理
17 | */
18 | @Slf4j
19 | @RestControllerAdvice
20 | public class GlobalExceptionConfig {
21 | /**
22 | * 自定义异常 BusinessException
23 | */
24 | @ExceptionHandler(BusinessException.class)
25 | public R bizException(BusinessException e) {
26 | log.error("-------------bizException:{}-------------", e.getCodeEnum());
27 | return R.out(e.getCodeEnum());
28 | }
29 |
30 | /**
31 | * 服务端接口参数校验异常
32 | */
33 | @ExceptionHandler(BindException.class)
34 | public R validationException(BindException e) {
35 | StringBuilder sb = new StringBuilder();
36 | e.getBindingResult().getAllErrors().forEach(error -> sb.append(error.getDefaultMessage()).append("\r\n"));
37 | log.error("-------------bindException:{}-------------", e.getMessage());
38 | return R.out(BusinessCodeEnum.PARAM_ERROR, sb);
39 | }
40 |
41 | @ExceptionHandler(HandlerMethodValidationException.class)
42 | public R handlerMethodValidationException(HandlerMethodValidationException e) {
43 | log.error("-------------handlerMethodValidationException:{}-------------", e.getMessage());
44 | return R.out(BusinessCodeEnum.REGEX_SHORT_LINK_FORMAT_ERROR, e.getMessage());
45 | }
46 |
47 |
48 | /**
49 | * 异常兜底 Exception
50 | */
51 | @ExceptionHandler(Exception.class)
52 | public R exception(Exception e) {
53 | log.error("-------------exception:{}-------------", e.getMessage());
54 | return R.out(BusinessCodeEnum.FAIL, e.getMessage());
55 | }
56 | }
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/config/MetaObjectConfig.java:
--------------------------------------------------------------------------------
1 | package com.minilink.config;
2 |
3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.ibatis.reflection.MetaObject;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.time.LocalDateTime;
9 |
10 | /**
11 | * @Author: 徐志斌
12 | * @CreateTime: 2023-10-24 11:48
13 | * @Description: MyBatis-Plus自动填充
14 | * @Version: 1.0
15 | */
16 | @Slf4j
17 | @Component
18 | public class MetaObjectConfig implements MetaObjectHandler {
19 | @Override
20 | public void insertFill(MetaObject metaObject) {
21 | this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
22 | this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
23 | this.strictInsertFill(metaObject, "deleted", Boolean.class, false);
24 | }
25 |
26 | @Override
27 | public void updateFill(MetaObject metaObject) {
28 | this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
29 | }
30 | }
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/config/MyThreadPoolExecutor.java:
--------------------------------------------------------------------------------
1 | package com.minilink.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
6 |
7 | import java.util.concurrent.ThreadPoolExecutor;
8 |
9 | /**
10 | * @Author: 徐志斌
11 | * @CreateTime: 2024-12-6 20:06
12 | * @Description: 自定义线程池
13 | * @Version: 1.0
14 | */
15 | @Configuration
16 | public class MyThreadPoolExecutor {
17 | public static final String THREAD_POOL_NAME = "threadPoolTaskExecutor";
18 |
19 | /**
20 | * CPU 密集型:线程数建议设置为 CPU 核心数 + 1。
21 | * IO 密集型:线程数建议设置为 2 * CPU 核心数。
22 | */
23 | @Bean(THREAD_POOL_NAME)
24 | public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
25 | int cpuCores = Runtime.getRuntime().availableProcessors();
26 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
27 | executor.setCorePoolSize(cpuCores + 1);
28 | executor.setMaxPoolSize(cpuCores + 1);
29 | executor.setQueueCapacity(100);
30 | executor.setKeepAliveSeconds(30);
31 | executor.setThreadNamePrefix("mini-link-");
32 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
33 | executor.initialize();
34 | return executor;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package com.minilink.config;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * @Author: 徐志斌
11 | * @CreateTime: 2024-12-20 16:14
12 | * @Description: MyBatis-Plus 分页插件
13 | * @Version: 1.0
14 | */
15 | @Configuration
16 | public class MybatisPlusConfig {
17 | @Bean
18 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
19 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
20 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
21 | return interceptor;
22 | }
23 | }
--------------------------------------------------------------------------------
/mini-link-common/src/main/java/com/minilink/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.minilink.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.data.redis.connection.RedisConnectionFactory;
6 | import org.springframework.data.redis.core.RedisTemplate;
7 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
8 | import org.springframework.data.redis.serializer.StringRedisSerializer;
9 |
10 | /**
11 | * @Author 徐志斌
12 | * @Date: 2024/12/7 10:01
13 | * @Version 1.0
14 | * @Description: Redis 配置类
15 | */
16 | @Configuration
17 | public class RedisConfig {
18 | @Bean
19 | public RedisTemplate