☰
TigShop双后端三前端架构解析:Spring Boot与ThinkPHP多端商城实践
2026/10/9 13:23:40 网站建设 项目流程

简介:TigShop开源商城系统是一套基于SpringBoot3与TP8后端、结合Vue3、TypeScript、Uniapp、Vite、Nuxt3、Element Plus前端框架的电商平台源码,面向需要自建商城或研究现代前后端分离架构的开发者。资源包共2000个文件,大小约105.23MB,其中634个vue组件与598个js脚本构成主要前端逻辑,303个css负责界面样式,另有405个md文档提供阅读与开发指引,以及sql数据库脚本、json配置和html页面等,目录结构完整,便于局部检索与整体学习。目前已有252人学习下载。包内附带安装配置、系统构建、功能模块介绍、接口说明等文档,可指导从开发环境搭建到部署上线的完整流程;源码基于分层模块组织,适合学习SpringBoot3与Vue3的整合方式,也能作为电商项目二次开发的参考起点。对于想掌握主流全栈技术选型或需要开源商城基座的开发者,这是一份结构清晰、实用性较强的资源。

1. TigShop 商城系统的第一印象:双后端 + 三前端,一套包把落地方式拆给你看

第一次打开 TigShop 这个开源商城 zip 包时,最意外的不是 Vue3、Nuxt3、Uniapp 三套前端齐活,而是后端目录里同时躺着 Spring Boot 3 和 ThinkPHP 8 两套实现。这不是重复造轮子,而是按场景分工:Spring Boot 3 管订单、库存、支付这类强事务链路,TP8 管 CMS、活动页这类高频改版的轻业务。

对需要同时维护 PC 管理端、SSR 商城页和跨端小程序的团队来说,这套包相当于把选型、对接和联调过程一起拆给你看。两个后端共用一套 MySQL 和 Redis,三套前端共享 TypeScript 业务逻辑,整个架构可以直接照着抄作业。

如果你正在做多端商城改造,或者需要一个前后端分离、多端分发的完整参考实现,这个包很适合先解压跑通,再按自己的业务改。后面各章我就按“拆结构 → 跑起来 → 二次开发 → 排坑”的顺序过一遍。

2. TigShop 技术栈拆解:双后端与三前端的定位、目录结构与运行前提

2.1 双后端的边界:Spring Boot 3 管钱,TP8 管内容

这个包最值得先看明白的是两个后端各自管什么。Spring Boot 3 端承载的是核心交易域——商品 SKU、购物车、订单状态机、支付回调、退款流程。这些链路对事务边界、分布式锁和消息补偿要求高,Java 侧用 @Transactional 配合 Redis 分布式锁是稳妥做法。TP8 端则负责运营域——首页装修、文章资讯、优惠券活动页、用户反馈,这类需求经常要在一两天内改版上线,PHP 的“改完即跑”节奏明显更顺手。

选型时不要犯“一个后端包打天下”的错误。常见翻车场景是:图省事把订单也放在 TP8 里写,结果促销峰值时 MySQL 连接数被打满,又不方便上成熟的分布式事务方案。反过来把活动页放 Spring Boot 里,光是排版数据的表结构就要设计半天。TigShop 的做法更实际:两套后端虽然业务独立,但共用同一套 MySQL 逻辑库和 Redis,通过 API 网关按路径分流,/order、/pay 开头走 Java,/cms、/activity 开头走 PHP。

两个后端读写的是同一套核心表。比如用户表和订单表由 Java 端负责写入,TP8 端在 CMS 后台展示用户列表、订单数量时只读这些表。为避免两边同时改同一行造成锁竞争,他们遵循一个朴素约定:写操作归属方唯一。Java 端写订单状态,TP8 端写活动配置。如果业务上非要 PHP 改订单状态,一律走 Java 端提供的 API,而不是直接连表 UPDATE。这个约定不写进代码,但要在团队规范里写明,否则并发一上来就分不清是谁改了字段。

2.2 三套前端为什么并存:管理端、SSR 商城页与跨端 App 的分工

Vue3 + TypeScript + Element Plus + Vite 的组合管的是 PC 管理后台。Element Plus 的表格、表单、弹窗组件能快速搭出订单列表、SKU 编辑、权限分配这些中后台页面。Nuxt3 管的是商城前台,它内置 SSR,商品详情页能返回完整 HTML,对搜索引擎友好,Vue3 代码可以复用管理端封装的业务逻辑。Uniapp 是最后一条线,同一套 Vue3 代码编译到微信小程序、H5 和 App,适合团队没有精力维护三套原生客户端的情况。

这套结构里 Vite 的角色容易被忽视。管理端和 Nuxt 端的构建都依赖 Vite,而且都启用了 TypeScript 路径别名,比如 @/ 指向 src 目录,两端的 tsconfig.json 配置一致,这直接影响到二次开发时复制组件是否会有路径报错。首次熟悉包时建议先看三个前端各自的 package.json scripts,确认 dev、build、type-check 命令的写法。

三端并非三份重复代码。包内通常把纯 TS 业务逻辑(金额计算、促销规则判断、登录态封装)放在各自 src/utils 下,再通过一个 shared 目录共享。注意 Nuxt3 的 shared 目录不会自动映射到所有地方,需要在 nuxt.config.ts 里配好 alias,否则两端代码风格会越来越分叉——实际维护时最怕一个数字格式化函数同时存在三种写法。

2.3 zip 解压后的目录结构与版本矩阵

解压后根目录大致这样:

tigshop/ ├── tigshop-backend-java/ # Spring Boot 3 后端 ├── tigshop-server-php/ # ThinkPHP 8 后端 ├── tigshop-admin-web/ # Vue3 + Element Plus 管理端 ├── tigshop-mobile-nuxt/ # Nuxt3 SSR 商城前台 ├── tigshop-uniapp/ # Uniapp 跨端工程 ├── doc/ │ ├── sql/ # 初始化脚本与增量脚本 │ └── api/ # 接口文档 └── README.md

环境版本矩阵建议按下表核对,版本不对会出现很多“玄学”问题,实际都是依赖不兼容:

组件建议版本说明
JDK17 及以上Spring Boot 3 要求基线
PHP8.1 及以上TP8 类型增强依赖 8.1
Node18 或 20 LTSVite 与 Nuxt3 的最低要求
MySQL8.0字符集 utf8mb4,排序规则 utf8mb4_unicode_ci
Redis7.x缓存和分布式锁共用

提示:如果本机 PHP 版本还是 7.x,TP8 端会在 composer install 阶段直接报语法错误,先升级 PHP 再继续。

SQL 初始化部分,doc/sql 下一般会有 init.sql 和 upgrade 目录。常见做法是先建库再导入:

mysql -u root -p -e "CREATE DATABASE tigshop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mysql -u root -p tigshop < doc/sql/init.sql

逻辑说明:CREATE DATABASE 显式指定 utf8mb4,避免建表时继承 MySQL 默认的 latin1 排序规则,插入 emoji 或生僻字时才不会报错。导入 init.sql 后,如果有 upgrade 目录,按文件名时间顺序依次导入,里面通常是字段调整和索引补充。

参数说明:-e 用于执行无返回的 SQL 建库语句;重定向符号 < 让 mysql 客户端读取 SQL 文件;若升级脚本之间有依赖,务必按文件名升序导入,否则会报“字段不存在”的 SQL 错误。

导入完成后做个快速体检,确认核心表都建好了:

mysql -u root -p -e "USE tigshop; SHOW TABLES;" | head -30 mysql -u root -p -e "USE tigshop; SHOW INDEX FROM tigshop_order;"

逻辑说明:SHOW INDEX 主要看两个索引——订单号唯一索引防止重复单号,用户 ID 普通索引加快订单列表按人查询。促销活动表则重点看 start_time、end_time 的普通索引,按时间范围筛选是促销接口最频繁的查询条件。

参数说明:如果 init.sql 里没建这些索引,促销高峰期全表扫描会把数据库拖垮。这条不如接口报错那么直观,却是我见过最容易被忽略的隐患。

3. 把 TigShop 跑起来:双后端启动、三端联调与连通性验证

3.1 先核对配置:环境版本、数据库连接、Redis 与端口规划

跑起来之前先做三件事:核对环境版本、改配置、定端口。环境版本用三条命令扫一遍:

java -version php -v node -v

JDK 必须是 17 及以上,PHP 8.1 及以上,Node 18 或 20 LTS。版本只是前提,真正容易出问题的是后续配置文件里的连接信息。

Spring Boot 端主要看 src/main/resources/application.yml,TP8 端看 .env 文件。两端的数据库连接必须指向同一个 tigshop 库,Redis 默认用 0 号库即可。端口规划上,我一般会避开默认值冲突,按下面的表分配:

服务端口说明
Spring Boot 3 API8080订单支付类接口
TP8 API8081CMS 活动类接口
Vue3 管理端 Vite dev5173Vite 默认
Nuxt3 SSR3000Nuxt 默认
Uniapp H5 dev5174避免与 5173 冲突

提示:Windows 下用 php think run 之前先确认防火墙放行了对应端口,否则手机访问时会被系统防火墙静默拦截,表现是请求超时而不是拒绝。

3.2 Spring Boot 3 后端:改数据源、启动并验证 JWT

application.yml 里最需要动的是 spring.datasource 和 spring.data.redis。改完后用 Maven 包装器启动:

cd tigshop-backend-java ./mvnw spring-boot:run

启动日志里看到“Started Application in xx seconds”后,先别急着测业务接口,按下面的顺序验证基础设施:

curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"admin123"}'

逻辑说明:该接口先查 MySQL 用户表,再比对 BCrypt 哈希,成功后把用户 ID 和角色写进 JWT 并存入 Redis,返回的 accessToken 就是后续请求的凭证。

参数说明:密码字段按包内 init.sql 里预置的管理员账号填写,默认账号通常在 README 里;如果返回 401,优先检查数据源里有没有导入 init.sql,而不是怀疑代码。

拿到 token 后继续验证鉴权链路:

curl http://localhost:8080/order/list?page=1&limit=10 \ -H "Authorization: Bearer <返回的token>"

这一步能同时确认 Spring Security 拦截器、Redis token 校验、MySQL 查询三层是否打通。常见坑是 Redis 没起来,表现是登录成功但访问业务接口时抛“Unable to connect to Redis”,先 service redis start 再重试。

3.3 TP8 后端:composer 依赖、.env 配置与伪静态

切换到 PHP 端后,先装依赖:

cd tigshop-server-php composer install --no-dev --optimize-autoloader cp .env.example .env php think run --port 8081

逻辑说明:composer install 用于拉取 TP8 核心和中间件;--no-dev 跳过调试工具包,--optimize-autoloader 生成更快的类映射。.env.example 拷成 .env 后把数据库、Redis 连接改成和 Java 端一致。php think run 是内置开发服务器,适合联调,生产建议换 Nginx。

参数说明:--port 必须显式指定 8081,避免和 Java 端 8080 冲突;如果 PHP 代码里有 opcache 扩展,改 .env 后记得重启 PHP 进程,否则 .env 的缓存不会自动失效。

验证 TP8 接口:

curl http://localhost:8081/api/cms/banner/list

返回 JSON 数组即通过。若出现 404,先看是不是伪静态没配对,开发态下 php think run 自带路由解析,生产 Nginx 的配置放到第 5 章排查。

3.4 三端联调:Vue3 管理端、Nuxt3 商城页与 Uniapp H5

前端三端启动命令差异不大:

cd tigshop-admin-web npm install npm run dev
cd tigshop-mobile-nuxt npm install npm run dev
cd tigshop-uniapp npm install npm run dev:h5

逻辑说明:三端都依赖 npm 安装依赖,但注意不要在三个目录里共用一个 node_modules,Vue3 和 Nuxt3 的依赖版本互相独立,硬套会引发依赖提升错乱。

联调时最常改的是 API 地址配置。管理端通常在 .env.development 里配:

VITE_API_BASE_URL=http://localhost:8080/api VITE_CMS_API_URL=http://localhost:8081/api

Nuxt3 端在 nuxt.config.ts 里用 runtimeConfig 注册:

export default defineNuxtConfig({ runtimeConfig: { public: { apiBase: 'http://localhost:8080/api', cmsBase: 'http://localhost:8081/api' } } })

逻辑说明:管理端走订单交易接口,商城页需要同时拉取商品和 CMS 装修数据,所以两个地址都要配置。

参数说明:Uniapp 端在 src/config/index.ts 里通常按运行平台区分,我一般这样写:

const platform = import.meta.env.VITE_PLATFORM || 'h5' export const API_BASE = platform === 'mp-weixin' ? 'https://api.example.test' : 'http://localhost:8080/api'

逻辑说明:小程序端要求 HTTPS 并配置合法域名,开发期可以直接勾选“不校验合法域名”,但真机预览必须用局域网 IP;H5 端 localhost 就够用。

启动完成后,用一条链路验证全通:

  • 管理端登录后,F12 Network 出现 /promo/list 请求,状态 200。
  • Nuxt3 打开 http://localhost:3000,右键“查看网页源代码”,页面源码里能搜到商品标题和价格字符串,说明 SSR 预取生效。
  • Uniapp H5 控制台能打印出 CMS banner 的 JSON 数组。

三者数据都来自同一套 MySQL,任何一个页面报错,都先回查对应后端的日志,而不是先改前端代码。这一条规则帮我节省了大量排查时间。

4. 二次开发实战:从后端接口到三端页面的完整改动链路

4.1 给 Spring Boot 3 端加一个“限时促销”列表接口

先做后端的接口扩展,这是前后端联调的基础。为什么先画后端?因为这套商城是前后端分离的,接口返回结构(code / data / message)是两端之间的契约。TigShop 里统一用 Result 包装,我们自己加接口时也要保持同样结构,前端 axios 拦截器才能直接解析。

假设要加促销活动列表,典型做法是建立 promo 模块:实体、Mapper、Service、Controller 四层。实体简化如下:

@Entity @Table(name = "promo_activity") public class PromoActivity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private LocalDateTime startTime; private LocalDateTime endTime; private Integer status; }

逻辑说明:@Table 映射数据库 promo_activity 表,字段名遵循下划线转驼峰约定,MyBatis-Plus 或 Spring Data JPA 都能自动映射。

参数说明:status 建议用 0 未开始、1 进行中、2 已结束,不要用 Boolean,促销这类业务大概率会扩展状态,比如提前终止、已撤下。

Controller 层暴露分页查询:

@RestController @RequestMapping("/promo") public class PromoController { @GetMapping("/list") public Result<PageResult<PromoActivity>> list( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int limit) { Page<PromoActivity> p = new Page<>(page, limit); return Result.ok(promoService.page(p)); } }

逻辑说明:defaultValue 保证了前端不传页码时也能返回第一页。分页对象直接传给 service,避免手动写 limit 偏移量的低级错误。

参数说明:page 从 1 开始,limit 建议做上限限制,比如 limit > 100 时强制按 100 处理,防止有人恶意拖全表。

启动 Java 端后用 curl 验证:

curl "http://localhost:8080/promo/list?page=1&limit=10" \ -H "Authorization: Bearer <token>"

拿到 JSON 后就可以交前端对接。这一步能少掉很多前后端扯皮,因为字段名、嵌套结构都是后端定的,前端照单接。

4.2 TP8 端扩展:CMS 活动位接口与权限中间件

PHP 端加接口更轻快。在 app/controller/Cms 下新增一个 Activity.php:

<?php declare(strict_types=1); namespace app\controller\Cms; use support\Request; use support\Response; use app\service\ActivityService; class Activity { public function list(Request $request): Response { $page = (int) $request->get('page', 1); $limit = min((int) $request->get('limit', 10), 100); $data = ActivityService::page($page, $limit); return json(['code' => 0, 'data' => $data]); } }

逻辑说明:declare(strict_types=1) 开启严格类型后,字符串数字不会自动转 int,适合接口层强制类型。min 函数直接给 limit 兜底,避免全表查询。

参数说明:get 第二个参数是默认值;(int) 强转在请求参数为非数字时会得到 0,可以在入口做参数校验,TP8 有 validate 机制,生产环境建议补上。

定义路由时单独挂权限中间件:

Route::get('/cms/activity/list', [Activity::class, 'list'])->middleware(AuthMiddleware::class);

逻辑说明:中间件和 Java 端拦截器思路一样,AuthMiddleware 里检查 header 里的 Token,不一致则返回 401。这里要注意 Java 端 JWT 和 TP8 端 token 体系是否共用,如果共用同一 Redis key 规则,两端要配置一致的签名密钥。

参数说明:中间件只挂在该路由上,不要全局挂载,以免 banner 这类公开接口也要登录态,前端首屏 SSR 会拿不到数据。

4.3 管理端页面改版:Element Plus 表格与搜索栏

新增列表页时,Element Plus 的 el-table 是最常用的组件:

<script setup lang="ts"> interface PromoItem { id: number title: string startTime: string endTime: string status: number } const list = ref<PromoItem[]>([]) const total = ref(0) const query = reactive({ page: 1, limit: 10 }) async function loadData() { const { data } = await http.get('/promo/list', { params: query }) list.value = data.list total.value = data.total } onMounted(loadData) </script> <template> <el-table :data="list" v-loading="loading"> <el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="title" label="活动名称" /> <el-table-column prop="startTime" label="开始时间" /> <el-table-column label="状态"> <template #default="{ row }"> <el-tag :type="row.status === 1 ? 'success' : 'info'"> {{ row.status === 1 ? '进行中' : '已结束' }} </el-tag> </template> </el-table-column> </el-table> </template>

逻辑说明:script setup 语法下 TypeScript 接口定义先声明 PromoItem,编译器就能推断表格行类型,避免 any 满天飞。http 是封装好的 axios 实例,统一带了 Authorization 头。

参数说明:status 的展示用 template 插槽做自定义渲染,比在数据里预先拼字符串更适合后续扩展,比如加“未开始”状态只需改三元表达式。loading 状态需要自己在 loadData 里控制,Element Plus 的 v-loading 指令绑定了布尔变量后,表格区域会出现遮罩,避免用户看到半截数据。

4.4 Nuxt3 商城页:服务端预取促销数据

Nuxt3 页面里用 useFetch 实现 SSR 预取:

<script setup lang="ts"> const { data: promos } = await useFetch('/api/promo/list', { baseURL: 'http://localhost:8080', query: { page: 1, limit: 4 } }) </script> <template> <section> <h2>限时促销</h2> <div v-for="p in promos.list" :key="p.id" class="promo-card"> <p>{{ p.title }}</p> <time>{{ p.startTime }}</time> </div> </section> </template>

逻辑说明:useFetch 在服务端渲染阶段就会请求 Java 后端,把数据连同 HTML 一起输出,用户首屏不用等前端再发一次 Ajax。

参数说明:baseURL 要指向 Java 端地址,query 参数会拼到 URL 上。如果促销数据不要求首屏 SEO,也可以改用 $fetch 在客户端按需加载,减少服务端压力。

4.5 Uniapp 跨端适配:条件编译改登录态

Uniapp 端最烦的是不同平台 API 差异。这套包用的是条件编译方案,以登录态封装为例:

// src/utils/auth.ts import { getStorageSync, setStorageSync } from '@dcloudio/uni-app' export function getToken(): string { // #ifdef H5 return localStorage.getItem('tigshop_token') || '' // #endif // #ifndef H5 return getStorageSync('tigshop_token') // #endif } export function setToken(token: string): void { // #ifdef H5 localStorage.setItem('tigshop_token', token) // #endif // #ifndef H5 setStorageSync('tigshop_token', token) // #endif }

逻辑说明:#ifdef H5 只在 H5 平台编译,小程序和 App 走 getStorageSync,避免在非浏览器环境直接操作 localStorage 抛错。

参数说明:条件编译是注释形式的预处理指令,编辑器里默认高亮,但复制到非 Uniapp 项目时会变成死代码,注意识别。

5. 避坑与常见问题排查:把这套多端商城常见的坑一次说完

5.1 两个后端抢 8080 端口,服务起不来

现象:先启动 Java 端没问题,再启动 TP8 端时终端报“Address already in use”,或者反过来 Java 端被按到 8081 上导致后面接口全串。极端时 Vite 也会来凑热闹,5173 被别的项目占掉,管理端白屏。

原因:两端默认配置文件里都写着 8080 或 8000,同时跑开发服务器必然冲突。

解决:按第 3 章的端口规划给 TP8 显式指定 8081,且两端 API 里的 baseURL 都要写对端口。我一般在启动前先执行:

lsof -i :8080 -i :8081

确认端口没被占再起服务。Windows 下用 netstat -ano | findstr :8080 代替 lsof。若本机 8080 被其他进程占用,改 Java 端 server.port=8082 也行,但记得同步修改三个前端的 API 配置。

5.2 前端联调时登录成功后刷新就掉登录态

现象:管理端输入账号密码拿到 token,跳转列表页正常,按 F5 刷新后页面跳回登录页。浏览器 Application 面板里看不到预期的凭证。

原因:浏览器跨域请求下,后端响应里的 Set-Cookie 属性不正确。Java 端配置了 CORS 允许跨域,但 Cookie 的 SameSite 默认 Lax,跨端口访问时浏览器选择不写入。

解决:开发环境最省事的做法是不用 Cookie,前端把 JWT 放 localStorage,请求头 Authorization 携带。如果业务必须用 Cookie,后端需设置 SameSite=None; Secure,同时要求 HTTPS,本地联调成本会高很多。从实际经验看,TigShop 这类前后端分离商城用 Authorization 头更稳,也方便 Uniapp 端复用同一套鉴权代码。

5.3 Nuxt3 构建时内存溢出或改完代码不生效

现象:npm run build 过程中报“JavaScript heap out of memory”;npm run dev 改完页面代码后,浏览器里还是旧数据。

原因:前者是 Nuxt3 客户端打包时默认堆内存不够,常见于 Node 18 且项目里引用了大量 Element Plus 组件;后者是 .nuxt 缓存目录没清理,或 Vite 依赖预构建缓存失效。

解决:构建时显式扩大 Node 堆内存:

NODE_OPTIONS=--max-old-space-size=4096 npm run build

开发态下改完代码先清缓存再重启:

rm -rf .nuxt node_modules/.vite npm run dev

OOM 之前日志会先出现“Reached heap limit”标识,看到这个再调大数值;清缓存是玄学但确实有效。从那次之后,我每次新建 Nuxt3 页面都会等编译日志跑完再切浏览器,不再凭直觉刷新。

5.4 Uniapp 真机调试连不上本地后端

现象:H5 端页面数据正常,微信开发者工具里接口全部报“request:fail”,或者在手机预览时白屏,控制台是网络层错误。

原因:H5 访问 localhost 指向电脑本机,但开发者工具和真机运行时,localhost 指向它们自己。开发者工具没勾选跳过域名校验,或手机和电脑不在同一局域网。

解决:把 API 地址临时改成电脑的局域网 IP,并让手机和电脑连同一 Wi-Fi。微信开发者工具右上角“详情-本地设置”勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。Android 模拟器特殊场景下要用 10.0.2.2 代替局域网 IP。改完 settings.json 里的代理后,重启开发者工具再试。

5.5 TP8 生产环境伪静态配置不对导致接口 404

现象:本地 php think run 接口正常,部署到 Nginx 后访问 /api/cms/banner/list 返回 404,加 index.php 又能访问。

原因:Nginx 的 location 配置没把请求转发给 ThinkPHP 的入口文件,PHP 没拿到真实路由。

解决:在 server 块里配置标准的 TP8 伪静态规则:

location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/run/php/php8.1-fpm.sock; }

逻辑说明:try_files 先找静态文件,找不到就把请求交给 index.php 解析,由 TP8 路由重新分发。

参数说明:fastcgi_pass 要和实际 PHP-FPM 版本一致,如果装了 php8.2,则路径也要换成 php8.2-fpm.sock,否则 502。这一步配完记得 nginx -t && nginx -s reload,并到 /var/log/nginx/error.log 确认错误码已经变化。

6. 进阶:给 TigShop 加一层轻量可观测性与多环境构建

跑通只是第一步,商城上线后的稳定性更值钱。我这边会优先给这套架构加一个轻量可观测层,不用额外部署链路追踪系统。

Spring Boot 3 端引入 Actuator 和 Micrometer,把接口耗时、JVM 内存、数据库连接池用量暴露成 Prometheus 指标。依赖加完后在 application.yml 里开放端点:

management: endpoints: web: exposure: include: health,metrics,prometheus

这段配置把 /actuator/prometheus 端点暴露出来,Prometheus 抓取后就能按 application 维度看接口吞吐和耗时分布。注意只放开这个端点,不要用 include: '*' 把全部 actuator 端点暴露到公网。

同时给 @RestController 加一个注解切面,记录请求路径、耗时和状态码。TP8 端在中间件里做同样的事,把 /api 前缀的请求耗时写入 Redis 的 zset,按分钟统计 P95。前端三端则统一在 axios 拦截器上报页面性能数据。

多环境构建也是这套包容易踩的坑。三个前端各自有 dev 和 prod 配置,最怕上线时有人手改 API 地址导致线上请求打到本地。我一般会在管理端和 Nuxt3 里加一层构建时校验:prod 构建时 if 判断地址不是 https 就直接抛错,从源头堵住这个失误。Uniapp 端则在 package.json 里预设 build:mp-weixin 和 build:app 两个脚本,避免每次手动切换平台。

这套可观测层加上后,验证链路就完整了:登录拿 token 访问 /promo/list,Prometheus 里能看到该接口的请求量和 P95 耗时;TP8 的 zset 能看到 CMS 接口流量分布;Nuxt3 页面响应时间直接进入日志。三端数据对得上,再谈上线。

有回做促销活动,运营反馈图片加载慢,查了 Prometheus 发现 Java 端接口耗时正常,问题出在静态资源链路。从那以后我每次部署 TigShop 都强制走一遍“登录 → 查指标 → 看日志”三连,先确认可观测数据齐全再放量。如果你手里正好有这份 zip 包,建议也先把这三步当成固定习惯。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询