logo
1
3
WeChat Login

demo-java-monorepo

unit coverage pull request tag_push pipeline tca tca

基于 Spring Boot 2.7 + Maven Multi-Module 的 Monorepo 多微服务演示项目,带有独立 Helm Chart。 一个仓库、一条流水线、多个可独立部署的服务。

⭐ 前端静态演示页已内嵌到 rps-game-service,启动 Spring Boot 即可同时拿到前后端。

demo-java-monorepo 架构图


✨ 一键启动

方式 1:直接跑 Spring Boot(本地最推荐)

./mvnw -pl rps-game-service -am spring-boot:run
# 打开浏览器 → http://localhost:8081

打开页面就能看到 CNB 演示页 + 石头剪刀布小游戏,后端 API 同样由 rps-game-service 提供。

💡 文档中的 ./mvnw 都可以替换成本机已安装的 mvn(要求 Maven ≥ 3.6)。 Wrapper 的好处是免安装、版本固定(见 .mvn/wrapper/maven-wrapper.properties,当前 3.8.7),CI 与团队成员保持一致。

方式 2:K8s 上用 Helm 部署

# 先构建并推送镜像(见下文 §5),然后:
helm install rps     ./rps-game-service/helm
helm install gateway ./gateway-service/helm
helm install weather ./weather-service/helm
helm install user    ./user-service/helm

1. 项目结构

所有微服务都作为顶层目录存在(不再套在 services/ 下),每个目录都可独立编译、打包、构建镜像、发布 Helm。

demo-java-monorepo/
├── pom.xml                        # 父 POM,声明子模块与依赖管理
├── Dockerfile                     # 通用后端 Dockerfile,--build-arg SERVICE=xxx
├── docs/
│   └── ARCHITECTURE.md            # 架构与服务拓扑说明
│
├── gateway-service/               # 8080 · 聚合网关
│   ├── pom.xml · src/
│   └── helm/                      #   ⎈ 独立 Helm Chart
│
├── rps-game-service/              # 8081 · 石头剪刀布 + 前端演示页(一键启动主服务)
│   ├── pom.xml
│   ├── src/main/java/             #   后端 ApiController: /api/rps/**
│   ├── src/main/resources/static/ #   ⭐ 前端静态页(index.html / styles.css / app.js)
│   └── helm/
│
├── weather-service/               # 8082 · 天气查询(mock)
│   ├── pom.xml · src/
│   └── helm/
│
├── user-service/                  # 8083 · 用户 CRUD(内存)
│   ├── pom.xml · src/
│   └── helm/
│
├── assets/                        # 文档插图
└── mvnw / mvnw.cmd

2. 服务一览

服务类型端口主要接口 / 入口Helm Chart
rps-game-serviceSpring Boot8081/(前端页)· /api/rps/playrps-game-service/helm
gateway-serviceSpring Boot8080/api/gateway/overviewgateway-service/helm
weather-serviceSpring Boot8082/api/weather/currentweather-service/helm
user-serviceSpring Boot8083/api/usersuser-service/helm

所有服务都完全独立ApiResponse / ServiceConstants 等共享类已下沉到各服务自身包内,服务之间无 Maven 依赖,可在任一服务目录下直接 ../mvnw clean package 单独构建。


3. 前端演示页(内嵌于 rps-game-service)

  • 位置:rps-game-service/src/main/resources/static/
    • index.html · styles.css · app.js
  • 风格:温馨简洁(奶油米白 + 暖杏 + 淡湖绿),圆角卡片 + 柔阴影。
  • 交互:页面上玩石头剪刀布,前端 fetch('/api/rps/play') 直接命中同进程的 ApiController,无跨域、无反代。
  • 访问入口:启动 rps-game-service 后浏览器打开 http://localhost:8081/

Spring Boot 默认会把 classpath:/static/ 作为静态资源根目录,index.html 作为 / 的欢迎页,无需额外配置。


4. 构建与测试

# 编译所有模块
./mvnw -q -DskipTests -T 1C compile

# 跑全部单测(带 Jacoco 覆盖率)
./mvnw -q -T 1C test

# 打包单个服务
./mvnw -pl rps-game-service -am -DskipTests package

# 本地运行(含前端)
./mvnw -pl rps-game-service -am spring-boot:run
# 或者: java -jar rps-game-service/target/rps-game-service.jar

# 已装 Maven 的话,等价命令是把 ./mvnw 换成 mvn,例如:
#   mvn -pl rps-game-service -am spring-boot:run

5. 构建镜像(支持全量 & 按需)

所有后端服务共用根目录的通用 Dockerfile,同时支持「全量构建」和「按需构建」两种姿势,本地与 CI 行为一致。

A. 全量构建 — 一次把 4 个服务镜像全打出来:

# 本地:4 条命令各打一个镜像(也可以写成 for 循环)
docker build --build-arg SERVICE=rps-game-service -t demo/rps-game-service .
docker build --build-arg SERVICE=weather-service  -t demo/weather-service  .
docker build --build-arg SERVICE=user-service     -t demo/user-service     .
docker build --build-arg SERVICE=gateway-service  -t demo/gateway-service  .

CI 上对应的全量入口:master 分支「手动发版」按钮里 var4 留空(默认全选 4 个服务),或在 dev 分支按下联调按钮。

B. 按需构建 — 只编译/推送你关心的几个服务,避免改 1 个服务时把 4 个全部重打:

# 本地:先增量编译,再单独打这一个镜像
./mvnw -pl rps-game-service -am -DskipTests package
docker build --build-arg SERVICE=rps-game-service -t demo/rps-game-service .

CI 上对应的按需入口:

触发方式按需粒度怎么选
PR 流水线自动按变更只对 PR 里改动到的服务跑构建(无需手动选)
master 手动发版按钮表单显式勾选var4 多选你想发的服务,仅这些镜像会被 build & push
dev 联调按钮默认全量不需要按需时不用动;想按需也支持手填 var4

前端资源随 rps-game-service 的 jar 一起打包,不需要单独构建前端镜像。

💡 详细机制(var3/var4 字段含义、mvn -pl 增量编译、镜像 tag 规则、本地等价命令、FAQ)见 docs/CI-ON-DEMAND-BUILD.md


6. Helm 发布

每个服务都带有独立的 helm/ 目录:

# 渲染查看
helm template demo ./rps-game-service/helm

# 安装到当前 namespace
helm install rps     ./rps-game-service/helm
helm install gateway ./gateway-service/helm
helm install weather ./weather-service/helm
helm install user    ./user-service/helm

# 升级 / 卸载
helm upgrade rps ./rps-game-service/helm -f custom-values.yaml
helm uninstall rps

公共的 values.yaml 字段包括 replicaCount / image.* / service.* / resources / env / livenessProbe / readinessProbe / ingress.*,足够演示常见改造需要。

rps-game-service 的 chart 发布后,同时暴露前端页面与 /api/rps/**,通过 ingress 对外只需要一个 Host。


7. 调用示例

# 前端页
open http://localhost:8081/

# 后端 API(前端内部调用的就是同一个地址)
curl -X POST http://localhost:8081/api/rps/play \
     -H "Content-Type: application/json" \
     -d '{"choice":"rock"}'

curl http://localhost:8081/api/rps/health

# 其他后端(独立启动 / 部署到 K8s 后访问)
curl "http://localhost:8082/api/weather/current?city=Shanghai"
curl  http://localhost:8083/api/users
curl "http://localhost:8080/api/gateway/overview?userId=1&city=Beijing"

8. 更多文档


9. 开发约定

  • Java 1.8 · Spring Boot 2.7.13 · Maven 3.x
  • 所有子模块继承父 POM 统一版本
  • 代码安全:参数化 SQL、SecureRandom、不硬编码密钥
  • 前端:纯静态(HTML + CSS + 原生 JS),不引入构建工具,保持最小依赖

Made with ☕ & ❤️ for CNB demos.

About

springboot+maven的测试案例。

springbootmaven