七、本地跑通 saas-starter
本章在本地把 saas-starter 当作真实业务 SaaS 跑起来,先验收 SaaS 自身,不拼完整支付链路。
重要
🎯 重要:本章目标: 证明 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/:
小技巧
🧰 先认脚本,再启动 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 后端、H5 前端和业务库连接正常,再进入后续线上部署章节。
7.2 执行 saas-starter 配置脚本
SaaS 示例项目有自己的配置脚本:
saas-starter/env-scripts/rename-saas-service.sh
重要
📌 这一步会把第 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 时使用 |
备注
💡 如果你本章只是先跑通教程,服务名可以直接回车保留 saas-starter,不用真的改成新产品名。
危险
🔐 脚本会写入敏感配置。 数据库密码、SSH 信息和 web-pay AppSecret 只应该保存在你控制的本地环境或私有仓库中,不要放进公开截图、公开文档或前端可见配置。
在 SaaS 项目目录执行:
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 后端需要重启才会读取新的 Spring 配置;前端 .env 变化也要重新运行 H5 前端。
7.3 启动前检查
确认:
警告
⚠️ 这些项通过后再启动 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 业务库。

7.4 配置 SaaS 支付身份
SaaS 后端调用 web-pay 时,必须带上 web-pay 运营平台里创建的应用身份。

这些值已经由 7.2 的配置脚本直接写入 saas-starter/backend/src/main/resources/application-local.yml 和 application.yml。你可以检查本地配置:
zhcpay:
mch-no: "你的商户号"
app-id: "web-pay运营平台应用AppId"
app-secret: "web-pay运营平台应用AppSecret"
重要
🎯 SaaS 支付身份只属于后端。 前端页面不需要知道 AppSecret;它只负责请求 SaaS 后端,由 SaaS 后端再用这组身份调用 web-pay。
这些值来自第 6 章的本地支付配置。如果你还没创建应用,先回到第 6 章创建商户和应用,再重新执行 7.2 的配置脚本并重启 SaaS 后端。
警告
⚠️ mch-no、app-id、app-secret 必须来自同一个 web-pay 应用。混用不同应用的值时,常见表现是创建订单失败、签名校验失败,或第 9 章回调通知无法被 SaaS 正确验签。
7.5 启动 SaaS 后端
进入 saas-starter,直接启动后端:
cd saas-starter
./env-scripts/start-local-test-backend.sh
脚本会做这些事:
重要
🚀 这一步只启动 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 默认保持注释 |

logs/application-local-tunnel.yml 会把 zhcpay.notify-url 覆盖成本次 cloudflared 公网地址。这个地址是第 9 章验证支付通知时使用的准备项;本章只确认文件生成和 SaaS 后端正常启动。
备注
📌 本章看到 cloudflared 地址生成即可,不用急着拿它做支付通知验收。真正验证 web-pay 回调 SaaS 的链路放到第 9 章。
警告
⚠️ 每次重启后端脚本都可能生成新的 SaaS cloudflared 地址。第 9 章如果要用本机 SaaS 接收通知,必须以本次启动生成的 logs/application-local-tunnel.yml 为准。
7.6 启动 SaaS 前端
SaaS 前端是 uni-app H5 项目。uni-app 是 DCloud 推出的跨端前端框架,写法接近 Vue,同一套页面和业务代码可以按需要编译到 H5、微信小程序、App 等不同端。本教程当前主流程只要求跑通 H5,也就是浏览器里的 SaaS 页面。
备注
📌 这里说的 “H5” 可以先理解成普通网页版本。后面部署到线上时,build-prod-frontend.sh 生成的 frontend/dist 就是给 Nginx、对象存储或 CDN 托管的 H5 静态文件。
uni-app 对这个 SaaS 模板的好处主要有:
| 优势 | 对本教程有什么用 |
|---|---|
| Vue 风格开发 | 页面、组件、状态组织都比较接近常见前端开发方式,新手上手成本低 |
| 多端能力预留 | 当前先跑 H5,以后如果要扩展小程序或 App,不用从零重写整套页面 |
| 页面配置集中 | pages.json 统一管理页面路由、标题和导航栏配置 |
| 构建产物清晰 | 生产构建后输出 frontend/dist,方便接入 CDN 或静态托管 |
| 和 HBuilderX 集成好 | 可以直接“运行到浏览器”,适合本地调试和查看控制台输出 |
重要
💡 本教程优先推荐用 HBuilderX 启动 SaaS 前端,不是因为命令行不能跑,而是因为 HBuilderX 对 uni-app 的项目识别、运行到浏览器、控制台日志和内置编译链路更完整,新手少踩环境坑。
HBuilderX 是 DCloud 官方 IDE。你可以把它理解成“专门为 uni-app 做了深度集成的编辑器”:它能识别 frontend 里的 uni-app 配置,提供运行、编译、预览、控制台日志等入口。你不需要先理解所有前端构建细节,先把页面跑起来、确认接口能访问即可。

小技巧
📁 第一次打开项目时,请打开 saas-starter/frontend 这个目录,不要打开整个 web-pay 仓库根目录。HBuilderX 需要从前端项目目录识别 pages.json、manifest.json 和 package.json。
推荐用 HBuilderX 启动:
打开 HBuilderX。
选择
文件->打开目录,打开saas-starter/frontend。选择
运行->运行到浏览器->Chrome或你常用的浏览器。以 HBuilderX 控制台输出的地址为准,默认通常是:
http://localhost:5173
小技巧
💡 如果 HBuilderX 提示安装浏览器运行插件、uni-app 编译插件或相关依赖,按提示安装即可。运行成功后,重点看 HBuilderX 控制台输出的本地访问地址,不要只凭记忆猜端口。
如果前端接口报错,检查:
saas-starter/frontend/.env.development
saas-starter/frontend/.env.development.local
重要
🎯 本机浏览器联调时 API 应该指向 http://localhost:9220/api/v1。frontend/.env.development.local 里的公网 API 默认保持注释,只有真机或公网环境需要直接访问 cloudflared API 时才取消注释。
7.7 本地页面验收
7.5、7.6 启动完成后,在浏览器打开 SaaS H5,做本章最后一轮肉眼确认。
重要
✅ 页面能打开且接口正常,就说明 SaaS 本地链路通过。 本章不验证支付下单和收银台跳转;那部分放到第 9 章统一验收。
建议至少点开这些页面:
| 页面 | 在本项目里对应什么 | 过关信号 |
|---|---|---|
| 我的 | H5 默认首页,展示昵称与功能入口 | 页面不白屏,头像区与菜单能渲染 |
| 续费管理 | 首页功能入口进入 | 订阅状态卡片能加载,无持续 loading |
| 开通专业版 | 订阅方案页 | 套餐列表能显示;此时不要求点支付 |
| 设置 | 通用功能入口进入 | 静态页与路由跳转正常 |
再确认两件事:
首次打开时,浏览器网络面板或
logs/backend.local.log里能看到POST /api/v1/session/anonymous,说明匿名会话已创建。后端日志没有数据库连接失败、端口占用或启动异常堆栈。
小技巧
🧪 页面白屏或接口报错时,先对照 7.6 检查 frontend/.env.development 里的 VITE_API_BASE_URL 是否指向 http://localhost:9220,再查 logs/backend.local.log。


7.8 停止 SaaS 本地服务
后端和隧道用脚本停止:
cd saas-starter
./env-scripts/stop.sh
如果前端是 HBuilderX 启动的,在 HBuilderX 里停止运行即可。
小技巧
💡 后端配置、数据库连接、Zhcpay 身份或 logs/application-local-tunnel.yml 变化后,重启 SaaS 后端;前端 .env 变化后,重启 HBuilderX 里的 H5 运行任务。

常用日志:
saas-starter/logs/backend.local.log
saas-starter/logs/backend.local.tunnel.log
saas-starter/logs/application-local-tunnel.yml
警告
⚠️ 如果页面仍然在请求旧地址,先确认 HBuilderX 已停止并重新运行,再清理浏览器缓存或打开无痕窗口复测。
7.9 本章完成标准
重要
✅ 本章完成后,只证明 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 章验证。

参见
➡️ 下一步进入第 8 章,把 web-pay 的线上部署方式跑通。第 9 章再回到本机,让 saas-starter 创建订单并完成支付闭环验收。