Skip to content

Latest commit

 

History

History
165 lines (127 loc) · 10.4 KB

File metadata and controls

165 lines (127 loc) · 10.4 KB

boot-server:与学习文档配套的 Spring Boot 4 多模块工程

本工程是 实战产品蓝图(BootMall「云市商城」)的实现载体:每学完一个阶段,按蓝图的「业务场景 × 技术方案」映射表往这里落一块功能。当前进度与下一步以 实践计划与进度 为准,本文件不复述状态。

配套客户端位于仓库根目录:admin-client/ 对应 B 端管理后台,user-client/ 对应 C 端商城,均为独立的 React + TypeScript + Vite 工程。各自的接入时机与进度见 实践计划与进度,本文件不复述。

后端项目级开发规则见 boot-server/AGENTS.md,其中包含 Java 分层、MyBatis-Plus、手写 SQL、事务、测试和数据库配置规范。

仓库 docs/ 里学习路线(阶段零 → 阶段八)的实操落点: 文档教概念,这个工程给你「跑得起来的最小样例」。

💡 数据库选择说明:初期用 H2 嵌入式数据库是为了前期学习方便——零安装、clone 即跑、数据文件随仓库走。后期学习到阶段三(MySQL / ORM)时,按文末「学习扩展点」切换到 MySQL 即可(引驱动 + 改一处 datasource url,H2 的 MODE=MySQL 已提前对齐 MySQL 方言,切换成本最低)。

技术栈与版本

组件 版本 对应文档
Java 25(LTS) 阶段零 02 讲(环境基线)
Spring Boot 4.0.0 阶段二 02 讲(BOM 示例同款)
MyBatis-Plus 3.5.17(Boot 4 专用 starter + jsqlparser) 阶段三第 2 讲(ORM)
H2 BOM 托管(嵌入式,免安装) 阶段二 05 讲(「仿制数据库」)
JJWT 0.13.0 M1-06(HS256 登录令牌)
Spring Security 7.0.0(由 Boot BOM 托管) M1-07(无状态 JWT 认证)
SpringDoc OpenAPI 3.1.1 M1-09(OpenAPI JSON + Swagger UI)
Maven 3.9.16(Maven Wrapper 自带,无需安装 阶段二 02 讲(聚合工程范式)

模块结构

boot-server/
├── pom.xml                          # 聚合父 pom:锁版本(BOM 范式)+ 声明模块
├── infrastructure/                  # 公共底座(打包为普通 jar,被业务服务引用)
│   └── common-core/                 # 统一响应体 Result 等通用组件(纯 Java,零框架依赖)
└── services/                        # 业务服务(每个都是可独立部署的 Spring Boot 应用)
    └── user-service/                # 用户服务(后续 order-service 等平级并列)
        ├── pom.xml
        └── src/main/
            ├── java/com/example/bootserver/
            │   ├── BootServerApplication.java # 入口(@SpringBootApplication)
            │   ├── controller/UserController # REST CRUD(统一响应体)
            │   ├── service/UserService       # 业务层(MP ServiceImpl)
            │   ├── mapper/UserMapper         # 数据层(MP BaseMapper)
            │   ├── entity/User               # 实体(@TableName + @TableLogic)
            │   └── config/MybatisPlusConfig  # 分页插件(H2 方言)
            └── resources/
                ├── application.yml           # 配置:H2 文件库 + 逻辑删除 + SQL 打印
                └── db/schema.sql             # 建表 + 初始数据(随仓库提交,启动自动执行)

布局说明:infrastructure/(技术底座)与 services/(业务服务)分层,是微服务工程化的标准形态——底座模块可被多个服务复用,服务之间相互独立、可单独构建部署。当前只有一个 user-service,后续加服务(如 order-service)平级放在 services/ 下即可。

快速开始

环境要求:JDK 25 与一个运行时 JWT 密钥。本仓库自带 Maven Wrappermvnw / mvnw.cmd),不需要安装 Maven。启动前生成一次本机密钥(不提交):

export JWT_SECRET_BASE64="$(openssl rand -base64 32)"

密钥通过环境变量注入,缺失时应用会在启动阶段拒绝运行;测试使用独立假密钥,不依赖本机环境变量。

方式一:IDEA(推荐)

  1. File → Open 选择 boot-server/pom.xml,以 Maven 工程打开(IDEA 自动识别 wrapper 与 JDK)
  2. 首次打开等待依赖下载(国内网络慢可先配阿里云镜像,见阶段零 02 讲
  3. 直接运行 BootServerApplication 的 main 方法

方式二:命令行(无需安装 Maven)

Windows 用 mvnw.cmd,macOS / Linux 用 ./mvnw(下面以 Windows 为例):

cd boot-server
# ① 构建并安装全部模块(首次 / 改动了 pom 后执行)
mvnw.cmd -pl services/user-service -am install -DskipTests
# ② 启动应用(注意:不要带 -am,run 只对服务模块执行)
mvnw.cmd -pl services/user-service spring-boot:run

小坑备忘:spring-boot:run-am 会把启动目标也跑到聚合父 pom 上(父模块没有 main 类会报错),所以启动单独一条命令。已装全局 Maven 3.9+ 的机器直接用 mvn 替换 mvnw.cmd 同样可行。

启动成功后控制台会打印 SQL(学习期特意打开),访问:

  • 公开接口:http://localhost:8080/api/auth/login
  • 受保护接口:http://localhost:8080/api/users/me(需 Authorization: Bearer <token>
  • 接口文档:http://localhost:8080/api/swagger-ui/index.html(OpenAPI JSON:http://localhost:8080/api/v3/api-docs
  • H2 控制台:本地需要时先执行 export H2_CONSOLE_ENABLED=true,再访问 http://localhost:8080/h2-console(JDBC URL 填 jdbc:h2:file:../../data/bootapp;MODE=MySQL,用户 sa,密码留空——与 datasource 一致,相对服务模块工作目录)
  • 数据库文件:boot-server/data/(随工程走,可提交记录——学习期每次实验的库状态都留档,方便回看 diff 与回滚;首次启动自动建表灌初始数据,data/ 已有数据则保留历史

本地管理员测试账号(M1-C-05)

管理接口(如 GET /api/users)需要 user:manage 权限,公开注册只能得到 USER 角色(访问返回 403)。本地验收需要管理员时,通过环境变量在启动时引导,不需要手工改数据库:

export BOOT_ADMIN_USERNAME="boot-admin"
export BOOT_ADMIN_PASSWORD="你的本地密码"   # 自选,不提交、不写进任何文件

行为说明:

  • 两个变量必须同时提供(只填一项会在启动时报配置错误);都不设置时引导不执行,生产环境不设置即不会创建任何管理员
  • 账号不存在时自动创建并绑定 ADMIN 角色;已存在时只补缺失的角色关联——重复启动幂等,不会重复建号,也不覆盖已有数据。
  • 密码只经 BCrypt 哈希后落库,不写入日志、代码或文档。

验证(配合上方启动命令):

# 登录引导账号,取响应里的 accessToken
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"boot-admin","password":"你的本地密码"}'
# 管理员访问用户列表应得到 200 / code:0;普通 USER 账号访问则得到 403 / 40300
curl http://localhost:8080/api/users -H "Authorization: Bearer <accessToken>"

接口一览

统一接口前缀spring.mvc.servlet.pathapplication.yml 中配置为 /api。Controller 仅声明资源路径(例如 /users),因此外部接口为 /api/users;后期调整为 /api/v1 时只修改该配置,不逐个修改 Controller。H2 Console 保持 http://localhost:8080/h2-console,不受 MVC 前缀影响。

方法 路径 说明
GET /api/users/me 当前 JWT 对应的用户 ID(需认证)
GET /api/users 列表(需 user:manage,自动过滤已逻辑删除)
GET /api/users/page?page=1&size=10 分页(需 user:manage
GET /api/users/by-name?name=xx 名称模糊查询(需 user:manage
GET /api/users/{id} 详情(需 user:manage;不存在返回 40400)
POST /api/users 新增(需 user:manage,body 传 JSON)
PUT /api/users/{id} 更新(需 user:manage
DELETE /api/users/{id} 逻辑删除(需 user:manage,UPDATE deleted=1)
POST /api/auth/register 注册用户并默认绑定 USER 角色
POST /api/auth/login 校验用户名和密码,返回短期 JWT

接口验证(curl)

# 注册并登录,响应 data.accessToken 是访问受保护接口的 Bearer token
curl -X POST http://localhost:8080/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"username":"dave","email":"dave@example.com","password":"secret123"}'
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"dave","password":"secret123"}'

# 将登录响应中的 accessToken 复制为 TOKEN;无 token 访问 /api/users 会得到 401/40100
TOKEN="替换为登录响应中的 accessToken"
curl http://localhost:8080/api/users/me -H "Authorization: Bearer $TOKEN"
curl http://localhost:8080/api/users -H "Authorization: Bearer $TOKEN"

与文档的对应关系(学到这里回来对照)

工程里的东西 文档
Result 统一响应体 / RESTful 风格 阶段二 03 讲「统一响应体与 API 设计」
@SpringBootApplication / 多模块聚合 阶段二 02 讲「Boot 实战 / 聚合工程」
@Service Bean / 构造器注入 / 自动装配 阶段二 01 讲 + 阶段零 05 讲「Bean 是什么」
Mapper 接口无实现类却能查库 阶段二 01 讲「框架魔法解密」(动态代理)
H2(「仿制数据库」) 阶段二 05 讲测试工程
逻辑删除字段 deleted 阿里规约(阶段零 02 讲)+ MyBatis-Plus 全局配置
分页插件(jsqlparser) 阶段三(ORM 数据访问)预告

学习扩展点(自己动手)

  • application.ymllog-impl 换成 org.apache.ibatis.logging.slf4j.Slf4jImpl,感受日志门面(阶段二 02 讲 SLF4J)
  • 换 MySQL:引入 mysql-connector-j 依赖 + 改 datasource URL,体验「H2 和 MySQL 只差一处配置」
  • 给 UserService 加一个带 @Transactional 的方法,然后故意抛异常看回滚(阶段二 01 讲)