# 七、本地跑通 saas-starter 本章在本地把 `saas-starter` 当作真实业务 SaaS 跑起来,先验收 SaaS 自身,不拼完整支付链路。 ```{important} 🎯 **重要:本章目标:** 证明 SaaS 能启动、能连业务库、能创建匿名会话,且已写入后续调用 web-pay 所需的商户号与应用身份。 **本章做到这些即可:** - 本地 SaaS 后端、前端可访问 - 业务库连接正常 - 匿名会话可创建 - `mchNo`、`appId`、`AppSecret` 已写入配置 **本章不做:** - 创建支付订单、跳转收银台、验证支付通知 - 把本机 SaaS、本机收银台、本机运营平台拼成支付闭环 **为什么先不拼本地支付闭环:** 完整支付依赖收银台、支付网关 API、运营平台商户/应用/通道、支付平台公网回调和 SaaS 通知地址。本章先证明 SaaS 自身可用,避免把端口、隧道、跨域、回调地址等问题提前混在一起。 **推荐顺序:** 第 8 章先完成 web-pay 上线配置 → 第 9 章回到本机,集中验证 `saas-starter` 下单、收银台、付款回调与业务订阅更新。 ``` ## 7.1 saas-starter 脚本速读 `saas-starter` 的脚本都在 `saas-starter/env-scripts/`: ```{tip} 🧰 **先认脚本,再启动 SaaS。** 本章主要用配置脚本、后端启动脚本和停止脚本;生产构建和上传脚本等线上部署时再处理。 ``` | 脚本 | 作用 | 什么时候用 | | --- | --- | --- | | `rename-saas-service.sh` | 写入 SaaS 前后端配置、少量前端展示文案和上传脚本 SSH 默认值 | 第一次配置 SaaS 或调整部署信息时 | | `start-local-test-backend.sh` | 构建并启动 SaaS 后端,创建 cloudflared 隧道,生成 `logs/application-local-tunnel.yml` | 本地跑 SaaS 后端;第 9 章验证支付通知时也会用到 | | `stop.sh` | 停止 SaaS 本地后端和 cloudflared 隧道;如果你用 CLI 启动前端,也可按实际端口清理前端进程 | 本地联调结束或端口冲突时 | | `build-prod-backend.sh` | 生产方式构建 `backend/target/saas-starter.jar` | 线上部署前构建后端 | | `build-prod-frontend.sh` | 生产方式构建 H5 前端 `frontend/dist` | 线上部署前构建前端 | | `upload-saas-backend-jars.sh` | 上传 `backend/target/saas-starter.jar` 到云服务器 | 后端生产构建完成后,需要把 SaaS 后端 Jar 上传到服务器时 | ![saas-starter 本地与部署脚本分工](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-19-071-script-map.png) ```{warning} ⚠️ 本章不要先跑生产构建和上传脚本。先确认本地 SaaS 后端、H5 前端和业务库连接正常,再进入后续线上部署章节。 ``` ## 7.2 执行 saas-starter 配置脚本 SaaS 示例项目有自己的配置脚本: ```text saas-starter/env-scripts/rename-saas-service.sh ``` ```{important} 📌 **这一步会把第 3 章和第 6 章记录的信息写入 SaaS 配置。** 尤其是 `mchNo`、`appId`、`AppSecret`,后面 SaaS 调用 web-pay 都依赖这组值。 ``` 运行前先准备 03 章里的 `saas-starter-deploy-info.md`,脚本会按下面顺序询问: | 脚本会询问 | 示例 | 说明 | | --- | --- | --- | | 服务名 | `saas-starter` | 只能使用小写字母、数字和中划线;空值默认 `saas-starter` | | 根域名 | `example.cn` | **自己申请的根域名**,脚本会自动生成 SaaS 前端和后端域名 | | 收银台前端域名 | `pay.example.cn` | **与web-pay配置一致**,填 web-pay 统一收银台前端域名,不需要写 `https://` | | 收银台后端域名 | `pay-api.example.cn` | **与web-pay配置一致**,填 web-pay 支付网关后端域名,不需要写 `https://` | | PostgreSQL 内网连接地址(不含端口) | `192.168.1.100` | **与web-pay配置一致**,云服务器线上运行用;写入 SaaS `application.yml` | | PostgreSQL 公网连接地址(不含端口) | `123.45.67.89` | **与web-pay配置一致**,本机联调用;写入 SaaS `application-local.yml` | | PostgreSQL 数据库名称 | `saas_starter` | **与web-pay配置一致**,必须和 RDS 中新建的 SaaS 业务库一致 | | 数据库用户名和密码 | 你的 RDS 业务用户 | **与web-pay配置一致**,写入 SaaS 后端配置 | | SSH 账户地址 / 账户 / 密码 | `12.34.56.78` / `root` / `自行填写强密码` | **与web-pay配置一致**,写入 `upload-saas-backend-jars.sh` 的默认值 | | Zhcpay 商户号、AppID、AppSecret | web-pay 运营平台应用信息 | SaaS 后端调用 web-pay 时使用 | ```{note} 💡 如果你本章只是先跑通教程,服务名可以直接回车保留 `saas-starter`,不用真的改成新产品名。 ``` ```{danger} 🔐 **脚本会写入敏感配置。** 数据库密码、SSH 信息和 web-pay `AppSecret` 只应该保存在你控制的本地环境或私有仓库中,不要放进公开截图、公开文档或前端可见配置。 ``` 在 SaaS 项目目录执行: ```bash cd saas-starter chmod +x ./env-scripts/rename-saas-service.sh ./env-scripts/rename-saas-service.sh ``` 脚本执行完成后会直接写入这些文件: | 文件 | 写入内容 | | --- | --- | | `backend/src/main/resources/application.yml` | 生产后端端口 `9220`、PostgreSQL 内网 JDBC、Zhcpay 身份、收银台前后端 URL、SaaS 生产站点和通知地址 | | `backend/src/main/resources/application-local.yml` | 本地后端端口 `9220`、PostgreSQL 公网 JDBC、Zhcpay 身份、收银台前后端 URL、本地站点 `http://localhost:5173` | | `frontend/.env` | 生产 SaaS API Base 和前端展示名 | | `frontend/.env.development` | 本地 SaaS API Base `http://localhost:9220/api/v1` 和开发展示名 | | `env-scripts/upload-saas-backend-jars.sh` | SSH 账户地址、账户和密码默认值 | 脚本还会替换少量用户可见的 `SaaS Starter` 前端展示文案,例如浏览器标题、关于页、协议/隐私文案。它不会修改 Java 包名、Maven `artifactId`、`backend/target/saas-starter.jar`、数据库表名或本地存储 key。 ![saas-starter 配置脚本写入前后端配置](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-20-072-config-script.png) ```{tip} 💡 如果后面重新运行配置脚本,已经启动的 SaaS 后端需要重启才会读取新的 Spring 配置;前端 `.env` 变化也要重新运行 H5 前端。 ``` ## 7.3 启动前检查 确认: ```{warning} ⚠️ **这些项通过后再启动 SaaS。** 如果业务库、支付身份或配置脚本有一项没准备好,后端可能能启动,但页面接口或后续支付联调会很快报错。 ``` - 第 5 章已经确认 web-pay 本地服务可启动。 - 第 6 章已经创建商户和应用,并把 `mchNo`、`appId`、`AppSecret` 记录到 `saas-starter-deploy-info.md`。 - RDS 中已经创建 SaaS 业务库,例如 `saas_starter`。业务库可以是空库,启动脚本会自动检查并初始化 SaaS 基础业务表。 - 已按 7.2 执行 `saas-starter/env-scripts/rename-saas-service.sh`,脚本已经把配置直接写入前后端配置文件。 - `saas-starter/backend/src/main/resources/application-local.yml` 能连接 SaaS 业务库。 ![SaaS 本地启动前检查项](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-21-073-preflight-check.png) ## 7.4 配置 SaaS 支付身份 SaaS 后端调用 web-pay 时,必须带上 web-pay 运营平台里创建的应用身份。 ![SaaS 后端调用 web-pay 的应用身份](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-22-074-payment-identity.png) 这些值已经由 7.2 的配置脚本直接写入 `saas-starter/backend/src/main/resources/application-local.yml` 和 `application.yml`。你可以检查本地配置: ```yaml zhcpay: mch-no: "你的商户号" app-id: "web-pay运营平台应用AppId" app-secret: "web-pay运营平台应用AppSecret" ``` ```{important} 🎯 **SaaS 支付身份只属于后端。** 前端页面不需要知道 `AppSecret`;它只负责请求 SaaS 后端,由 SaaS 后端再用这组身份调用 web-pay。 ``` 这些值来自第 6 章的本地支付配置。如果你还没创建应用,先回到第 6 章创建商户和应用,再重新执行 7.2 的配置脚本并重启 SaaS 后端。 ```{warning} ⚠️ `mch-no`、`app-id`、`app-secret` 必须来自同一个 web-pay 应用。混用不同应用的值时,常见表现是创建订单失败、签名校验失败,或第 9 章回调通知无法被 SaaS 正确验签。 ``` ## 7.5 启动 SaaS 后端 进入 `saas-starter`,直接启动后端: ```bash cd saas-starter ./env-scripts/start-local-test-backend.sh ``` 脚本会做这些事: ```{important} 🚀 **这一步只启动 SaaS 后端。** SaaS 前端仍然需要用 HBuilderX 单独运行;后端脚本不会替你打开 H5 页面。 ``` | 动作 | 说明 | | --- | --- | | 构建后端 Jar | 输出 `backend/target/saas-starter.jar` | | 检查并初始化数据库 | 读取 `application-local.yml` 的 PostgreSQL 连接,缺少 `t_user`、`t_saas_pay_order`、`t_vip_subscription`、`t_redeem_code` 时自动执行 `backend/sql/init_pg.sql` | | 启动 SaaS 后端 | 默认 `http://localhost:9220` | | 创建 cloudflared 隧道 | 把本机 `9220` 暴露为公网通知地址 | | 写入通知覆盖配置 | 生成 `logs/application-local-tunnel.yml` | | 写入前端公网提示 | 生成 `frontend/.env.development.local`,其中公网 `VITE_API_BASE_URL` 默认保持注释 | ![SaaS 后端本地启动流程](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-23-075-backend-start-flow.png) `logs/application-local-tunnel.yml` 会把 `zhcpay.notify-url` 覆盖成本次 cloudflared 公网地址。这个地址是第 9 章验证支付通知时使用的准备项;本章只确认文件生成和 SaaS 后端正常启动。 ```{note} 📌 本章看到 cloudflared 地址生成即可,不用急着拿它做支付通知验收。真正验证 web-pay 回调 SaaS 的链路放到第 9 章。 ``` ```{warning} ⚠️ 每次重启后端脚本都可能生成新的 SaaS cloudflared 地址。第 9 章如果要用本机 SaaS 接收通知,必须以本次启动生成的 `logs/application-local-tunnel.yml` 为准。 ``` ## 7.6 启动 SaaS 前端 SaaS 前端是 **uni-app H5 项目**。uni-app 是 DCloud 推出的跨端前端框架,写法接近 Vue,同一套页面和业务代码可以按需要编译到 H5、微信小程序、App 等不同端。本教程当前主流程只要求跑通 H5,也就是浏览器里的 SaaS 页面。 ```{note} 📌 这里说的 “H5” 可以先理解成普通网页版本。后面部署到线上时,`build-prod-frontend.sh` 生成的 `frontend/dist` 就是给 Nginx、对象存储或 CDN 托管的 H5 静态文件。 ``` uni-app 对这个 SaaS 模板的好处主要有: | 优势 | 对本教程有什么用 | | --- | --- | | Vue 风格开发 | 页面、组件、状态组织都比较接近常见前端开发方式,新手上手成本低 | | 多端能力预留 | 当前先跑 H5,以后如果要扩展小程序或 App,不用从零重写整套页面 | | 页面配置集中 | `pages.json` 统一管理页面路由、标题和导航栏配置 | | 构建产物清晰 | 生产构建后输出 `frontend/dist`,方便接入 CDN 或静态托管 | | 和 HBuilderX 集成好 | 可以直接“运行到浏览器”,适合本地调试和查看控制台输出 | ```{important} 💡 本教程优先推荐用 HBuilderX 启动 SaaS 前端,不是因为命令行不能跑,而是因为 HBuilderX 对 uni-app 的项目识别、运行到浏览器、控制台日志和内置编译链路更完整,新手少踩环境坑。 ``` HBuilderX 是 DCloud 官方 IDE。你可以把它理解成“专门为 uni-app 做了深度集成的编辑器”:它能识别 `frontend` 里的 uni-app 配置,提供运行、编译、预览、控制台日志等入口。你不需要先理解所有前端构建细节,先把页面跑起来、确认接口能访问即可。 ![HBuilderX 启动 uni-app H5 并连接本地 API](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-24-076-frontend-h5-flow.png) ```{tip} 📁 第一次打开项目时,请打开 `saas-starter/frontend` 这个目录,不要打开整个 `web-pay` 仓库根目录。HBuilderX 需要从前端项目目录识别 `pages.json`、`manifest.json` 和 `package.json`。 ``` 推荐用 HBuilderX 启动: 1. 打开 HBuilderX。 2. 选择 `文件` -> `打开目录`,打开 `saas-starter/frontend`。 3. 选择 `运行` -> `运行到浏览器` -> `Chrome` 或你常用的浏览器。 4. 以 HBuilderX 控制台输出的地址为准,默认通常是: ```text http://localhost:5173 ``` ```{tip} 💡 如果 HBuilderX 提示安装浏览器运行插件、uni-app 编译插件或相关依赖,按提示安装即可。运行成功后,重点看 HBuilderX 控制台输出的本地访问地址,不要只凭记忆猜端口。 ``` 如果前端接口报错,检查: ```text saas-starter/frontend/.env.development saas-starter/frontend/.env.development.local ``` ```{important} 🎯 本机浏览器联调时 API 应该指向 `http://localhost:9220/api/v1`。`frontend/.env.development.local` 里的公网 API 默认保持注释,只有真机或公网环境需要直接访问 cloudflared API 时才取消注释。 ``` ## 7.7 本地页面验收 7.5、7.6 启动完成后,在浏览器打开 SaaS H5,做本章最后一轮肉眼确认。 ```{important} ✅ **页面能打开且接口正常,就说明 SaaS 本地链路通过。** 本章不验证支付下单和收银台跳转;那部分放到第 9 章统一验收。 ``` **建议至少点开这些页面:** | 页面 | 在本项目里对应什么 | 过关信号 | | --- | --- | --- | | **我的** | H5 默认首页,展示昵称与功能入口 | 页面不白屏,头像区与菜单能渲染 | | **续费管理** | 首页功能入口进入 | 订阅状态卡片能加载,无持续 loading | | **开通专业版** | 订阅方案页 | 套餐列表能显示;此时不要求点支付 | | **设置** | 通用功能入口进入 | 静态页与路由跳转正常 | **再确认两件事:** - 首次打开时,浏览器网络面板或 `logs/backend.local.log` 里能看到 `POST /api/v1/session/anonymous`,说明匿名会话已创建。 - 后端日志没有数据库连接失败、端口占用或启动异常堆栈。 ```{tip} 🧪 页面白屏或接口报错时,先对照 7.6 检查 `frontend/.env.development` 里的 `VITE_API_BASE_URL` 是否指向 `http://localhost:9220`,再查 `logs/backend.local.log`。 ``` ![SaaS 本地 H5 页面验收边界](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-25-077-page-acceptance.png) ![SaaS 本地 H5:我的与续费管理](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/Saas-01.png) ![SaaS 本地 H5:开通专业版与设置](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/Saas-02.png) ## 7.8 停止 SaaS 本地服务 后端和隧道用脚本停止: ```bash cd saas-starter ./env-scripts/stop.sh ``` 如果前端是 HBuilderX 启动的,在 HBuilderX 里停止运行即可。 ```{tip} 💡 后端配置、数据库连接、Zhcpay 身份或 `logs/application-local-tunnel.yml` 变化后,重启 SaaS 后端;前端 `.env` 变化后,重启 HBuilderX 里的 H5 运行任务。 ``` ![停止 SaaS 本地后端、隧道与前端运行](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-26-078-stop-logs.png) 常用日志: ```text saas-starter/logs/backend.local.log saas-starter/logs/backend.local.tunnel.log saas-starter/logs/application-local-tunnel.yml ``` ```{warning} ⚠️ 如果页面仍然在请求旧地址,先确认 HBuilderX 已停止并重新运行,再清理浏览器缓存或打开无痕窗口复测。 ``` ## 7.9 本章完成标准 ```{important} ✅ **本章完成后,只证明 SaaS 自身本地可用。** 支付订单、收银台跳转和支付通知不要在这里硬验收,否则会把第 9 章的完整支付链路问题提前混进来。 ``` - [ ] 已执行 SaaS 配置脚本,配置已写入 `application-local.yml`、`application.yml`、前端 `.env` 文件。 - [ ] `http://localhost:9220/api/health` 可访问。 - [ ] `http://localhost:5173` 或 HBuilderX 输出的 H5 地址能打开 SaaS 前端。 - [ ] SaaS 后端日志没有数据库连接错误。 - [ ] SaaS 配置中 `api-base-url`、`cashier-base-url` 已写入第 3 章规划的 web-pay 线上域名。 - [ ] 已理解本章不要求本机 SaaS 与本机收银台/运营平台完成支付闭环。 - [ ] SaaS H5 首次打开可以创建匿名会话。 - [ ] 本章不要求支付订单跳转成功;支付闭环统一放到第 9 章验证。 ![本地跑通 saas-starter 的完成标准](https://image-osb.obs.cn-east-3.myhuaweicloud.com/OPC%E5%9B%BE%E5%BA%93/index-27-079-completion-standard.png) ```{seealso} ➡️ 下一步进入第 8 章,把 web-pay 的线上部署方式跑通。第 9 章再回到本机,让 `saas-starter` 创建订单并完成支付闭环验收。 ```