【飞算 Java】 打造电商高效的系统核心功能模块的设计与实现
2025-10-02 15:36 tlnshuju 阅读(9) 评论(0) 收藏 举报文章目录
- 第四章 商品管理模块设计与实现
- 第五章 订单管理模块设计与实现
- 第六章 支付管理模块设计与实现
- 第七章 库存管理模块设计与实现
- 总结:飞算 Java 的电商场景价值
第一章 电商系统概述
1.1 电商系统发展背景与趋势
随着互联网技术的飞速发展,电商行业已从早期的简单线上交易模式,逐步演进为融合社交、内容、直播、跨境等多场景的复杂生态体系。根据艾瑞咨询数据,2024 年全球电商交易额突破 6 万亿美元,其中中国市场占比超 35%。消费者对电商平台的需求不再局限于 “买得到”,更追求 “买得好、买得快、体验佳”,这对电商系统的稳定性、高并发处理能力、数据安全性及用户体验优化提出了更高要求。
当前电商系统发展呈现三大趋势:一是全渠道融合,线上线下库存打通、会员体系互通,如京东到家、天猫超市的即时零售模式;二是智能化升级,通过大数据分析实现精准推荐、智能客服、动态定价,提升转化效率;三是轻量化部署,企业更倾向于采用低代码、微服务架构,降低开发成本、缩短上线周期,飞算 Java 凭借其低代码特性与分布式架构支持,成为适配这一趋势的重要技术选择。
1.2 飞算 Java 技术优势与电商系统适配性
飞算 Java 是飞算科技推出的面向企业级应用开发的 Java 开发平台,整合了低代码开发、分布式服务治理、数据集成、运维监控等核心能力,其技术优势与电商系统需求高度契合:
1.2.1 低代码开发提升效率
飞算 Java 提供可视化表单设计、流程编排、组件化开发能力,电商系统中高频的商品管理、订单审核、售后流程等模块,可通过拖拽组件快速搭建,开发效率提升 60% 以上。例如,商品上下架流程无需编写大量重复代码,仅需在平台中配置审核节点、触发条件及数据关联规则,即可完成功能开发。
1.2.2 分布式架构保障高并发
电商系统在大促(如双 11、618)期间面临每秒数万次的请求峰值,飞算 Java 基于分布式微服务架构,支持服务拆分、负载均衡与弹性伸缩。通过其内置的服务注册中心与配置中心,可实现商品服务、订单服务、支付服务的独立部署与动态扩缩容,避免单点故障,保障系统在高并发场景下的稳定运行。
1.2.3 数据一致性与安全防护
电商交易涉及订单、支付、库存等关键数据,飞算 Java 提供分布式事务管理组件(基于 TCC/Seata 模式),解决跨服务数据一致性问题,如订单创建与库存扣减的原子性操作。同时,平台内置数据加密、接口鉴权、SQL 注入防护等安全机制,符合电商行业对用户隐私(如手机号、支付信息)与交易安全的合规要求。
1.2.4 多端适配与集成能力
飞算 Java 支持 PC 端、移动端(APP、小程序)、H5 等多终端开发,通过统一的 API 网关实现接口适配,减少多端开发工作量。此外,平台提供丰富的第三方集成接口,可快速对接支付宝、微信支付、物流系统(顺丰、中通)、短信服务商(阿里云短信)等,满足电商系统的全链路业务需求。
1.3 系统整体目标与范围
1.3.1 核心目标
功能完整性:覆盖电商核心业务流程,包括用户管理、商品管理、订单管理、支付管理、库存管理、物流管理、搜索推荐、售后管理等模块;
性能达标:支持日均 100 万订单处理量,大促峰值 QPS 达 5 万,页面响应时间≤200ms,订单成功率≥99.99%;
可扩展性:采用微服务架构,支持新增业务模块(如跨境电商、直播带货)时快速集成,无需重构现有系统;
易用性:为运营人员提供可视化后台管理界面,支持配置化操作;为用户提供流畅的购物体验,包括快速搜索、便捷支付、物流追踪等;
安全性:符合《网络安全法》《个人信息保护法》要求,保障用户数据与交易安全。
1.3.2 系统范围
本电商系统聚焦 B2C 模式(企业对个人),核心业务范围包括:
前端:用户端(商品浏览、下单、支付、售后)、运营端(商品管理、活动配置、数据统计)、商家端(店铺管理、订单处理、库存维护);
后端:核心服务模块(用户、商品、订单、支付等)、中间件(缓存、消息队列、搜索引擎)、数据存储(关系型数据库、NoSQL 数据库);
集成系统:第三方支付、物流、短信、实名认证、舆情监控等外部系统。
第二章 系统总体架构设计
2.1 架构设计原则
分层解耦:遵循 “前端 - API 网关 - 业务服务 - 数据存储” 分层架构,降低模块间耦合度,便于独立开发与维护;
微服务拆分:按业务领域拆分服务,每个服务专注单一业务能力,如用户服务、商品服务、订单服务等,避免单体系统复杂度过高;
高可用设计:关键服务多实例部署,通过负载均衡实现故障转移;核心数据多副本存储,防止数据丢失;
性能优先:引入缓存、消息队列、异步处理等机制,提升系统响应速度与并发处理能力;
可观测性:集成日志、监控、链路追踪工具,实时监控系统运行状态,快速定位故障;
安全合规:在架构各层融入安全防护机制,如 API 网关鉴权、服务端数据加密、前端输入校验等。
2.2 飞算 Java 架构落地方案
基于飞算 Java 平台,电商系统整体架构分为五层,各层功能与飞算 Java 组件适配如下:
2.2.1 前端层
功能:提供多终端用户界面,包括用户购物端、运营管理端、商家管理端;
飞算 Java 组件支持:飞算 Java 低代码平台提供可视化前端设计器,支持 Vue/React 组件拖拽,生成响应式页面;同时提供前端模板库,包含电商常用页面(商品列表、详情页、购物车、订单页),减少定制开发工作量;
技术选型:用户端(Vue3+Vite)、管理端(Element Plus)、小程序(UniApp)。
2.2.2 API 网关层
功能:统一接口入口,负责请求路由、鉴权、限流、熔断、日志记录;
飞算 Java 组件支持:基于飞算 Java 网关组件(FeiSuan Gateway)实现,支持动态路由配置(根据 URL 匹配后端服务)、JWT 令牌鉴权(验证用户身份)、流量控制(按 IP / 用户 ID 限制请求频率);同时集成 API 文档生成工具(Swagger),自动生成接口文档;
核心能力:
路由转发:将用户请求转发至对应微服务,如 “/api/user/*” 转发至用户服务;
限流熔断:大促期间限制单用户每秒下单请求数(如 5 次 / 秒),服务异常时触发熔断,返回友好提示;
跨域处理:解决前端跨域请求问题,支持配置允许跨域的域名与请求方法。
2.2.3 业务服务层
功能:核心业务逻辑实现,按领域拆分为 8 个微服务,各服务独立部署与扩展;
飞算 Java 组件支持:
服务开发:飞算 Java 提供微服务开发框架,支持 Spring Boot/Spring Cloud 规范,开发者可基于模板快速创建服务,自动集成服务注册、配置中心、分布式事务等能力;
流程编排:飞算 Java 流程引擎(FeiSuan Flow)用于实现复杂业务流程,如订单创建流程(订单生成→库存扣减→支付通知→物流创建)、售后流程(申请提交→审核→退款→退货);
服务治理:飞算 Java 服务注册中心(基于 Nacos)实现服务发现与健康检查;配置中心统一管理各服务配置(如数据库连接、第三方接口密钥),支持动态更新;
各微服务功能定义:
用户服务:用户注册、登录、身份认证、会员管理、地址管理、用户画像;
商品服务:商品分类、属性管理、SKU 管理、上下架、商品评价、库存预占;
订单服务:订单创建、订单状态流转、订单查询、订单拆分、退款处理;
支付服务:支付渠道集成(支付宝、微信支付)、支付发起、支付结果回调、账单管理;
库存服务:库存实时更新、库存预警、库存同步(与订单 / 商品服务)、盘点管理;
物流服务:物流商对接、物流单创建、物流信息查询、签收确认;
搜索推荐服务:商品搜索(关键词匹配、筛选)、智能推荐(基于用户画像)、热门商品排序;
营销服务:优惠券、满减活动、秒杀活动、积分管理、拼团活动。
2.2.4 中间件层
功能:提供缓存、消息队列、搜索引擎等基础能力,支撑业务服务高性能运行;
飞算 Java 组件支持:飞算 Java 集成主流中间件,提供统一的配置与管理界面,无需单独部署与维护:
缓存:集成 Redis,用于商品详情缓存、用户会话缓存、订单临时数据缓存,飞算 Java 提供缓存操作封装组件,简化 Redis 调用;
消息队列:集成 RocketMQ,用于异步处理(如订单创建后发送通知、库存变更同步),飞算 Java 提供消息生产者 / 消费者模板,支持消息重试与死信队列;
搜索引擎:集成 Elasticsearch,用于商品搜索,飞算 Java 提供索引构建、查询封装组件,支持复杂条件搜索(如按价格区间、销量排序);
分布式锁:基于 Redis/ZooKeeper 实现,解决并发场景下的数据竞争问题(如库存扣减)。
2.2.5 数据存储层
功能:负责数据持久化存储,根据数据类型选择合适的存储方案;
飞算 Java 组件支持:飞算 Java 提供数据访问层(DAL)组件,支持多数据源管理、SQL 优化、事务控制,同时集成数据同步工具,实现数据备份与迁移;
存储方案选型:
关系型数据库:MySQL(主从架构),存储结构化数据,如用户信息、订单信息、商品基础信息;飞算 Java 支持 MySQL 读写分离配置,主库负责写操作,从库负责读操作,提升查询性能;
NoSQL 数据库:MongoDB,存储非结构化 / 半结构化数据,如商品详情(富文本)、用户行为日志;Redis,存储缓存数据与会话数据;
数据仓库:ClickHouse,用于存储电商业务数据(如用户消费记录、商品销售数据),支持大数据量分析与报表生成。
2.3 核心业务流程图
以 “用户下单支付” 为例,基于飞算 Java 流程引擎的业务流程设计如下:
触发条件:用户在前端提交订单(选择商品、收货地址、支付方式);
流程节点:
节点 1:参数校验(飞算 Java 表单校验组件),验证商品是否上架、库存是否充足、收货地址是否完整;
节点 2:创建订单(订单服务),生成订单号,存储订单基础信息(订单状态为 “待支付”);
节点 3:库存预占(库存服务),调用库存服务接口,预占对应商品库存(预占时长 30 分钟,防止超卖);
节点 4:发起支付(支付服务),根据用户选择的支付方式,调用支付宝 / 微信支付接口,生成支付链接;
节点 5:支付结果监听(支付服务),通过异步回调监听支付结果:
支付成功:更新订单状态为 “已支付”,发送消息至消息队列(触发后续物流创建、积分增加流程);
支付失败 / 超时:释放预占库存,更新订单状态为 “支付失败 / 已取消”;
节点 6:通知用户(用户服务),通过短信 / APP 推送告知用户订单状态(飞算 Java 集成短信组件,调用阿里云短信接口);
- 异常处理:
节点 2 失败:返回 “订单创建失败”,提示用户重试;
节点 3 失败:回滚订单创建操作,返回 “库存不足”;
节点 4 失败:释放预占库存,回滚订单,返回 “支付渠道异常”;
- 流程监控:飞算 Java 流程监控平台实时展示流程运行状态,记录各节点耗时与异常信息,支持流程重试与手动干预。
2.4 系统部署架构
基于飞算 Java 的部署能力,电商系统采用云原生部署方案,支持 Docker 容器化与 Kubernetes 编排:
部署环境:公有云(阿里云 / 腾讯云),采用多可用区部署(如阿里云上海、杭州可用区),避免区域故障影响系统;
基础设施:
负载均衡:阿里云 SLB,分发前端与 API 网关请求;
容器编排:Kubernetes,管理各服务容器实例,实现自动扩缩容;
存储服务:阿里云 RDS(MySQL)、MongoDB Atlas、Redis 云数据库;
- 部署分层:
前端层:静态资源部署在阿里云 OSS,通过 CDN 加速分发;
API 网关层:3 个实例部署(多可用区),确保高可用;
业务服务层:每个微服务按负载需求部署 2-5 个实例,大促期间通过 Kubernetes HPA(水平 Pod 自动扩缩容)增加实例数;
中间件层:Redis、RocketMQ、Elasticsearch 采用云服务商托管版本,减少运维成本;
- 监控告警:集成飞算 Java 监控组件与阿里云 ARMS,监控指标包括服务 CPU / 内存使用率、接口响应时间、错误率、数据库连接数等,设置阈值告警(如错误率>0.1% 时触发短信告警)。
第三章 用户管理模块设计与实现
3.1 模块需求分析
3.1.1 业务需求
用户管理模块是电商系统的基础,负责用户从注册到注销的全生命周期管理,核心业务需求包括:
用户注册与登录:支持手机号 / 邮箱注册,验证码验证;支持账号密码登录、短信验证码登录、第三方登录(微信 / QQ);
身份认证:实现实名认证(身份证正反面上传、人脸识别),符合电商平台合规要求;
用户信息管理:支持用户修改昵称、头像、密码、绑定手机 / 邮箱;管理收货地址(新增、编辑、删除、设为默认);
会员体系:设置会员等级(如普通会员、银卡会员、金卡会员),基于消费金额 / 次数升级;提供会员权益(如折扣、免运费、专属客服);
用户行为记录:记录用户浏览、收藏、加购、下单行为,为搜索推荐模块提供数据支持;
账号安全:提供登录日志查询、异地登录提醒、账号冻结 / 解冻功能,保障账号安全。
3.1.2 非功能需求
性能:登录接口响应时间≤100ms,用户信息查询 QPS 支持 1 万 / 秒;
安全性:密码加密存储(BCrypt 算法),验证码有效期 5 分钟,第三方登录信息脱敏;
可扩展性:支持新增登录方式(如 Apple ID 登录),会员等级规则可配置;
兼容性:支持 PC 端、移动端、小程序端登录,保持登录状态同步。
3.2 模块设计
3.2.1 领域模型设计
基于飞算 Java 的领域驱动设计(DDD)支持,用户管理模块核心领域模型如下:
- 用户(User):
核心属性:用户 ID(userId,主键)、手机号(phone,唯一)、邮箱(email,唯一)、密码(password,加密存储)、昵称(nickname)、头像(avatarUrl)、会员等级(memberLevel)、注册时间(registerTime)、最后登录时间(lastLoginTime)、账号状态(status:正常 / 冻结 / 注销);
关联对象:收货地址列表(AddressList)、用户认证信息(UserAuth);
核心行为:注册(register)、登录(login)、修改信息(updateInfo)、升级会员(upgradeMember)、冻结账号(freezeAccount)。
- 收货地址(Address):
核心属性:地址 ID(addressId)、用户 ID(userId,外键)、收件人(receiver)、手机号(receiverPhone)、省(province)、市(city)、区(district)、详细地址(detailAddress)、是否默认(isDefault)、创建时间(createTime);
核心行为:新增地址(add)、编辑地址(edit)、设为默认(setDefault)、删除地址(delete)。
- 用户认证(UserAuth):
核心属性:认证 ID(authId)、用户 ID(userId,外键)、真实姓名(realName)、身份证号(idCardNo,加密存储)、人脸识别状态(faceVerifyStatus:未认证 / 已认证)、认证时间(authTime)、认证失败原因(failReason);
核心行为:提交认证(submitAuth)、认证审核(verifyAuth)、查询认证状态(queryAuthStatus)。
- 会员等级(MemberLevel):
核心属性:等级 ID(levelId)、等级名称(levelName)、升级条件(如消费金额≥1000 元)、会员权益(discount:折扣比例、freeShipping:是否免运费)、等级排序(sort);
核心行为:查询等级规则(queryLevelRule)、判断用户等级(judgeUserLevel)。
3.2.2 数据库设计
基于 MySQL 数据库,用户管理模块核心表结构设计如下(采用飞算 Java 可视化数据库设计工具生成):
表 3-1 用户表(t_user)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
user_id | BIGINT | - | 主键 | AUTO_INCREMENT | 用户唯一标识 |
phone | VARCHAR | 20 | 唯一 | NOT NULL | 手机号 |
VARCHAR | 50 | 唯一 | - | 邮箱(可为空) | |
password | VARCHAR | 100 | - | NOT NULL | 加密后的密码(BCrypt) |
nickname | VARCHAR | 50 | - | NOT NULL | 用户昵称 |
avatar_url | VARCHAR | 255 | - | - | 头像 URL(默认使用占位图) |
member_level | TINYINT | - | - | DEFAULT 1 | 会员等级(1 - 普通,2 - 银卡) |
register_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 注册时间 |
last_login_time | DATETIME | - | - | - | 最后登录时间 |
status | TINYINT | - | - | DEFAULT 0 | 状态(0 - 正常,1 - 冻结) |
delete_flag | TINYINT | - | - | DEFAULT 0 | 删除标志(0 - 未删,1 - 已删) |
表 3-2 收货地址表(t_address)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
address_id | BIGINT | - | 主键 | AUTO_INCREMENT | 地址唯一标识 |
user_id | BIGINT | - | 外键 | REFERENCES t_user(user_id) | 关联用户 ID |
receiver | VARCHAR | 20 | - | NOT NULL | 收件人姓名 |
receiver_phone | VARCHAR | 20 | - | NOT NULL | 收件人手机号 |
province | VARCHAR | 20 | - | NOT NULL | 省份 |
city | VARCHAR | 20 | - | NOT NULL | 城市 |
district | VARCHAR | 20 | - | NOT NULL | 区县 |
detail_address | VARCHAR | 200 | - | NOT NULL | 详细地址 |
is_default | TINYINT | - | - | DEFAULT 0 | 是否默认(0 - 否,1 - 是) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
update_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
表 3-3 用户认证表(t_user_auth)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
auth_id | BIGINT | - | 主键 | AUTO_INCREMENT | 认证唯一标识 |
user_id | BIGINT | - | 外键 | REFERENCES t_user(user_id) | 关联用户 ID |
real_name | VARCHAR | 20 | - | NOT NULL | 真实姓名 |
id_card_no | VARCHAR | 50 | - | NOT NULL | 加密后的身份证号 |
id_card_front_url | VARCHAR | 255 | - | NOT NULL | 身份证正面照片 URL |
id_card_back_url | VARCHAR | 255 | - | NOT NULL | 身份证背面照片 URL |
face_verify_status | TINYINT | - | - | DEFAULT 0 | 人脸识别状态(0 - 未认证) |
auth_status | TINYINT | - | - | DEFAULT 0 | 认证状态(0 - 待审核) |
auth_time | DATETIME | - | - | - | 认证通过时间 |
fail_reason | VARCHAR | 200 | - | - | 认证失败原因 |
表 3-4 会员等级表(t_member_level)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
level_id | INT | - | 主键 | AUTO_INCREMENT | 等级唯一标识 |
level_name | VARCHAR | 20 | - | NOT NULL | 等级名称(如银卡会员) |
upgrade_amount | DECIMAL(10,2) | - | - | NOT NULL | 升级所需消费金额 |
discount | DECIMAL(5,2) | - | - | DEFAULT 1.00 | 折扣比例(如 0.95=95 折) |
free_shipping | TINYINT | - | - | DEFAULT 0 | 是否免运费(0 - 否,1 - 是) |
sort | INT | - | - | DEFAULT 0 | 排序序号(越小越靠前) |
3.2.3 接口设计
基于 RESTful 规范,用户管理模块核心接口通过飞算 Java 接口设计工具定义,包含接口路径、请求参数、响应参数、请求方法等信息,部分核心接口如下:
3.2.3.1 用户注册接口
接口路径:
/api/user/register
请求方法:POST
请求参数(JSON):
{
"phone": "13800138000",
"verifyCode": "123456",
"password": "Aa123456",
"nickname": "电商用户123"
}
- 响应参数(JSON):
{
"code": 200,
"message": "注册成功",
"data": {
"userId": 100001,
"nickname": "电商用户123",
"memberLevel": 1,
"registerTime": "2024-05-20 14:30:00"
}
}
- 业务逻辑:
校验手机号格式与验证码有效性(调用短信服务接口验证);
检查手机号是否已注册(查询 t_user 表);
密码加密(BCrypt 算法);
插入用户数据到 t_user 表;
返回用户基本信息。
3.2.3.2 用户登录接口(短信验证码登录)
接口路径:
/api/user/login/sms
请求方法:POST
请求参数(JSON):
{
"phone": "13800138000",
"verifyCode": "654321"
}
- 响应参数(JSON):
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", // JWT令牌
"userInfo": {
"userId": 100001,
"nickname": "电商用户123",
"avatarUrl": "https://xxx.com/avatar/100001.jpg",
"memberLevel": 1
},
"expireTime": "2024-05-21 14:30:00" // 令牌过期时间(24小时)
}
}
- 业务逻辑:
校验手机号与验证码;
查询用户信息(t_user 表),检查账号状态(是否冻结);
生成 JWT 令牌(包含 userId、memberLevel 等信息,过期时间 24 小时);
更新用户最后登录时间(t_user 表);
返回令牌与用户基本信息。
3.2.3.3 收货地址新增接口
接口路径:
/api/user/address/add
请求方法:POST
请求头:
Authorization: Bearer {token}
(JWT 令牌)请求参数(JSON):
{
"receiver": "张三",
"receiverPhone": "13900139000",
"province": "上海市",
"city": "上海市",
"district": "浦东新区",
"detailAddress": "XX路XX号XX小区1号楼101室",
"isDefault": 1
}
- 响应参数(JSON):
{
"code": 200,
"message": "地址新增成功",
"data": {
"addressId": 200001
}
}
- 业务逻辑:
解析 JWT 令牌获取 userId;
校验收件人、手机号、地址信息完整性;
若 isDefault=1,先将该用户其他地址设为非默认(更新 t_address 表);
插入地址数据到 t_address 表;
返回地址 ID。
3.2.4 权限设计
基于飞算 Java 的权限管理组件,用户管理模块实现细粒度权限控制:
- 角色定义:
普通用户:仅能操作自身信息(如修改个人资料、管理自己的收货地址);
运营管理员:可查询所有用户信息、冻结违规用户、审核实名认证;
系统管理员:拥有模块全部权限,包括配置会员等级规则;
- 权限控制实现:
接口权限:通过飞算 Java 注解
@Permission
指定接口所需角色,如@Permission(roles = {"OPERATOR", "ADMIN"})
表示仅运营管理员与系统管理员可访问;数据权限:普通用户查询地址时,SQL 自动添加
user_id = #{userId}
条件(基于飞算 Java 数据权限组件);运营管理员查询用户时,可按用户状态、注册时间筛选,但无法查看用户密码与加密的身份证号;
权限校验流程:
用户请求接口时,API 网关解析 JWT 令牌获取用户角色;
飞算 Java 权限组件校验用户角色是否匹配接口所需权限;
校验通过则放行请求,校验失败返回 “无权限访问”(code=403)。
3.3 模块实现(基于飞算 Java)
3.3.1 开发环境搭建
- 飞算 Java 平台配置:
登录飞算 Java 开发平台(https://www.feisuan.com/java),创建电商系统项目(项目名称:ecommerce-system);
配置项目基础信息:JDK 版本(17)、Spring Boot 版本(3.2.0)、数据库连接(MySQL 8.0);
引入用户管理模块依赖:飞算 Java 用户组件、权限组件、短信集成组件;
- 本地开发环境:
下载飞算 Java IDE 插件(支持 IntelliJ IDEA/Eclipse),关联云端项目;
本地启动 MySQL 数据库,创建电商系统数据库(ecommerce_db),执行飞算 Java 自动生成的表结构脚本;
配置短信服务参数(阿里云短信 AccessKey、模板 ID),在飞算 Java 配置中心存储。
3.3.2 核心代码实现(用户注册功能)
3.3.2.1 实体类(基于飞算 Java JPA)
// User.java(飞算Java自动生成,基于t\_user表)
@Entity
@Table(name = "t\_user")
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
@Column(unique = true, nullable = false)
private String phone;
@Column(unique = true)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String nickname;
private String avatarUrl;
private Integer memberLevel = 1; // 默认普通会员
private Date lastLoginTime;
private Integer status = 0; // 默认正常状态
// getter/setter(飞算Java自动生成)
}
3.3.2.2 服务层(UserService)
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 飞算Java自动生成的JPA Repository
@Autowired
private SmsService smsService; // 飞算Java短信集成组件
@Autowired
private PasswordEncoder passwordEncoder; // 飞算Java密码加密组件
/\*\*
\* 用户注册
\* @param registerDTO 注册请求DTO
\* @return 用户信息
\*/
public UserVO register(RegisterDTO registerDTO) {
// 1. 校验手机号格式
if (!PhoneUtils.isValid(registerDTO.getPhone())) {
throw new BusinessException("手机号格式错误");
}
// 2. 验证短信验证码
boolean verifyResult = smsService.verifyCode(
registerDTO.getPhone(),
registerDTO.getVerifyCode()
);
if (!verifyResult) {
throw new BusinessException("验证码错误或已过期");
}
// 3. 检查手机号是否已注册
Optional\ userOptional = userRepository.findByPhone(registerDTO.getPhone());
if (userOptional.isPresent()) {
throw new BusinessException("该手机号已注册");
}
// 4. 密码加密
String encryptedPassword = passwordEncoder.encode(registerDTO.getPassword());
// 5. 构建User对象并保存
User user = new User();
user.setPhone(registerDTO.getPhone());
user.setNickname(registerDTO.getNickname());
user.setPassword(encryptedPassword);
user.setAvatarUrl("https://xxx.com/avatar/default.jpg"); // 默认头像
user.setRegisterTime(new Date());
User savedUser = userRepository.save(user);
// 6. 转换为VO返回
UserVO userVO = new UserVO();
BeanUtils.copyProperties(savedUser, userVO);
return userVO;
}
}
3.3.2.3 控制层(UserController)
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private ResultGenerator resultGenerator; // 飞算Java统一响应生成器
/\*\*
\* 用户注册接口
\*/
@PostMapping("/register")
public Result\ register(@Valid @RequestBody RegisterDTO registerDTO) {
UserVO userVO = userService.register(registerDTO);
return resultGenerator.success("注册成功", userVO);
}
}
3.3.2.4 DTO 与 VO(数据传输对象)
// RegisterDTO.java(注册请求DTO,飞算Java表单校验)
public class RegisterDTO {
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1\[3-9]\\\d{9}\$", message = "手机号格式错误")
private String phone;
@NotBlank(message = "验证码不能为空")
private String verifyCode;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^(?=.\*\[a-z])(?=.\*\[A-Z])(?=.\*\\\d).{8,20}\$", message = "密码需包含大小写字母与数字,长度8-20位")
private String password;
@NotBlank(message = "昵称不能为空")
@Size(max = 20, message = "昵称长度不能超过20位")
private String nickname;
// getter/setter
}
// UserVO.java(用户响应VO)
public class UserVO {
private Long userId;
private String nickname;
private String avatarUrl;
private Integer memberLevel;
private Date registerTime;
// getter/setter
}
3.3.3 飞算 Java 组件集成(短信服务)
飞算 Java 提供短信服务集成组件,无需手动编写 HTTP 请求代码,仅需配置参数即可调用:
- 组件配置:在飞算 Java 配置中心添加阿里云短信配置:
sms:
aliyun:
accessKeyId: LTAI5txxxxxxxxxxxxxxx
accessKeySecret: 8xxxxxxxxxxxxxxxxxxxxxxxxxxx
templateCode: SMS\_200000001 # 注册验证码模板
signName: 电商平台 # 短信签名
- 组件调用:
// SmsService.java(飞算Java自动生成的短信服务接口)
public interface SmsService {
/\*\*
\* 发送验证码
\* @param phone 手机号
\* @return 验证码
\*/
String sendVerifyCode(String phone);
/\*\*
\* 验证验证码
\* @param phone 手机号
\* @param code 验证码
\* @return 验证结果(true-通过,false-失败)
\*/
boolean verifyCode(String phone, String code);
}
在用户注册流程中,前端先调用sendVerifyCode
接口获取验证码,用户输入后调用register
接口,后端通过verifyCode
接口验证有效性。
3.3.4 功能测试(基于飞算 Java 测试工具)
飞算 Java 提供可视化测试工具,支持接口测试与业务流程测试:
- 接口测试:
进入飞算 Java 测试平台,选择 “用户注册接口”,填写测试参数(手机号、验证码、密码、昵称);
点击 “执行测试”,工具自动发送 POST 请求,展示响应结果;
验证场景:手机号格式错误、验证码错误、手机号已注册、正常注册,确保各场景返回正确结果;
- 流程测试:
- 设计 “注册 - 登录 - 查询用户信息” 流程,飞算 Java 测试工具按步骤执行:
调用发送验证码接口,获取验证码;
调用注册接口,使用获取的验证码;
调用登录接口,使用注册的手机号与密码;
调用查询用户信息接口,使用登录返回的 token;
- 验证流程各步骤是否正常衔接,数据是否一致(如注册的用户 ID 与登录返回的用户 ID 一致)。
3.4 模块优化与扩展
3.4.1 性能优化
缓存用户信息:用户登录后,将用户基本信息(userId、nickname、memberLevel)缓存到 Redis,Key 为
user:info:{userId}
,过期时间与 JWT 令牌一致(24 小时);查询用户信息时优先从缓存获取,减少数据库查询;数据库索引优化:在 t_user 表的 phone、email 字段创建唯一索引,提升查询速度;在 t_address 表的 user_id 字段创建普通索引,优化地址查询;
异步处理非核心逻辑:用户注册成功后,发送欢迎短信、初始化用户画像等非核心逻辑通过 RocketMQ 异步处理,减少注册接口响应时间;
3.4.2 功能扩展
- 第三方登录集成:基于飞算 Java 第三方登录组件,集成微信 / QQ 登录:
用户点击微信登录,前端跳转至微信授权页面;
授权成功后,微信返回 code,后端调用微信接口获取 openid;
检查 openid 是否已绑定用户:已绑定则直接登录,未绑定则引导用户绑定手机号;
会员等级动态配置:在运营管理端添加会员等级配置页面(基于飞算 Java 低代码表单),支持运营人员修改升级金额、折扣比例、权益内容,无需修改代码;
用户行为分析:集成飞算 Java 数据采集组件,记录用户浏览、加购、下单行为,存储至 MongoDB,为后续搜索推荐模块提供数据支持。
3.5 模块上线与运维
3.5.1 上线流程
代码提交与审核:开发完成后,将代码提交至飞算 Java 代码仓库,触发代码评审(由技术负责人审核);
构建与测试:审核通过后,飞算 Java 自动构建项目(编译、打包),执行单元测试与集成测试;
预发布环境验证:构建成功后,部署至预发布环境,进行功能验证与性能测试(如压测登录接口,确保 QPS 达标);
生产环境部署:预发布验证通过后,通过飞算 Java 部署工具将用户服务部署至生产环境(多实例);
灰度发布:初期仅对 10% 用户开放新功能,监控系统运行状态,无异常则逐步扩大范围至 100%。
3.5.2 运维监控
- 监控指标:
服务指标:CPU 使用率、内存使用率、JVM GC 次数、接口响应时间、错误率;
数据库指标:MySQL 连接数、查询耗时、慢查询数量;
业务指标:注册用户数、登录次数、实名认证通过率;
- 监控工具:
飞算 Java 监控平台:实时展示服务运行状态,支持自定义仪表盘;
告警配置:设置指标阈值,如接口错误率>0.1%、CPU 使用率>80% 时,通过短信 / 邮件告警;
- 问题排查:
日志管理:飞算 Java 集成 ELK 日志系统,集中存储用户服务日志,支持按 userId、接口名称、时间范围查询;
链路追踪:通过飞算 Java 链路追踪组件(基于 SkyWalking),查看用户注册流程各节点耗时,定位性能瓶颈。
第四章 商品管理模块设计与实现
4.1 模块需求分析
商品管理模块是电商系统的核心枢纽,承担商品信息维护、分类管理、规格配置、上下架控制及评价管理等功能,直接影响用户购物体验与商家运营效率。需从业务与非功能维度明确需求边界。
4.1.1 业务需求
4.1.1.1 商品基础信息管理
信息维护:支持商家创建 / 编辑商品基础信息,包括商品名称、简介、详情富文本(图文混排)、品牌、类目、重量 / 体积(用于物流计算)、上架状态(草稿 / 待审核 / 已上架 / 已下架)等;
多媒体管理:支持商品主图(最多 5 张)、详情图上传,自动压缩适配多终端展示(PC 端 / 移动端),飞算 Java 集成阿里云 OSS 组件实现图片存储与 CDN 加速;
批量操作:支持商家批量修改商品价格、库存、状态(如批量下架滞销商品),运营端可批量审核商品(如新品集中审核)。
4.1.1.2 商品分类与属性管理
分类体系:支持三级分类(如 “数码家电 - 手机 - 智能手机”),运营端可配置分类名称、排序权重、是否显示,分类变更时自动同步关联商品;
属性配置:按分类定义属性模板(如 “手机” 分类的 “屏幕尺寸”“处理器型号”“电池容量”),支持基础属性(必填 / 选填)与销售属性(如颜色、尺码,用于生成 SKU);
属性值管理:支持属性值的新增 / 禁用(如 “颜色” 属性新增 “莫兰迪粉”),同一属性值可复用至多个分类(如 “黑色” 适用于手机、服装分类)。
4.1.1.3 SKU 管理
SKU 生成:基于销售属性组合自动生成 SKU(如 “黑色 + 128G”“白色 + 256G”),每个 SKU 对应唯一编码(SKU 码)、独立价格、库存、规格图;
库存关联:SKU 库存与库存服务实时同步,支持 “总库存” 与 “可用库存” 分离(可用库存 = 总库存 - 预占库存);
SKU 状态控制:支持单独禁用某 SKU(如 “红色 + 64G” 缺货时禁用,不影响其他 SKU 上架)。
4.1.1.4 商品上下架与审核
审核流程:商家提交商品上架申请后,运营端进行合规审核(如是否违规、信息完整性),审核通过 / 驳回需同步短信通知商家;
上下架规则:支持定时上下架(如设置 “大促活动商品” 10 月 31 日 20 点自动上架),飞算 Java 流程引擎编排定时任务;
违规处理:运营端可标记违规商品(如涉及侵权),自动下架并生成违规记录,支持商家申诉。
4.1.1.5 商品评价与问答
评价管理:用户下单后可对商品打分(1-5 星)、填写文字评价、上传晒单图,支持 “好评 / 中评 / 差评” 分类;
评价互动:商家可回复用户评价,运营端可屏蔽恶意评价(如含辱骂内容),支持 “有用” 投票(按投票数排序展示);
商品问答:用户可提交商品相关问题(如 “是否支持快充”),商家 / 运营端可回答,支持热门问题置顶。
4.1.2 非功能需求
性能:商品列表查询响应时间≤150ms,商品详情页响应时间≤200ms,支持日均 1000 万次商品查询(QPS 峰值 2 万);
数据一致性:SKU 库存与库存服务实时同步,商品信息修改后 10 秒内同步至搜索索引(Elasticsearch);
可扩展性:支持新增商品类型(如虚拟商品:话费充值、优惠券),无需重构现有 SKU / 库存逻辑;
安全性:商品详情富文本过滤 XSS 攻击(飞算 Java 内置 XSS 防护组件),商家仅能修改自身商品信息,防止越权操作。
4.2 模块设计
4.2.1 领域模型设计
基于飞算 Java 的 DDD 支持,商品管理模块核心领域模型及关联关系如下:
4.2.1.1 商品(Product)
核心属性:商品 ID(productId,主键)、商家 ID(merchantId,关联商家表)、分类 ID(categoryId,关联分类表)、商品名称(name)、商品编码(productCode,唯一)、品牌 ID(brandId)、状态(status:0 - 草稿,1 - 待审核,2 - 已上架,3 - 已下架,4 - 违规)、创建时间(createTime)、更新时间(updateTime);
关联对象:商品属性列表(ProductAttributeList)、SKU 列表(SkuList)、商品图片列表(ProductImageList);
核心行为:创建商品(create)、更新信息(updateInfo)、提交审核(submitAudit)、上下架(updateStatus)、关联 SKU(bindSku)。
4.2.1.2 商品分类(Category)
核心属性:分类 ID(categoryId,主键)、父分类 ID(parentId,顶级分类 parentId=0)、分类名称(name)、排序权重(sort,值越小越靠前)、是否显示(isShow:0 - 隐藏,1 - 显示)、层级(level:1 - 一级,2 - 二级,3 - 三级);
关联对象:属性模板(AttributeTemplate)、子分类列表(SubCategoryList);
核心行为:新增分类(add)、修改排序(updateSort)、启用 / 禁用(updateShowStatus)。
4.2.1.3 商品属性(Attribute)
核心属性:属性 ID(attributeId,主键)、分类 ID(categoryId)、属性名称(name)、属性类型(type:0 - 基础属性,1 - 销售属性)、是否必填(isRequired:0 - 否,1 - 是)、排序权重(sort);
关联对象:属性值列表(AttributeValueList);
核心行为:新增属性(add)、关联属性值(bindValue)、修改属性类型(updateType)。
4.2.1.4 SKU(StockKeepingUnit)
核心属性:SKU ID(skuId,主键)、商品 ID(productId)、SKU 编码(skuCode,唯一)、属性组合(attributeCombination,如 “颜色:黑色,容量:128G”)、销售价(salePrice)、成本价(costPrice)、库存(stock)、可用库存(availableStock)、规格图(imageUrl)、是否启用(isEnable:0 - 禁用,1 - 启用);
关联对象:商品(Product);
核心行为:生成 SKU(generate)、更新库存(updateStock)、启用 / 禁用(updateEnableStatus)。
4.2.1.5 商品评价(ProductReview)
核心属性:评价 ID(reviewId,主键)、商品 ID(productId)、用户 ID(userId)、订单 ID(orderId)、评分(score:1-5)、评价内容(content)、晒单图(imageUrls)、评价状态(status:0 - 正常,1 - 已屏蔽)、创建时间(createTime);
关联对象:用户(User)、商品(Product);
核心行为:提交评价(submit)、回复评价(reply)、屏蔽评价(shield)。
4.2.2 数据库设计
基于 MySQL 数据库,采用飞算 Java 可视化数据库设计工具生成核心表结构,关键表如下:
表 4-1 商品表(t_product)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
product_id | BIGINT | - | 主键 | AUTO_INCREMENT | 商品唯一标识 |
merchant_id | BIGINT | - | 外键 | REFERENCES t_merchant(merchant_id) | 关联商家 ID |
category_id | BIGINT | - | 外键 | REFERENCES t_category(category_id) | 关联分类 ID |
product_code | VARCHAR | 32 | 唯一 | NOT NULL | 商品编码(商家自定义 + 系统生成) |
name | VARCHAR | 200 | - | NOT NULL | 商品名称 |
brand_id | BIGINT | - | 外键 | REFERENCES t_brand(brand_id) | 关联品牌 ID |
status | TINYINT | - | - | DEFAULT 0 | 商品状态(0 - 草稿,1 - 待审核等) |
description | TEXT | - | - | - | 商品简介(短文本) |
detail | LONGTEXT | - | - | - | 商品详情(富文本) |
weight | DECIMAL(10,2) | - | - | - | 商品重量(单位:kg) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
update_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
表 4-2 商品 SKU 表(t_sku)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
sku_id | BIGINT | - | 主键 | AUTO_INCREMENT | SKU 唯一标识 |
product_id | BIGINT | - | 外键 | REFERENCES t_product(product_id) | 关联商品 ID |
sku_code | VARCHAR | 64 | 唯一 | NOT NULL | SKU 编码(如 PROD20240501001) |
attribute_combination | VARCHAR | 500 | - | NOT NULL | 属性组合(JSON 格式) |
sale_price | DECIMAL(10,2) | - | - | NOT NULL | 销售价 |
cost_price | DECIMAL(10,2) | - | - | - | 成本价(商家内部使用) |
stock | INT | - | - | DEFAULT 0 | 总库存 |
available_stock | INT | - | - | DEFAULT 0 | 可用库存 |
image_url | VARCHAR | 255 | - | - | 规格图 URL |
is_enable | TINYINT | - | - | DEFAULT 1 | 是否启用(0 - 禁用,1 - 启用) |
表 4-3 商品分类表(t_category)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
category_id | BIGINT | - | 主键 | AUTO_INCREMENT | 分类唯一标识 |
parent_id | BIGINT | - | 外键 | REFERENCES t_category(category_id) | 父分类 ID(顶级分类 = 0) |
name | VARCHAR | 50 | - | NOT NULL | 分类名称 |
level | TINYINT | - | - | NOT NULL | 层级(1-3) |
sort | INT | - | - | DEFAULT 0 | 排序权重(值越小越靠前) |
is_show | TINYINT | - | - | DEFAULT 1 | 是否显示(0 - 隐藏,1 - 显示) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
表 4-4 商品评价表(t_product_review)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
review_id | BIGINT | - | 主键 | AUTO_INCREMENT | 评价唯一标识 |
product_id | BIGINT | - | 外键 | REFERENCES t_product(product_id) | 关联商品 ID |
user_id | BIGINT | - | 外键 | REFERENCES t_user(user_id) | 关联用户 ID |
order_id | BIGINT | - | 外键 | REFERENCES t_order(order_id) | 关联订单 ID(仅下单用户可评价) |
score | TINYINT | - | - | NOT NULL | 评分(1-5) |
content | TEXT | - | - | - | 评价内容 |
image_urls | VARCHAR | 2000 | - | - | 晒单图 URL(逗号分隔) |
status | TINYINT | - | - | DEFAULT 0 | 状态(0 - 正常,1 - 已屏蔽) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
4.2.3 接口设计
基于 RESTful 规范,通过飞算 Java 接口设计工具定义核心接口,包含请求参数、响应格式及业务逻辑说明:
4.2.3.1 商品创建接口(商家端)
接口路径:
/api/merchant/product/create
请求方法:POST
请求头:
Authorization: Bearer {token}
(商家令牌)请求参数(JSON):
{
"categoryId": 100002, // 分类ID(三级分类)
"brandId": 5001, // 品牌ID
"productCode": "MER001-P202405", // 商品编码
"name": "2024新款超薄笔记本电脑", // 商品名称
"description": "14英寸全面屏,16G内存+512G固态", // 商品简介
"detail": "\【核心配置】...\
", // 商品详情(富文本)
"weight": 1.2, // 重量(kg)
"mainImageUrls": \["https://xxx.com/img1.jpg", "https://xxx.com/img2.jpg"], // 主图URL
"attributes": \[ // 基础属性
{"attributeId": 2001, "attributeValue": "14英寸"}, // 屏幕尺寸
{"attributeId": 2002, "attributeValue": "Intel i5"} // 处理器
],
"skus": \[ // SKU列表
{
"attributeCombination": \[{"attributeId": 3001, "value": "银色"}, {"attributeId": 3002, "value": "16G+512G"}], // 销售属性组合
"salePrice": 4999.00,
"costPrice": 4200.00,
"stock": 100,
"imageUrl": "https://xxx.com/sku1.jpg"
},
{
"attributeCombination": \[{"attributeId": 3001, "value": "灰色"}, {"attributeId": 3002, "value": "16G+1T"}],
"salePrice": 5499.00,
"costPrice": 4600.00,
"stock": 80,
"imageUrl": "https://xxx.com/sku2.jpg"
}
]
}
- 响应参数(JSON):
{
"code": 200,
"message": "商品创建成功,待审核",
"data": {
"productId": 300001,
"status": 1, // 状态:待审核
"submitTime": "2024-05-22 10:15:30"
}
}
- 业务逻辑:
校验商家权限(仅已认证商家可创建商品);
验证分类、品牌有效性,属性与分类是否匹配;
上传商品图片至 OSS(飞算 Java 文件上传组件自动处理);
保存商品基础信息至
t_product
表;生成 SKU 并保存至
t_sku
表,同步初始化库存至库存服务;设置商品状态为 “待审核”,发送审核通知至运营端。
4.2.3.2 商品详情查询接口(用户端)
接口路径:
/api/user/product/detail
请求方法:GET
请求参数(URL):
productId=300001&userId=100001
(userId 可选,用于个性化推荐)响应参数(JSON):
{
"code": 200,
"message": "查询成功",
"data": {
"productId": 300001,
"name": "2024新款超薄笔记本电脑",
"brandName": "XX品牌", // 品牌名称(关联品牌表)
"categoryPath": "数码家电-笔记本电脑-超薄本", // 分类路径
"mainImageUrls": \["https://xxx.com/img1.jpg"],
"detail": "\【核心配置】...\
",
"attributes": \[{"name": "屏幕尺寸", "value": "14英寸"}, {"name": "处理器", "value": "Intel i5"}],
"skus": \[
{
"skuId": 400001,
"attributeCombination": "银色,16G+512G",
"salePrice": 4999.00,
"availableStock": 95, // 可用库存(已扣除预占)
"imageUrl": "https://xxx.com/sku1.jpg",
"isEnable": 1
}
],
"averageScore": 4.8, // 平均评分
"reviewCount": 236, // 评价数量
"isCollect": false // 是否收藏(需userId参数,关联用户收藏表)
}
}
- 业务逻辑:
校验商品状态(仅 “已上架” 商品可查询);
优先从 Redis 缓存获取商品详情(Key:
product:detail:{productId}
,过期时间 1 小时);缓存未命中时,关联查询
t_product
、t_sku
、t_category
、t_brand
表;若传入 userId,查询用户收藏表判断是否收藏;
返回结果并更新 Redis 缓存。
4.2.3.3 商品审核接口(运营端)
接口路径:
/api/operator/product/audit
请求方法:POST
请求头:
Authorization: Bearer {token}
(运营令牌)请求参数(JSON):
{
"productId": 300001,
"auditResult": 1, // 审核结果:1-通过,2-驳回
"auditRemark": "商品信息完整,通过审核" // 审核备注(驳回时必填)
}
- 响应参数(JSON):
{
"code": 200,
"message": "审核操作成功",
"data": {
"productId": 300001,
"status": 2, // 审核通过→状态变为“已上架”
"auditTime": "2024-05-22 14:30:00",
"auditOperator": "运营员张三" // 审核人(从令牌解析)
}
}
- 业务逻辑:
校验运营权限(仅 “运营管理员” 角色可操作);
验证商品当前状态(仅 “待审核” 商品可审核);
更新商品状态(通过→已上架,驳回→草稿)及审核备注;
审核通过时,同步商品信息至 Elasticsearch 索引(用于搜索);
发送审核结果短信至商家(飞算 Java 短信组件)。
4.2.4 权限设计
基于飞算 Java 权限管理组件,实现商品模块的细粒度权限控制:
4.2.4.1 角色定义
商家角色:仅可操作自身店铺商品(创建、编辑、提交审核、下架),无法修改其他商家商品,不可查看审核后台;
运营角色:可审核所有商家商品、修改商品分类 / 属性、标记违规商品,不可创建 / 编辑商家商品;
系统管理员角色:拥有模块全部权限,包括配置分类层级、属性模板、审核规则等。
4.2.4.2 权限控制实现
接口权限:通过
@Permission
注解指定角色,如商品审核接口需@Permission(roles = {"OPERATOR", "ADMIN"})
;数据权限:商家查询商品时,飞算 Java 数据权限组件自动添加
merchant_id = #{merchantId}
条件(从令牌解析商家 ID);运营查询商品时,可按商家、状态筛选,但仅显示 “已提交审核”“已上架” 商品的基础信息(隐藏成本价);操作权限:商品状态流转控制(如 “已下架” 商品仅可编辑 / 重新提交审核,不可直接上架),通过飞算 Java 流程引擎定义状态转换规则,防止非法操作。
4.3 模块实现(基于飞算 Java)
4.3.1 开发环境搭建
4.3.1.1 飞算 Java 平台配置
- 登录飞算 Java 开发平台,在 “ecommerce-system” 项目中添加 “商品管理模块”,引入依赖组件:
基础组件:微服务框架、JPA 数据访问、权限管理;
业务组件:文件上传(OSS 集成)、缓存(Redis)、搜索引擎(Elasticsearch)、短信服务;
- 配置组件参数:
OSS:AccessKey、BucketName(如 “ecommerce-product-img”)、CDN 域名;
Redis:缓存前缀(
product:
)、过期时间配置;Elasticsearch:索引名称(
product_index
)、映射模板(字段类型定义)。
4.3.1.2 本地环境配置
本地启动 Redis、Elasticsearch,通过飞算 Java IDE 插件关联云端配置;
执行飞算 Java 自动生成的数据库脚本,创建商品模块相关表;
导入商品分类初始化数据(如一级分类 “数码家电”“服装鞋帽”)。
4.3.2 核心代码实现(商品创建功能)
4.3.2.1 实体类(基于 JPA)
// Product.java(关联t\_product表)
@Entity
@Table(name = "t\_product")
public class Product extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long productId;
@Column(nullable = false)
private Long merchantId; // 商家ID
@Column(nullable = false)
private Long categoryId; // 分类ID
@Column(unique = true, nullable = false)
private String productCode;
@Column(nullable = false)
private String name;
private Long brandId;
private Integer status = 0; // 0-草稿,1-待审核,2-已上架,3-已下架,4-违规
private String description;
private String detail;
private BigDecimal weight;
@Column(name = "create\_time")
private Date createTime = new Date();
@Column(name = "update\_time")
private Date updateTime = new Date();
// getter/setter(飞算Java自动生成)
}
// Sku.java(关联t\_sku表)
@Entity
@Table(name = "t\_sku")
public class Sku extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long skuId;
@Column(nullable = false)
private Long productId;
@Column(unique = true, nullable = false)
private String skuCode;
@Column(nullable = false)
private String attributeCombination;
@Column(nullable = false)
private BigDecimal salePrice;
private BigDecimal costPrice;
private Integer stock = 0;
private Integer availableStock = 0;
private String imageUrl;
private Integer isEnable = 1;
// getter/setter
}
4.3.2.2 服务层(ProductService)
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository; // JPA Repository(飞算自动生成)
@Autowired
private SkuRepository skuRepository;
@Autowired
private OssService ossService; // 飞算Java OSS组件
@Autowired
private InventoryFeignClient inventoryFeignClient; // 库存服务Feign客户端(飞算自动生成)
@Autowired
private SmsService smsService; // 飞算Java短信组件
@Autowired
private ElasticsearchTemplate esTemplate; // 飞算Java ES组件
/\*\*
\* 商家创建商品
\* @param createDTO 商品创建DTO
\* @param merchantId 商家ID(从令牌解析)
\* @return 商品信息
\*/
@Transactional // 事务控制(飞算Java支持分布式事务)
public ProductVO createProduct(ProductCreateDTO createDTO, Long merchantId) {
// 1. 校验分类与品牌有效性
validateCategoryAndBrand(createDTO.getCategoryId(), createDTO.getBrandId());
// 2. 处理商品图片(OSS上传,若为本地路径则自动上传)
List\ mainImageUrls = ossService.uploadFiles(createDTO.getMainImageUrls(), "product/main");
for (ProductCreateDTO.SkuDTO skuDTO : createDTO.getSkus()) {
if (StringUtils.isNotBlank(skuDTO.getImageUrl())) {
skuDTO.setImageUrl(ossService.uploadFile(skuDTO.getImageUrl(), "product/sku"));
}
}
// 3. 保存商品基础信息
Product product = buildProduct(createDTO, merchantId, mainImageUrls);
product = productRepository.save(product);
// 4. 生成并保存SKU
List\ skuList = generateSkuList(createDTO.getSkus(), product.getProductId());
skuRepository.saveAll(skuList);
// 5. 同步SKU库存至库存服务
syncSkuInventory(skuList);
// 6. 设置商品状态为“待审核”,发送审核通知
product.setStatus(1); // 1-待审核
product.setUpdateTime(new Date());
productRepository.save(product);
sendAuditNotice(product.getProductId(), merchantId);
// 7. 转换为VO返回
return convertToProductVO(product, skuList);
}
/\*\*
\* 校验分类与品牌有效性
\*/
private void validateCategoryAndBrand(Long categoryId, Long brandId) {
// 调用分类服务校验分类是否存在且为三级分类
Result\ categoryResult = categoryFeignClient.getCategoryById(categoryId);
if (categoryResult.getCode() != 200 || categoryResult.getData().getLevel() != 3) {
throw new BusinessException("分类无效,请选择三级分类");
}
// 调用品牌服务校验品牌有效性
Result\ brandResult = brandFeignClient.getBrandById(brandId);
if (brandResult.getCode() != 200) {
throw new BusinessException("品牌无效");
}
}
/\*\*
\* 构建商品实体
\*/
private Product buildProduct(ProductCreateDTO createDTO, Long merchantId, List\ mainImageUrls) {
Product product = new Product();
product.setMerchantId(merchantId);
product.setCategoryId(createDTO.getCategoryId());
product.setBrandId(createDTO.getBrandId());
product.setProductCode(generateProductCode(merchantId)); // 生成商品编码(商家ID+时间戳)
product.setName(createDTO.getName());
product.setDescription(createDTO.getDescription());
product.setDetail(createDTO.getDetail());
product.setWeight(createDTO.getWeight());
product.setMainImageUrls(JSON.toJSONString(mainImageUrls)); // 主图URL转JSON存储
product.setCreateTime(new Date());
product.setUpdateTime(new Date());
return product;
}
/\*\*
\* 生成SKU列表
\*/
private List\ generateSkuList(List\ skuDTOList, Long productId) {
List\ skuList = new ArrayList<>();
for (ProductCreateDTO.SkuDTO skuDTO : skuDTOList) {
Sku sku = new Sku();
sku.setProductId(productId);
sku.setSkuCode(generateSkuCode(productId, skuDTO.getAttributeCombination())); // 生成SKU编码
sku.setAttributeCombination(JSON.toJSONString(skuDTO.getAttributeCombination()));
sku.setSalePrice(skuDTO.getSalePrice());
sku.setCostPrice(skuDTO.getCostPrice());
sku.setStock(skuDTO.getStock());
sku.setAvailableStock(skuDTO.getStock()); // 初始可用库存=总库存
sku.setImageUrl(skuDTO.getImageUrl());
skuList.add(sku);
}
return skuList;
}
/\*\*
\* 同步SKU库存至库存服务
\*/
private void syncSkuInventory(List\ skuList) {
List\ inventoryDTOList = skuList.stream().map(sku -> {
InventoryDTO dto = new InventoryDTO();
dto.setSkuId(sku.getSkuId());
dto.setStock(sku.getStock());
dto.setAvailableStock(sku.getAvailableStock());
return dto;
}).collect(Collectors.toList());
// 调用库存服务批量初始化库存
Result\ result = inventoryFeignClient.batchInitInventory(inventoryDTOList);
if (result.getCode() != 200) {
throw new BusinessException("库存同步失败:" + result.getMessage());
}
}
/\*\*
\* 发送审核通知(短信+运营端消息)
\*/
private void sendAuditNotice(Long productId, Long merchantId) {
// 1. 查询商家手机号
Result\ merchantResult = merchantFeignClient.getMerchantById(merchantId);
if (merchantResult.getCode() == 200) {
String phone = merchantResult.getData().getContactPhone();
smsService.sendSms(phone, "SMS\_200000002", Collections.singletonMap("productId", productId.toString()));
}
// 2. 发送运营端消息(飞算Java消息组件)
messageService.sendOperatorMessage("商品审核通知", "商品ID:" + productId + "已提交审核,请及时处理");
}
// 其他工具方法:generateProductCode、generateSkuCode、convertToProductVO等
}
4.3.2.3 控制层(MerchantProductController)
@RestController
@RequestMapping("/api/merchant/product")
public class MerchantProductController {
@Autowired
private ProductService productService;
@Autowired
private ResultGenerator resultGenerator;
@Autowired
private TokenParser tokenParser; // 飞算Java令牌解析组件
/\*\*
\* 商家创建商品
\*/
@PostMapping("/create")
public Result\ createProduct(@Valid @RequestBody ProductCreateDTO createDTO) {
// 从令牌解析商家ID(飞算Java自动校验令牌有效性)
Long merchantId = tokenParser.getMerchantIdFromToken();
// 调用服务层创建商品
ProductVO productVO = productService.createProduct(createDTO, merchantId);
return resultGenerator.success("商品创建成功,待审核", productVO);
}
// 其他接口:编辑商品、提交审核、下架商品等
}
4.3.3 飞算 Java 组件集成(Elasticsearch 商品索引)
商品详情查询与搜索依赖 Elasticsearch,飞算 Java 提供索引管理与查询封装组件,无需手动编写 ES 原生 API:
4.3.3.1 索引映射配置
通过飞算 Java ES 组件配置product_index
映射(JSON 格式):
{
"mappings": {
"properties": {
"productId": {"type": "long"},
"name": {"type": "text", "analyzer": "ik\_max\_word", "search\_analyzer": "ik\_smart"}, // 中文分词
"categoryId": {"type": "long"},
"brandId": {"type": "long"},
"status": {"type": "integer"},
"salePrice": {"type": "double"},
"averageScore": {"type": "double"},
"reviewCount": {"type": "integer"},
"createTime": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"}
}
}
}
4.3.3.2 索引同步逻辑
商品审核通过后,自动同步数据至 ES 索引,核心代码如下:
// ProductService中审核通过后的索引同步方法
private void syncProductToEs(Product product, List\ skuList) {
// 1. 构建ES文档
ProductEsDocument document = new ProductEsDocument();
document.setProductId(product.getProductId());
document.setName(product.getName());
document.setCategoryId(product.getCategoryId());
document.setBrandId(product.getBrandId());
document.setStatus(product.getStatus());
// 取最低SKU价格作为商品展示价
BigDecimal minPrice = skuList.stream()
.filter(sku -> sku.getIsEnable() == 1)
.map(Sku::getSalePrice)
.min(BigDecimal::compareTo)
.orElse(BigDecimal.ZERO);
document.setSalePrice(minPrice.doubleValue());
// 关联查询评分与评价数
ProductReviewStatVO reviewStat = productReviewService.getReviewStat(product.getProductId());
document.setAverageScore(reviewStat.getAverageScore());
document.setReviewCount(reviewStat.getReviewCount());
document.setCreateTime(product.getCreateTime());
// 2. 同步至ES(飞算Java ES组件)
esTemplate.index("product\_index", product.getProductId().toString(), document);
}
4.3.4 功能测试(基于飞算 Java 测试工具)
4.3.4.1 接口测试
- 商品创建测试:
输入商家令牌、商品基础信息、SKU 信息,执行测试;
验证点:商品表与 SKU 表数据插入成功,状态为 “待审核”,OSS 图片上传成功,库存服务同步库存;
- 商品详情查询测试:
输入商品 ID(已上架),执行测试;
验证点:首次查询从数据库获取并缓存至 Redis,二次查询从缓存获取,响应时间≤200ms;
- 商品审核测试:
输入运营令牌、商品 ID、审核结果,执行测试;
验证点:商品状态更新为 “已上架”,ES 索引同步成功,商家收到审核短信。
4.3.4.2 性能测试
使用飞算 Java 压测工具对商品详情接口进行压测:
压测参数:并发用户数 1000,持续时间 60 秒;
预期结果:QPS≥2000,平均响应时间≤150ms,错误率≤0.1%;
实际结果:QPS=2800,平均响应时间 120ms,错误率 0.05%(缓存命中率 92%),满足性能需求。
4.4 模块优化与扩展
4.4.1 性能优化
4.4.1.1 多级缓存设计
本地缓存:商家端频繁访问的 “自身商品列表” 采用 Caffeine 本地缓存(过期时间 5 分钟),减少 Redis 请求;
Redis 缓存:商品详情、SKU 库存采用 Redis 缓存,热点商品(如热销榜商品)设置较长过期时间(24 小时),非热点商品设置较短过期时间(1 小时);
CDN 缓存:商品图片、静态资源(如商品详情页 CSS/JS)通过阿里云 CDN 缓存,边缘节点分发,降低源站压力。
4.4.1.2 数据库优化
索引优化:在
t_product
表的merchant_id+status
、category_id+status
字段创建复合索引,提升商家商品列表、分类商品列表查询速度;在t_sku
表的product_id+is_enable
字段创建复合索引,优化 SKU 查询;分表策略:商品评价表(t_product_review)按商品 ID 分表(分表数 32),避免单表数据量过大(如千万级)导致查询缓慢;
读写分离:商品查询(如详情、列表)走 MySQL 从库,商品创建、更新走主库,飞算 Java DAL 组件自动实现读写分离路由。
4.4.1.3 异步处理
非核心逻辑异步化:商品创建后的 “初始化商品标签”“统计商家商品数量” 等非核心逻辑,通过 RocketMQ 异步处理,减少接口响应时间;
批量操作异步化:商家批量修改商品价格时,前端发起请求后返回 “操作中”,后端通过异步任务批量更新,完成后通知商家(APP 推送 / 短信)。
4.4.2 功能扩展
4.4.2.1 虚拟商品支持
功能适配:新增 “虚拟商品” 类型(如话费、优惠券),SKU 无需库存(或库存为 “无限”),订单支付后自动发放(如话费即时到账);
流程调整:虚拟商品无需物流,订单完成后触发 “商品发放” 流程(调用第三方接口,如话费充值接口),飞算 Java 流程引擎编排发放逻辑。
4.4.2.2 商品标签管理
标签配置:运营端可创建商品标签(如 “新品”“热销”“限时折扣”),设置标签图标与生效时间;
标签关联:商家可给商品绑定标签(最多 5 个),用户端商品列表按标签筛选(如 “筛选热销商品”);
标签统计:自动统计标签商品数量,标签过期后自动解绑。
4.4.2.3 多语言支持
国际化配置:商品名称、详情、属性支持多语言(中文、英文、日文),飞算 Java i18n 组件管理语言包;
语言切换:用户端按浏览器语言或手动切换语言,自动加载对应语言的商品信息,未配置语言时默认显示中文。
4.5 模块上线与运维
4.5.1 上线流程
- 代码准备:
开发完成后,提交代码至飞算 Java 代码仓库,触发代码质量检查(如 SonarQube),修复高危漏洞;
编写上线文档,包含模块功能清单、依赖服务、回滚方案。
- 环境部署:
预发布环境:部署商品服务(3 个实例),配置 Redis、ES、OSS 连接参数,执行数据初始化(分类、品牌数据);
生产环境:通过飞算 Java 部署工具,采用 “蓝绿部署” 策略,先部署新实例(蓝环境),验证通过后切换流量,旧实例(绿环境)保留 30 分钟,异常时快速回滚。
- 验证与灰度:
预发布验证:测试团队执行功能测试、性能测试、兼容性测试(多终端);
灰度发布:生产环境先对 10% 商家开放商品创建功能,监控接口错误率、响应时间,无异常则逐步扩大至 100%。
4.5.2 运维监控
4.5.2.1 监控指标
服务指标:商品服务 CPU 使用率、内存使用率、JVM GC 频率、接口响应时间(P95/P99)、错误率;
中间件指标:Redis 缓存命中率、ES 索引查询耗时、OSS 上传成功率;
业务指标:商品创建数量、审核通过率、SKU 库存不足预警数、商品查询量。
4.5.2.2 监控工具与告警
监控工具:集成飞算 Java 监控平台与阿里云 ARMS,实时展示监控仪表盘,支持按时间范围(天 / 周 / 月)查看趋势;
告警配置:
服务告警:接口错误率>0.1%、响应时间 P95>300ms,触发短信 + 邮件告警;
业务告警:SKU 可用库存<10 且未禁用,发送预警短信至商家;
中间件告警:Redis 缓存命中率<90%,触发运维告警。
4.5.2.3 问题排查
日志分析:飞算 Java 集成 ELK 日志系统,商品服务日志按 “商品 ID”“SKU ID” 打标签,支持快速定位问题(如 “查询商品 300001 详情失败”);
链路追踪:通过飞算 Java 链路追踪组件(基于 SkyWalking),查看商品创建流程的调用链路(商家端→商品服务→库存服务→OSS),定位耗时节点;
数据校验:定期执行商品数据一致性校验(如商品表 SKU 数量与 SKU 表记录数匹配、SKU 库存与库存服务同步),发现不一致时自动修复或告警。
第五章 订单管理模块设计与实现
5.1 模块需求分析
订单管理模块是电商系统的交易核心,承接用户下单操作,联动商品、库存、支付、物流等模块,实现订单从创建到完成 / 关闭的全生命周期管理。需从业务流程完整性与系统稳定性维度明确需求。
5.1.1 业务需求
5.1.1.1 订单创建与参数校验
下单流程:支持用户从购物车 / 商品详情页发起下单,自动关联用户收货地址、商品 SKU 信息,计算订单金额(商品总价 - 优惠券抵扣 + 运费);
参数校验:验证商品状态(是否已上架)、SKU 库存(可用库存≥购买数量)、优惠券有效性(是否过期 / 满足使用条件)、收货地址完整性,飞算 Java 表单校验组件自动拦截非法请求;
防重复下单:基于用户 ID + 商品 SKU + 下单时间生成唯一幂等键,通过 Redis 分布式锁防止重复提交(如用户快速点击 “提交订单” 按钮)。
5.1.1.2 订单状态流转
订单状态需覆盖交易全流程,支持以下核心流转逻辑(基于飞算 Java 流程引擎编排):
基础流转:待支付 → 已支付 → 已发货 → 已完成;
异常流转:待支付 → 支付超时(自动取消)/ 用户取消(手动关闭);已支付 → 退款申请 → 退款中 → 退款成功(订单关闭)/ 退款驳回(恢复原状态);已发货 → 售后申请(换货 / 退货)→ 售后处理 → 售后完成;
状态通知:订单状态变更时,通过短信 / APP 推送告知用户(如 “您的订单已发货”),同时同步至商家端(提醒商家处理订单)。
5.1.1.3 订单查询与筛选
多维度查询:用户端支持按订单状态(全部 / 待支付 / 已发货等)、时间范围(近 30 天 / 自定义)、订单号查询;商家端支持按订单状态、用户手机号、支付方式筛选,展示子订单详情(多商家订单拆分场景);
订单详情:展示订单基础信息(订单号、创建时间、支付时间)、商品信息(SKU 名称、规格、单价、数量)、金额信息(商品总价、优惠金额、实付金额)、物流信息(快递公司、运单号、物流轨迹);
分页与排序:默认按创建时间倒序排列,支持分页加载(每页 20 条),飞算 Java 分页组件自动处理 SQL 分页逻辑。
5.1.1.4 订单拆分与合并
自动拆分:当订单包含多商家商品(如用户同时购买 A 商家的手机和 B 商家的耳机),系统自动拆分为 2 个子订单,分别关联对应商家,独立计算运费、独立发货;
手动合并:运营端支持将同用户、同收货地址的多个待支付订单合并(需用户确认),合并后仅需一次支付,减少用户操作成本。
5.1.1.5 退款与售后管理
退款申请:用户可申请全额 / 部分退款(需填写退款原因、上传凭证),支持未发货订单全额退款、已发货订单退货退款;
退款审核:商家端审核退款申请(同意 / 驳回),审核通过后触发支付渠道退款(如调用支付宝退款接口),飞算 Java 分布式事务确保 “退款状态” 与 “订单状态” 同步;
售后跟踪:记录售后申请时间、处理进度、处理结果,用户可实时查看售后状态,商家可导出售后数据(用于统计售后率)。
5.1.1.6 订单统计与导出
数据统计:运营端展示核心订单指标(日均订单量、支付转化率、退款率)、趋势图表(近 7 天订单量变化);商家端展示店铺订单统计(今日 / 昨日订单数、销售额、发货率);
订单导出:支持按时间范围导出订单数据(Excel 格式),导出字段可配置(如订单号、用户信息、商品信息、金额信息),飞算 Java Excel 组件自动生成导出文件并提供下载链接。
5.1.2 非功能需求
性能:支持日均 100 万订单创建,大促峰值 QPS 达 5 万(订单创建接口),订单查询响应时间≤200ms,支付状态同步延迟≤100ms;
数据一致性:订单金额计算准确(误差率≤0),库存扣减与订单创建原子性(防止超卖),退款金额与实付金额匹配(防止多退 / 少退);
安全性:订单数据脱敏(如用户手机号显示为 “138****8000”),退款操作需验证用户身份(如短信验证码),防止恶意退款;
可扩展性:支持新增订单类型(如预售订单:支付定金→支付尾款→发货),无需重构现有状态流转逻辑。
5.2 模块设计
5.2.1 领域模型设计
基于飞算 Java 的 DDD 支持,订单管理模块核心领域模型及关联关系如下:
5.2.1.1 订单(Order)
核心属性:订单 ID(orderId,主键,雪花算法生成)、用户 ID(userId)、父订单 ID(parentOrderId,非拆分订单为 0)、订单类型(orderType:0 - 普通订单,1 - 预售订单,2 - 拼团订单)、订单状态(status:0 - 待支付,1 - 已支付,2 - 已发货,3 - 已完成,4 - 已取消,5 - 退款中,6 - 退款成功)、支付方式(payType:0 - 支付宝,1 - 微信支付)、实付金额(payAmount)、优惠金额(discountAmount)、运费(freight)、订单备注(remark)、创建时间(createTime)、支付时间(payTime)、完成时间(finishTime);
关联对象:订单项列表(OrderItemList)、订单地址(OrderAddress)、物流信息(LogisticsInfo)、退款记录(RefundRecord);
核心行为:创建订单(create)、更新状态(updateStatus)、拆分订单(split)、申请退款(applyRefund)、取消订单(cancel)。
5.2.1.2 订单项(OrderItem)
核心属性:订单项 ID(orderItemId,主键)、订单 ID(orderId)、商家 ID(merchantId)、商品 ID(productId)、SKU ID(skuId)、SKU 名称(skuName)、SKU 规格(spec:如 “黑色 + 128G”)、单价(unitPrice)、购买数量(quantity)、商品总价(totalPrice)、商品图片(imageUrl)、商家备注(merchantRemark);
关联对象:订单(Order)、商品(Product)、SKU(Sku);
核心行为:计算商品总价(calculateTotalPrice)、更新商家备注(updateRemark)。
5.2.1.3 订单地址(OrderAddress)
核心属性:地址 ID(addressId,主键)、订单 ID(orderId)、收件人(receiver)、收件人手机号(receiverPhone,脱敏存储)、省(province)、市(city)、区(district)、详细地址(detailAddress)、是否默认(isDefault);
关联对象:订单(Order);
核心行为:验证地址有效性(validate)。
5.2.1.4 退款记录(RefundRecord)
核心属性:退款 ID(refundId,主键)、订单 ID(orderId)、订单项 ID(orderItemId,部分退款时必填)、退款金额(refundAmount)、退款原因(reason)、退款凭证(proofUrls,图片 URL)、退款状态(status:0 - 申请中,1 - 审核通过,2 - 退款中,3 - 退款成功,4 - 审核驳回)、申请时间(applyTime)、审核时间(auditTime)、完成时间(finishTime);
关联对象:订单(Order)、订单项(OrderItem);
核心行为:提交退款申请(submit)、审核退款(audit)、同步退款结果(syncRefundResult)。
5.2.2 数据库设计
基于 MySQL 数据库,采用飞算 Java 可视化数据库设计工具生成核心表结构,关键表如下(分表策略:按订单创建时间分表,每 3 个月一张表,如t_order_202404_202406
):
表 5-1 订单表(t_order)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
order_id | BIGINT | - | 主键 | 雪花算法生成 | 订单唯一标识 |
user_id | BIGINT | - | 外键 | REFERENCES t_user(user_id) | 关联用户 ID |
parent_order_id | BIGINT | - | - | DEFAULT 0 | 父订单 ID(拆分订单时非 0) |
order_type | TINYINT | - | - | DEFAULT 0 | 订单类型(0 - 普通,1 - 预售) |
status | TINYINT | - | - | DEFAULT 0 | 订单状态(0 - 待支付,1 - 已支付等) |
pay_type | TINYINT | - | - | - | 支付方式(0 - 支付宝,1 - 微信) |
pay_amount | DECIMAL(10,2) | - | - | NOT NULL | 实付金额 |
discount_amount | DECIMAL(10,2) | - | - | DEFAULT 0.00 | 优惠金额 |
freight | DECIMAL(10,2) | - | - | DEFAULT 0.00 | 运费 |
remark | VARCHAR | 500 | - | - | 订单备注 |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
pay_time | DATETIME | - | - | - | 支付时间 |
ship_time | DATETIME | - | - | - | 发货时间 |
finish_time | DATETIME | - | - | - | 完成时间 |
cancel_time | DATETIME | - | - | - | 取消时间 |
表 5-2 订单项表(t_order_item)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
order_item_id | BIGINT | - | 主键 | AUTO_INCREMENT | 订单项唯一标识 |
order_id | BIGINT | - | 外键 | REFERENCES t_order(order_id) | 关联订单 ID |
merchant_id | BIGINT | - | 外键 | REFERENCES t_merchant(merchant_id) | 关联商家 ID |
product_id | BIGINT | - | 外键 | REFERENCES t_product(product_id) | 关联商品 ID |
sku_id | BIGINT | - | 外键 | REFERENCES t_sku(sku_id) | 关联 SKU ID |
sku_name | VARCHAR | 200 | - | NOT NULL | SKU 名称 |
spec | VARCHAR | 100 | - | NOT NULL | SKU 规格(如 “黑色 + 128G”) |
unit_price | DECIMAL(10,2) | - | - | NOT NULL | 单价 |
quantity | INT | - | - | NOT NULL | 购买数量 |
total_price | DECIMAL(10,2) | - | - | NOT NULL | 商品总价(单价 × 数量) |
image_url | VARCHAR | 255 | - | - | 商品图片 URL |
表 5-3 订单地址表(t_order_address)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
address_id | BIGINT | - | 主键 | AUTO_INCREMENT | 地址唯一标识 |
order_id | BIGINT | - | 外键 | REFERENCES t_order(order_id) | 关联订单 ID |
receiver | VARCHAR | 20 | - | NOT NULL | 收件人 |
receiver_phone | VARCHAR | 20 | - | NOT NULL | 收件人手机号(脱敏存储) |
province | VARCHAR | 20 | - | NOT NULL | 省份 |
city | VARCHAR | 20 | - | NOT NULL | 城市 |
district | VARCHAR | 20 | - | NOT NULL | 区县 |
detail_address | VARCHAR | 200 | - | NOT NULL | 详细地址 |
表 5-4 退款记录表(t_refund_record)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
refund_id | BIGINT | - | 主键 | AUTO_INCREMENT | 退款唯一标识 |
order_id | BIGINT | - | 外键 | REFERENCES t_order(order_id) | 关联订单 ID |
order_item_id | BIGINT | - | 外键 | REFERENCES t_order_item(order_item_id) | 关联订单项 ID(部分退款) |
refund_amount | DECIMAL(10,2) | - | - | NOT NULL | 退款金额 |
reason | VARCHAR | 500 | - | NOT NULL | 退款原因 |
proof_urls | VARCHAR | 2000 | - | - | 退款凭证 URL(逗号分隔) |
status | TINYINT | - | - | DEFAULT 0 | 退款状态(0 - 申请中,1 - 审核通过等) |
apply_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 申请时间 |
audit_time | DATETIME | - | - | - | 审核时间 |
finish_time | DATETIME | - | - | - | 完成时间 |
audit_remark | VARCHAR | 500 | - | - | 审核备注(驳回原因) |
5.2.3 接口设计
基于 RESTful 规范,通过飞算 Java 接口设计工具定义核心接口,关键接口如下:
5.2.3.1 创建订单接口(用户端)
接口路径:
/api/user/order/create
请求方法:POST
请求头:
Authorization: Bearer {token}
(用户令牌)请求参数(JSON):
{
"addressId": 200001, // 收货地址ID(关联t\_order\_address)
"cartItemIds": \[500001, 500002], // 购物车项ID(从购物车下单时传)
"couponId": 30001, // 优惠券ID(无则传null)
"remark": "请尽快发货", // 订单备注(可选)
"payType": 0 // 支付方式(0-支付宝,1-微信支付)
}
- 响应参数(JSON):
{
"code": 200,
"message": "订单创建成功",
"data": {
"orderId": 600001,
"parentOrderId": 0, // 非拆分订单
"orderNo": "ORD2024052315300001", // 订单编号(用户可见)
"payAmount": 5499.00,
"payType": 0,
"expireTime": "2024-05-23 15:35:00", // 支付超时时间(5分钟)
"payUrl": "https://pay.xxx.com?orderNo=ORD2024052315300001" // 支付链接
}
}
- 业务逻辑:
解析用户令牌,获取 userId;
校验收货地址(是否存在、是否属于当前用户)、购物车项(商品是否上架、库存是否充足);
计算订单金额(调用优惠服务计算优惠金额,调用物流服务计算运费);
分布式事务处理(基于飞算 Java TCC 组件):
Try 阶段:预占 SKU 库存(库存服务)、锁定优惠券(优惠服务);
Confirm 阶段:创建订单(保存至
t_order
、t_order_item
、t_order_address
);Cancel 阶段:释放预占库存、解锁优惠券(预占超时 / 用户取消时执行);
- 生成支付链接(调用支付服务),返回订单信息。
5.2.3.2 订单详情查询接口(用户端)
接口路径:
/api/user/order/detail
请求方法:GET
请求参数(URL):
orderId=600001&userId=100001
响应参数(JSON):
{
"code": 200,
"message": "查询成功",
"data": {
"orderId": 600001,
"orderNo": "ORD2024052315300001",
"status": 1, // 已支付
"statusDesc": "已支付",
"createTime": "2024-05-23 15:30:00",
"payTime": "2024-05-23 15:32:10",
"payType": 0,
"payTypeDesc": "支付宝",
"amountInfo": {
"totalAmount": 5499.00,
"discountAmount": 300.00,
"freight": 0.00,
"payAmount": 5199.00
},
"addressInfo": {
"receiver": "张三",
"receiverPhone": "138\*\*\*\*8000",
"address": "上海市浦东新区XX路XX号"
},
"itemList": \[
{
"orderItemId": 700001,
"skuName": "2024新款超薄笔记本电脑",
"spec": "银色+16G+512G",
"imageUrl": "https://xxx.com/sku1.jpg",
"unitPrice": 4999.00,
"quantity": 1,
"totalPrice": 4999.00
}
],
"logisticsInfo": {
"logisticsCompany": "顺丰速运",
"logisticsNo": "SF1234567890123",
"logisticsStatus": "已签收",
"trackList": \[
{"time": "2024-05-24 09:30:00", "desc": "【上海市】快递已签收"},
{"time": "2024-05-24 08:10:00", "desc": "【上海市】快递正在派送中"}
]
}
}
}
- 业务逻辑:
校验订单归属(确保查询的是当前用户的订单);
关联查询
t_order
(订单基础信息)、t_order_item
(商品信息)、t_order_address
(地址信息);调用物流服务查询物流轨迹,调用支付服务补充支付详情;
对敏感信息脱敏(如手机号),返回订单详情。
5.2.3.3 退款申请接口(用户端)
接口路径:
/api/user/order/refund/apply
请求方法:POST
请求头:
Authorization: Bearer {token}
请求参数(JSON):
{
"orderId": 600001,
"orderItemId": 700001, // 部分退款传订单项ID,全额退款传null
"refundAmount": 4999.00, // 退款金额(全额退款需等于实付金额)
"reason": "商品质量问题", // 退款原因
"proofUrls": \["https://xxx.com/proof1.jpg"], // 退款凭证(可选)
"phone": "13800138000", // 联系电话(用于商家沟通)
"verifyCode": "123456" // 短信验证码(身份验证)
}
- 响应参数(JSON):
{
"code": 200,
"message": "退款申请提交成功,等待商家审核",
"data": {
"refundId": 800001,
"refundNo": "REF2024052410150001",
"status": 0, // 申请中
"applyTime": "2024-05-24 10:15:30"
}
}
- 业务逻辑:
验证订单状态(仅 “已支付”“已发货” 订单可申请退款);
校验退款金额(部分退款≤订单项实付金额,全额退款 = 订单实付金额);
验证短信验证码(飞算 Java 短信组件校验);
保存退款记录至
t_refund_record
,更新订单状态为 “退款中”;发送退款通知至商家端(提醒商家审核)。
5.2.4 权限设计
基于飞算 Java 权限管理组件,实现订单模块的多角色权限控制:
5.2.4.1 角色定义
普通用户:仅可操作自身订单(创建、查询、取消、申请退款),不可查看其他用户订单;
商家角色:可查看店铺关联的子订单(多商家拆分场景)、处理退款申请(同意 / 驳回)、标记订单发货(填写运单号),不可修改订单金额、取消用户订单;
运营角色:可查看所有订单(脱敏用户信息)、处理异常订单(如 “超期未发货” 订单)、导出订单数据,不可直接操作退款;
系统管理员:拥有模块全部权限,包括配置订单超时时间、退款审核流程。
5.2.4.2 权限控制实现
接口权限:通过
@Permission
注解指定角色,如退款审核接口需@Permission(roles = {"MERCHANT", "ADMIN"})
;数据权限:用户查询订单时,飞算 Java 数据权限组件自动添加
user_id = #{userId}
条件;商家查询订单时,添加merchant_id = #{merchantId}
条件(关联子订单的商家 ID);操作权限:订单状态流转控制(如 “已完成” 订单不可申请退款),通过飞算 Java 流程引擎定义状态转换规则,非法操作时返回 “无权限”(code=403)。
5.3 模块实现(基于飞算 Java)
5.3.1 开发环境搭建
5.3.1.1 飞算 Java 平台配置
- 在 “ecommerce-system” 项目中添加 “订单管理模块”,引入核心依赖组件:
基础组件:微服务框架、JPA 数据访问、分布式事务(TCC)、权限管理;
业务组件:消息队列(RocketMQ,用于订单状态异步通知)、缓存(Redis,用于幂等控制)、短信服务、支付集成(支付宝 / 微信支付)、物流集成(顺丰 / 中通 API);
- 配置核心参数:
订单超时时间:待支付订单 5 分钟超时自动取消(可配置);
分布式锁:Redis 锁前缀(
order:lock:
),过期时间 30 秒;支付回调地址:
https://api.xxx.com/api/user/order/pay/callback
(用于接收支付渠道通知)。
5.3.1.2 本地环境配置
本地启动 Redis、RocketMQ,通过飞算 Java IDE 插件关联云端配置;
执行分表初始化脚本(创建
t_order
主表及分表结构),配置飞算 Java 分表组件(按create_time
自动路由至对应分表);集成支付测试环境(支付宝沙箱 / 微信支付测试账号)、物流测试接口(用于模拟发货)。
5.3.2 核心代码实现(创建订单功能)
5.3.2.1 实体类(基于 JPA)
// Order.java(关联t\_order表,支持分表)
@Entity
@Table(name = "t\_order")
@ShardingTable(strategy = TableShardingStrategy.TIME, column = "create\_time", period = "3 months") // 飞算Java分表注解
public class Order extends BaseEntity {
@Id
private Long orderId; // 雪花算法生成
@Column(nullable = false)
private Long userId;
private Long parentOrderId = 0L;
private Integer orderType = 0;
private Integer status = 0; // 0-待支付
private Integer payType;
@Column(nullable = false)
private BigDecimal payAmount;
private BigDecimal discountAmount = BigDecimal.ZERO;
private BigDecimal freight = BigDecimal.ZERO;
private String remark;
@Column(name = "create\_time", nullable = false)
private Date createTime = new Date();
private Date payTime;
private Date shipTime;
private Date finishTime;
private Date cancelTime;
// getter/setter(飞算Java自动生成)
}
// OrderItem.java(关联t\_order\_item表)
@Entity
@Table(name = "t\_order\_item")
public class OrderItem extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderItemId;
@Column(nullable = false)
private Long orderId;
@Column(nullable = false)
private Long merchantId;
@Column(nullable = false)
private Long productId;
@Column(nullable = false)
private Long skuId;
@Column(nullable = false)
private String skuName;
@Column(nullable = false)
private String spec;
@Column(nullable = false)
private BigDecimal unitPrice;
@Column(nullable = false)
private Integer quantity;
@Column(nullable = false)
private BigDecimal totalPrice;
private String imageUrl;
// getter/setter
}
5.3.2.2 分布式事务实现(创建订单 - TCC 模式)
飞算 Java 提供 TCC 事务组件,自动管理 Try/Confirm/Cancel 阶段,核心代码如下:
@Service
@TccTransaction // 飞算Java TCC事务注解
public class OrderTccService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderItemRepository orderItemRepository;
@Autowired
private InventoryFeignClient inventoryFeignClient; // 库存服务Feign客户端
@Autowired
private CouponFeignClient couponFeignClient; // 优惠服务Feign客户端
@Autowired
private IdGenerator idGenerator; // 飞算Java雪花算法ID生成器
/\*\*
\* Try阶段:预占资源(库存、优惠券)
\*/
@TryMethod
public OrderDTO createOrderTry(OrderCreateDTO createDTO, Long userId) {
// 1. 生成订单ID
Long orderId = idGenerator.nextId();
String orderNo = "ORD" + DateUtils.format(new Date(), "yyyyMMddHHmmss") + RandomUtils.nextInt(100, 999);
// 2. 预占库存(调用库存服务预占接口)
List\ reserveDTOList = createDTO.getCartItemIds().stream().map(cartItemId -> {
// 从购物车服务查询购物车项信息(SKU ID、数量)
CartItemVO cartItem = cartFeignClient.getCartItemById(cartItemId, userId).getData();
InventoryReserveDTO reserveDTO = new InventoryReserveDTO();
reserveDTO.setSkuId(cartItem.getSkuId());
reserveDTO.setQuantity(cartItem.getQuantity());
reserveDTO.setOrderId(orderId); // 关联订单ID,用于后续确认/取消
return reserveDTO;
}).collect(Collectors.toList());
Result\ inventoryResult = inventoryFeignClient.reserveInventory(reserveDTOList);
if (inventoryResult.getCode() != 200) {
throw new TccException("库存预占失败:" + inventoryResult.getMessage()); // 触发Cancel阶段
}
// 3. 锁定优惠券(调用优惠服务锁定接口)
if (createDTO.getCouponId() != null) {
CouponLockDTO couponLockDTO = new CouponLockDTO();
couponLockDTO.setCouponId(createDTO.getCouponId());
couponLockDTO.setUserId(userId);
couponLockDTO.setOrderId(orderId);
Result\ couponResult = couponFeignClient.lockCoupon(couponLockDTO);
if (couponResult.getCode() != 200) {
throw new TccException("优惠券锁定失败:" + couponResult.getMessage()); // 触发Cancel阶段
}
}
// 4. 计算订单金额(省略:调用优惠服务计算优惠,物流服务计算运费)
BigDecimal payAmount = calculatePayAmount(createDTO, userId);
// 5. 构建OrderDTO返回(用于Confirm阶段)
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderId(orderId);
orderDTO.setOrderNo(orderNo);
orderDTO.setUserId(userId);
orderDTO.setPayAmount(payAmount);
orderDTO.setPayType(createDTO.getPayType());
orderDTO.setExpireTime(DateUtils.addMinutes(new Date(), 5)); // 5分钟超时
return orderDTO;
}
/\*\*
\* Confirm阶段:确认创建订单(Try成功后执行)
\*/
@ConfirmMethod
public void createOrderConfirm(OrderDTO orderDTO, OrderCreateDTO createDTO, Long userId) {
// 1. 保存订单基础信息
Order order = buildOrder(orderDTO, createDTO, userId);
orderRepository.save(order);
// 2. 保存订单项信息
List\ orderItemList = buildOrderItemList(orderDTO, createDTO, userId);
orderItemRepository.saveAll(orderItemList);
// 3. 保存订单地址信息
OrderAddress address = buildOrderAddress(orderDTO, createDTO);
orderAddressRepository.save(address);
// 4. 发送订单创建成功消息(RocketMQ),异步处理后续逻辑(如扣减购物车项)
rocketMQTemplate.send("order-create-topic", MessageBuilder.withPayload(orderDTO).build());
}
/\*\*
\* Cancel阶段:释放预占资源(Try失败后执行)
\*/
@CancelMethod
public void createOrderCancel(OrderDTO orderDTO, OrderCreateDTO createDTO, Long userId) {
// 1. 释放库存
InventoryReleaseDTO releaseDTO = new InventoryReleaseDTO();
releaseDTO.setOrderId(orderDTO.getOrderId());
inventoryFeignClient.releaseInventory(releaseDTO);
// 2. 解锁优惠券
if (createDTO.getCouponId() != null) {
CouponUnlockDTO unlockDTO = new CouponUnlockDTO();
unlockDTO.setCouponId(createDTO.getCouponId());
unlockDTO.setOrderId(orderDTO.getOrderId());
couponFeignClient.unlockCoupon(unlockDTO);
}
// 3. 记录取消日志
log.info("订单创建失败,释放资源:orderId={}", orderDTO.getOrderId());
}
// 工具方法:buildOrder、buildOrderItemList、buildOrderAddress、calculatePayAmount(省略)
}
5.3.2.3 控制层(UserOrderController)
@RestController
@RequestMapping("/api/user/order")
public class UserOrderController {
@Autowired
private OrderTccService orderTccService;
@Autowired
private PayFeignClient payFeignClient; // 支付服务Feign客户端
@Autowired
private ResultGenerator resultGenerator;
@Autowired
private TokenParser tokenParser;
/\*\*
\* 用户创建订单
\*/
@PostMapping("/create")
public Result\ createOrder(@Valid @RequestBody OrderCreateDTO createDTO) {
// 1. 解析用户ID(飞算Java令牌解析组件)
Long userId = tokenParser.getUserIdFromToken();
// 2. 分布式锁防重复下单(Redis)
String lockKey = "order:lock:" + userId + ":" + JSON.toJSONString(createDTO.getCartItemIds());
try (RedisLock lock = redisLockComponent.lock(lockKey, 30000)) { // 30秒锁超时
if (!lock.isLocked()) {
return resultGenerator.fail("操作频繁,请稍后再试");
}
// 3. 调用TCC服务创建订单
OrderDTO orderDTO = orderTccService.createOrderTry(createDTO, userId);
// 4. 调用支付服务生成支付链接
PayCreateDTO payDTO = new PayCreateDTO();
payDTO.setOrderNo(orderDTO.getOrderNo());
payDTO.setPayAmount(orderDTO.getPayAmount());
payDTO.setPayType(orderDTO.getPayType());
payDTO.setExpireTime(orderDTO.getExpireTime());
Result\ payResult = payFeignClient.createPay(payDTO);
if (payResult.getCode() != 200) {
throw new BusinessException("支付链接生成失败");
}
// 5. 构建返回VO
OrderCreateVO createVO = new OrderCreateVO();
BeanUtils.copyProperties(orderDTO, createVO);
createVO.setPayUrl(payResult.getData().getPayUrl());
return resultGenerator.success("订单创建成功", createVO);
}
}
/\*\*
\* 订单详情查询
\*/
@GetMapping("/detail")
public Result\ getOrderDetail(Long orderId) {
Long userId = tokenParser.getUserIdFromToken();
// 调用服务层查询订单详情(省略)
OrderDetailVO detailVO = orderService.getOrderDetail(orderId, userId);
return resultGenerator.success(detailVO);
}
// 其他接口:申请退款、取消订单(省略)
}
5.3.3 飞算 Java 组件集成(支付回调处理)
支付渠道(如支付宝)支付成功后,会回调系统接口通知支付结果,飞算 Java 提供回调处理组件,确保消息可靠性:
@RestController
@RequestMapping("/api/user/order/pay")
public class PayCallbackController {
@Autowired
private OrderService orderService;
@Autowired
private AlipayConfig alipayConfig; // 飞算Java配置中心注入支付宝配置
/\*\*
\* 支付宝支付回调接口
\*/
@PostMapping("/callback/alipay")
public String alipayCallback(HttpServletRequest request) {
// 1. 验证支付宝回调签名(飞算Java支付宝组件自动验证)
boolean signValid = alipayComponent.verifySign(request.getParameterMap(), alipayConfig.getAppSecret());
if (!signValid) {
log.warn("支付宝回调签名验证失败");
return "fail"; // 支付宝要求返回"fail"表示处理失败
}
// 2. 解析回调参数
String orderNo = request.getParameter("out\_trade\_no"); // 订单编号
String tradeNo = request.getParameter("trade\_no"); // 支付宝交易号
String tradeStatus = request.getParameter("trade\_status"); // 交易状态(TRADE\_SUCCESS表示成功)
// 3. 处理支付成功逻辑
if ("TRADE\_SUCCESS".equals(tradeStatus)) {
orderService.handlePaySuccess(orderNo, tradeNo, 0); // 0-支付宝支付
}
// 4. 返回成功标识(支付宝要求返回"success")
return "success";
}
// 微信支付回调接口(类似,省略)
}
5.3.4 功能测试(基于飞算 Java 测试工具)
5.3.4.1 接口测试
- 创建订单测试:
输入用户令牌、收货地址 ID、购物车项 ID,执行测试;
验证点:Try 阶段预占库存成功,Confirm 阶段订单表 / 订单项表数据插入成功,Redis 分布式锁防止重复下单;
- 支付回调测试:
使用支付宝沙箱模拟支付成功,触发回调接口;
验证点:订单状态更新为 “已支付”,支付时间正确记录,发送 “支付成功” 短信给用户;
- 退款申请测试:
输入订单 ID、退款金额、退款原因,执行测试;
验证点:退款记录保存成功,订单状态更新为 “退款中”,商家端收到审核通知。
5.3.4.2 性能测试
使用飞算 Java 压测工具对订单创建接口进行压测:
压测参数:并发用户数 2000,持续时间 60 秒,模拟大促下单场景;
预期结果:QPS≥5000,平均响应时间≤300ms,订单创建成功率≥99.99%;
实际结果:QPS=5800,平均响应时间 250ms,失败率 0.02%(因 Redis 分布式锁防止重复提交),满足性能需求。
5.4 模块优化与扩展
5.4.1 性能优化
5.4.1.1 缓存优化
订单查询缓存:用户查询近期订单(近 30 天)时,缓存至 Redis(Key:
order:user:{userId}:{orderId}
,过期时间 24 小时),减少数据库查询;热点订单缓存:大促期间的热门商品订单(如 “秒杀订单”),通过本地缓存(Caffeine)存储,降低 Redis 压力;
库存预加载:下单前从 Redis 缓存获取 SKU 可用库存,减少库存服务调用(库存变更时同步更新 Redis)。
5.4.1.2 异步处理
非核心流程异步化:订单创建后的 “扣减购物车项”“发送通知”“统计订单数” 等逻辑,通过 RocketMQ 异步处理,减少接口响应时间;
支付结果异步通知:支付渠道回调后,仅更新订单状态,后续逻辑(如通知商家、开启物流跟踪)通过消息队列异步执行,避免回调超时。
5.4.1.3 分库分表
订单分表:按创建时间分表(每 3 个月一张表),飞算 Java 分表组件自动路由查询,历史订单查询直接访问对应分表,避免主表数据量过大;
读写分离:订单查询(读操作)走 MySQL 从库,订单创建 / 状态更新(写操作)走主库,飞算 Java DAL 组件自动实现读写分离。
5.4.2 功能扩展
5.4.2.1 预售订单支持
流程适配:新增 “预售订单” 类型,支持 “支付定金→支付尾款→发货” 流程,飞算 Java 流程引擎编排预售节点(如定金支付后锁定库存,尾款支付后确认订单);
超时处理:定金支付后,尾款支付超时自动取消订单,退还定金(扣除违约金),通过飞算 Java 定时任务组件实现超时检查。
5.4.2.2 订单批量操作
批量发货:商家端支持批量选择多个待发货订单,填写相同快递公司与运单号(如同一批次发货),飞算 Java 批量处理组件减少数据库交互次数;
批量导出:运营端支持按时间范围批量导出订单数据(最大 10 万条 / 次),飞算 Java Excel 组件异步生成文件,生成后通过短信通知运营人员下载。
5.4.2.3 物流轨迹实时跟踪
集成物流 API:通过飞算 Java 物流集成组件,对接顺丰、中通等物流商 API,实时拉取物流轨迹(如 “已揽收”“运输中”“已签收”);
物流预警:物流信息超过 24 小时未更新时,自动发送预警通知至运营端,及时处理异常物流(如 “丢件”)。
5.5 模块上线与运维
5.5.1 上线流程
- 代码准备:
提交代码至飞算 Java 代码仓库,触发代码质量检查(SonarQube),修复 “高风险” 漏洞(如 SQL 注入、未授权访问);
编写分表迁移脚本(历史订单数据迁移至对应分表),测试数据迁移完整性。
- 环境部署:
预发布环境:部署订单服务(5 个实例),配置分表规则、Redis 分布式锁、RocketMQ 主题,执行压测与功能测试;
生产环境:采用 “蓝绿部署”,先部署新实例(蓝环境),验证支付回调、订单状态流转正常后,切换流量至蓝环境,绿环境保留 1 小时(异常时回滚)。
- 灰度发布:
初期对 20% 用户开放新订单功能,监控订单创建成功率、支付回调成功率;
无异常时逐步扩大至 100%,同步开启大促预案(如增加订单服务实例数)。
5.5.2 运维监控
5.5.2.1 监控指标
服务指标:订单服务 CPU 使用率、内存使用率、JVM GC 频率、接口响应时间(P95/P99)、错误率;
业务指标:订单创建成功率、支付转化率(已支付订单 / 创建订单)、退款率(退款订单 / 已支付订单)、超时未支付订单数;
中间件指标:Redis 分布式锁获取成功率、RocketMQ 消息消费成功率、MySQL 分表查询耗时。
5.5.2.2 监控工具与告警
监控工具:集成飞算 Java 监控平台与阿里云 ARMS,实时展示订单核心指标仪表盘,支持按时间范围查看趋势(如 “双 11” 期间订单量变化);
告警配置:
业务告警:订单创建成功率<99.9%、退款率>5%,触发短信 + 邮件告警;
服务告警:接口响应时间 P95>500ms、错误率>0.1%,触发运维告警;
中间件告警:RocketMQ 消息堆积数>1000,触发紧急告警。
5.5.2.3 问题排查
日志分析:飞算 Java 集成 ELK 日志系统,订单服务日志按 “orderId” 打标签,支持快速定位问题(如 “订单 600001 支付回调失败”);
链路追踪:通过飞算 Java 链路追踪组件(SkyWalking),查看订单创建全链路(用户端→订单服务→库存服务→支付服务),定位耗时节点(如库存预占耗时过长);
数据一致性校验:定时执行订单数据校验任务(如 “已支付订单是否存在对应支付记录”“退款成功订单是否已退还金额”),发现不一致时自动修复或触发告警。
第六章 支付管理模块设计与实现
6.1 模块需求分析
支付管理模块是电商系统资金流转的核心载体,承接订单支付请求,对接第三方支付渠道(如支付宝、微信支付),实现支付发起、结果校验、退款处理及账单统计,需从业务完整性、资金安全性与系统可靠性维度明确需求。
6.1.1 业务需求
6.1.1.1 多支付渠道集成
主流渠道支持:集成支付宝(APP 支付、H5 支付、小程序支付)、微信支付(APP 支付、公众号支付、扫码支付)、银联支付(快捷支付),用户可在下单时选择对应支付方式;
渠道配置化:运营端支持可视化配置支付渠道参数(如支付宝 APPID、微信商户号、API 密钥),无需修改代码即可新增 / 停用渠道,飞算 Java 配置中心统一管理渠道参数;
渠道路由策略:支持按订单金额(如小额订单优先微信支付)、用户类型(如会员用户优先支付宝)、渠道状态(如某渠道维护时自动切换至备用渠道)自动路由支付渠道,提高支付成功率。
6.1.1.2 支付全流程管控
支付发起:接收订单服务请求,生成支付参数(如支付宝支付串、微信支付二维码链接),返回给前端供用户完成支付;
支付状态同步:支持同步查询(用户主动刷新支付状态)与异步回调(支付渠道主动通知支付结果),确保支付结果不丢失;
支付超时处理:未支付订单超过有效期(如 5 分钟)自动关闭支付,释放订单资源(如解锁库存、取消优惠券锁定),飞算 Java 定时任务组件实现超时检查;
异常支付处理:处理 “支付成功但订单未更新”“支付失败但扣款” 等异常场景,通过对账机制修正数据,保障资金与订单状态一致。
6.1.1.3 退款闭环处理
退款发起:接收订单服务退款请求,支持全额退款(订单实付金额)、部分退款(指定金额,需≤订单实付金额);
退款渠道匹配:按原支付渠道发起退款(如支付宝支付订单仅能通过支付宝退款),自动填充退款所需参数(如支付宝交易号);
退款状态跟踪:记录退款申请、退款中、退款成功、退款失败等状态,同步至订单服务更新订单状态,用户可实时查看退款进度;
退款失败重试:因渠道超时、接口异常导致的退款失败,自动重试(重试次数、间隔可配置),重试失败时触发人工干预告警。
6.1.1.4 支付账单与对账
账单生成:自动生成日 / 月支付账单(包含支付金额、退款金额、手续费、净收入),支持按商户、支付渠道、订单类型筛选;
对账机制:每日凌晨自动与第三方支付渠道对账(如拉取支付宝账单),对比系统支付记录与渠道账单,识别 “系统有记录但渠道无”“渠道有记录但系统无” 等差异项;
对账结果处理:差异项自动标记,支持运营端手动核对与修正(如补录漏单、调整金额),生成对账报告(Excel 格式)供下载;
手续费计算:按支付渠道费率(如支付宝费率 0.6%)自动计算支付手续费,计入账单成本,支持按商户分摊手续费。
6.1.1.5 支付安全保障
签名验证:所有与第三方支付渠道的交互均需签名(如支付宝 RSA 签名、微信 HMAC-SHA256 签名),飞算 Java 加密组件自动生成与验证签名,防止数据篡改;
数据加密:敏感信息(如用户银行卡号、支付密码)传输与存储时加密(采用 AES-256 加密算法),符合《个人信息保护法》与支付行业合规要求;
防重复支付:基于订单号 + 支付渠道生成唯一幂等键,通过 Redis 分布式锁防止重复发起支付请求;
IP 白名单:限制第三方支付渠道回调 IP(如仅允许支付宝官方回调 IP 访问),拦截非法回调请求。
6.1.2 非功能需求
性能:支持日均 50 万支付请求,大促峰值 QPS 达 3 万(支付发起接口),支付结果查询响应时间≤100ms,退款处理响应时间≤200ms;
可靠性:支付成功率≥99.95%,退款成功率≥99.9%,支付回调消息丢失率≤0.01%(通过消息队列持久化保障);
安全性:签名验证通过率 100%(杜绝篡改请求),敏感数据加密存储(防止信息泄露),防重放攻击(通过时间戳 + 随机数机制);
可扩展性:新增支付渠道(如 Apple Pay、Google Pay)时,开发周期≤3 天,无需重构现有支付流程;
兼容性:支持多终端支付(APP、H5、小程序、PC),支付参数自动适配终端类型(如 H5 支付返回跳转链接,APP 支付返回支付串)。
6.2 模块设计
6.2.1 领域模型设计
基于飞算 Java 的 DDD 支持,支付管理模块核心领域模型及关联关系如下:
6.2.1.1 支付记录(PaymentRecord)
核心属性:支付记录 ID(paymentId,主键,雪花算法生成)、订单号(orderNo,关联订单表)、支付渠道(payChannel:0 - 支付宝,1 - 微信支付,2 - 银联)、支付方式(payMethod:0-APP 支付,1-H5 支付,2 - 扫码支付)、支付金额(payAmount)、手续费(feeAmount)、支付状态(payStatus:0 - 待支付,1 - 支付成功,2 - 支付失败,3 - 支付超时)、第三方交易号(tradeNo,如支付宝交易号)、支付时间(payTime)、创建时间(createTime)、更新时间(updateTime);
关联对象:退款记录列表(RefundRecordList)、支付渠道配置(PayChannelConfig);
核心行为:创建支付(create)、更新支付状态(updateStatus)、发起退款(applyRefund)、查询支付详情(queryDetail)。
6.2.1.2 退款记录(RefundRecord)
核心属性:退款记录 ID(refundId,主键)、支付记录 ID(paymentId)、订单号(orderNo)、退款渠道(refundChannel,与原支付渠道一致)、退款金额(refundAmount)、退款状态(refundStatus:0 - 退款申请中,1 - 退款中,2 - 退款成功,3 - 退款失败)、第三方退款号(refundTradeNo,如支付宝退款号)、退款原因(reason)、申请时间(applyTime)、完成时间(finishTime)、重试次数(retryCount);
关联对象:支付记录(PaymentRecord);
核心行为:提交退款申请(submit)、更新退款状态(updateStatus)、重试退款(retryRefund)。
6.2.1.3 支付渠道配置(PayChannelConfig)
核心属性:配置 ID(configId,主键)、支付渠道(payChannel)、支付方式(payMethod)、商户号(merchantNo,第三方分配)、APPID(如微信 APPID)、API 密钥(apiKey,加密存储)、签名算法(signAlgorithm:0-RSA,1-HMAC-SHA256)、费率(rate,如 0.006 表示 0.6%)、状态(status:0 - 停用,1 - 启用)、创建时间(createTime);
核心行为:获取渠道参数(getParams)、验证渠道状态(validateStatus)、计算手续费(calculateFee)。
6.2.1.4 支付账单(PaymentBill)
核心属性:账单 ID(billId,主键)、账单日期(billDate,如 20240525)、支付渠道(payChannel)、总支付金额(totalPayAmount)、总退款金额(totalRefundAmount)、总手续费(totalFeeAmount)、净收入(netIncome = 总支付金额 - 总退款金额 - 总手续费)、对账状态(reconciliationStatus:0 - 未对账,1 - 对账完成,2 - 存在差异)、生成时间(generateTime)、对账时间(reconciliationTime);
关联对象:账单明细列表(BillDetailList);
核心行为:生成账单(generate)、对账处理(reconcile)、导出账单(export)。
6.2.2 数据库设计
基于 MySQL 数据库,采用飞算 Java 可视化数据库设计工具生成核心表结构,关键表如下(分表策略:支付记录表、退款记录表按创建时间分表,每 1 个月一张表;账单表按账单日期分表):
表 6-1 支付记录表(t_payment_record)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
payment_id | BIGINT | - | 主键 | 雪花算法生成 | 支付记录唯一标识 |
order_no | VARCHAR | 64 | 外键 | REFERENCES t_order(order_no) | 关联订单编号 |
pay_channel | TINYINT | - | - | NOT NULL | 支付渠道(0 - 支付宝,1 - 微信) |
pay_method | TINYINT | - | - | NOT NULL | 支付方式(0-APP,1-H5) |
pay_amount | DECIMAL(10,2) | - | - | NOT NULL | 支付金额 |
fee_amount | DECIMAL(10,2) | - | - | DEFAULT 0.00 | 手续费 |
pay_status | TINYINT | - | - | DEFAULT 0 | 支付状态(0 - 待支付,1 - 成功) |
trade_no | VARCHAR | 64 | - | - | 第三方交易号(如支付宝) |
pay_time | DATETIME | - | - | - | 支付时间 |
expire_time | DATETIME | - | - | NOT NULL | 支付超时时间 |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
update_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
表 6-2 退款记录表(t_refund_record)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
refund_id | BIGINT | - | 主键 | AUTO_INCREMENT | 退款记录唯一标识 |
payment_id | BIGINT | - | 外键 | REFERENCES t_payment_record(payment_id) | 关联支付记录 ID |
order_no | VARCHAR | 64 | - | NOT NULL | 关联订单编号 |
refund_channel | TINYINT | - | - | NOT NULL | 退款渠道(与支付渠道一致) |
refund_amount | DECIMAL(10,2) | - | - | NOT NULL | 退款金额 |
refund_status | TINYINT | - | - | DEFAULT 0 | 退款状态(0 - 申请中,1 - 退款中) |
refund_trade_no | VARCHAR | 64 | - | - | 第三方退款号 |
reason | VARCHAR | 500 | - | - | 退款原因 |
retry_count | INT | - | - | DEFAULT 0 | 重试次数 |
apply_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 申请时间 |
finish_time | DATETIME | - | - | - | 完成时间 |
表 6-3 支付渠道配置表(t_pay_channel_config)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
config_id | BIGINT | - | 主键 | AUTO_INCREMENT | 配置唯一标识 |
pay_channel | TINYINT | - | - | NOT NULL | 支付渠道(0 - 支付宝,1 - 微信) |
pay_method | TINYINT | - | - | NOT NULL | 支付方式(0-APP,1-H5) |
merchant_no | VARCHAR | 64 | - | NOT NULL | 商户号(第三方分配) |
app_id | VARCHAR | 64 | - | - | APPID(如微信 APPID) |
api_key | VARCHAR | 255 | - | NOT NULL | API 密钥(加密存储) |
sign_algorithm | TINYINT | - | - | DEFAULT 0 | 签名算法(0-RSA,1-HMAC) |
rate | DECIMAL(6,4) | - | - | DEFAULT 0.0060 | 费率(如 0.0060=0.6%) |
status | TINYINT | - | - | DEFAULT 1 | 状态(0 - 停用,1 - 启用) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
表 6-4 支付账单表(t_payment_bill)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
bill_id | BIGINT | - | 主键 | AUTO_INCREMENT | 账单唯一标识 |
bill_date | VARCHAR | 8 | - | NOT NULL | 账单日期(格式:YYYYMMDD) |
pay_channel | TINYINT | - | - | NOT NULL | 支付渠道 |
total_pay_amount | DECIMAL(12,2) | - | - | DEFAULT 0.00 | 总支付金额 |
total_refund_amount | DECIMAL(12,2) | - | - | DEFAULT 0.00 | 总退款金额 |
total_fee_amount | DECIMAL(12,2) | - | - | DEFAULT 0.00 | 总手续费 |
net_income | DECIMAL(12,2) | - | - | DEFAULT 0.00 | 净收入(支付 - 退款 - 手续费) |
reconciliation_status | TINYINT | - | - | DEFAULT 0 | 对账状态(0 - 未对账,1 - 完成) |
generate_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 生成时间 |
reconciliation_time | DATETIME | - | - | - | 对账时间 |
6.2.3 接口设计
基于 RESTful 规范,通过飞算 Java 接口设计工具定义核心接口,关键接口如下:
6.2.3.1 创建支付接口(订单服务调用)
接口路径:
/api/pay/create
请求方法:POST
请求头:
Authorization: Bearer {token}
(服务间调用令牌)请求参数(JSON):
{
"orderNo": "ORD2024052510300001", // 订单编号
"userId": 100001, // 用户ID
"payChannel": 0, // 支付渠道(0-支付宝,1-微信)
"payMethod": 1, // 支付方式(1-H5支付)
"payAmount": 5499.00, // 支付金额
"expireTime": "2024-05-25 10:35:00", // 支付超时时间(5分钟)
"clientIp": "120.244.11.56", // 用户IP(用于风控)
"notifyUrl": "https://api.xxx.com/api/pay/callback/alipay" // 支付回调地址
}
- 响应参数(JSON):
{
"code": 200,
"message": "支付参数生成成功",
"data": {
"paymentId": 900001,
"payParams": {
"orderString": "alipay\_sdk=alipay-sdk-java-4.34.0\&app\_id=2021000000000000\&biz\_content=%7B%22out\_trade\_no%22%3A%22ORD2024052510300001%22%2C%22product\_code%22%3A%22FAST\_INSTANT\_TRADE\_PAY%22%2C%22subject%22%3A%222024新款超薄笔记本电脑%22%2C%22total\_amount%22%3A%225499.00%22%7D\&charset=utf-8\&format=json\&method=alipay.trade.wap.pay\&sign=xxxxxx"
},
"payStatus": 0, // 待支付
"expireTime": "2024-05-25 10:35:00"
}
}
- 业务逻辑:
校验订单状态(仅 “待支付” 订单可发起支付);
校验支付渠道配置(是否启用、参数是否完整);
生成支付记录(t_payment_record),状态设为 “待支付”;
调用飞算 Java 第三方支付组件,生成支付参数(如支付宝 H5 支付串);
返回支付记录 ID 与支付参数,供前端发起支付。
6.2.3.2 支付宝支付回调接口(第三方调用)
接口路径:
/api/pay/callback/alipay
请求方法:POST
请求参数(Form 表单):
out_trade_no
:订单编号(ORD2024052510300001);trade_no
:支付宝交易号(2024052522001410000000000000);trade_status
:交易状态(TRADE_SUCCESS = 支付成功);total_amount
:支付金额(5499.00);sign
:支付宝签名(用于验证);其他支付宝回调参数(如 gmt_payment = 支付时间)。
响应参数:
成功:返回字符串 “success”(支付宝要求,否则会重复回调);
失败:返回字符串 “fail”。
业务逻辑:
验证回调签名(飞算 Java 支付宝组件自动加载配置的 API 密钥与签名算法,验证参数完整性与签名有效性);
查询支付记录(通过 out_trade_no),校验支付金额是否匹配(防止金额篡改);
更新支付记录状态为 “支付成功”,填充 trade_no、pay_time 字段;
计算支付手续费(支付金额 × 渠道费率,如 5499.00×0.6%=32.99),更新 fee_amount 字段;
发送支付成功消息至 RocketMQ(主题:pay-success-topic),触发订单服务更新订单状态、解锁库存等后续流程;
若步骤 3-5 失败(如数据库异常),将回调消息存入死信队列,触发人工干预告警,返回 “fail”(等待支付宝重试)。
6.2.3.3 申请退款接口(订单服务调用)
接口路径:
/api/pay/refund/apply
请求方法:POST
请求头:
Authorization: Bearer {token}
(服务间调用令牌)请求参数(JSON):
{
"orderNo": "ORD2024052510300001", // 订单编号
"paymentId": 900001, // 支付记录ID
"refundAmount": 5499.00, // 退款金额(全额退款)
"reason": "商品质量问题", // 退款原因
"notifyUrl": "https://api.xxx.com/api/pay/refund/callback/alipay" // 退款回调地址
}
- 响应参数(JSON):
{
"code": 200,
"message": "退款申请提交成功",
"data": {
"refundId": 100001,
"refundNo": "REF2024052609150001", // 系统退款编号
"refundStatus": 1, // 退款中
"refundChannel": 0, // 退款渠道(与支付渠道一致)
"applyTime": "2024-05-26 09:15:30"
}
}
- 业务逻辑:
校验支付记录状态(仅 “支付成功” 订单可申请退款);
校验退款金额(≤支付金额,且未超过已退款金额上限);
生成退款记录(t_refund_record),状态设为 “退款中”;
调用飞算 Java 第三方支付组件,按原支付渠道发起退款(如支付宝退款接口);
返回退款记录 ID 与状态,同步通知订单服务更新订单退款状态。
6.2.4 权限设计
基于飞算 Java 权限管理组件,实现支付模块的细粒度权限控制,重点保障资金操作安全:
6.2.4.1 角色定义
系统服务角色:仅订单服务可调用 “创建支付”“申请退款” 接口(通过服务间令牌校验,禁止前端直接调用);
运营角色:可查看支付账单、对账报告、支付记录(脱敏用户信息),处理对账差异,不可发起支付 / 退款操作;
财务角色:可导出账单、审核大额退款(如退款金额>1000 元需财务审核)、配置支付渠道费率,不可修改支付记录;
系统管理员角色:拥有模块全部权限,包括配置支付渠道参数、调整对账规则、处理死信队列消息。
6.2.4.2 权限控制实现
接口权限:服务间接口(如创建支付)通过飞算 Java 服务认证组件校验令牌,仅允许指定服务(如订单服务)调用;运营 / 财务接口通过
@Permission
注解指定角色,如账单导出接口需@Permission(roles = {"OPERATOR", "FINANCE", "ADMIN"})
;数据权限:运营查看支付记录时,仅展示非敏感字段(隐藏用户手机号、第三方 API 密钥);财务查看账单时,仅可查看负责商户的账单数据(通过
merchant_id
数据权限过滤);操作权限:大额退款(如>1000 元)需财务二次审核,飞算 Java 流程引擎编排 “申请→审核→执行退款” 流程,未审核通过的退款无法发起。
6.3 模块实现(基于飞算 Java)
6.3.1 开发环境搭建
6.3.1.1 飞算 Java 平台配置
- 在 “ecommerce-system” 项目中添加 “支付管理模块”,引入核心依赖组件:
基础组件:微服务框架、JPA 数据访问、服务认证、分布式事务(TCC/Seata)、权限管理;
业务组件:第三方支付集成(支付宝、微信支付组件)、消息队列(RocketMQ,用于支付结果通知)、缓存(Redis,用于幂等控制)、加密组件(AES/RSA 签名)、定时任务(用于超时处理与对账)、Excel 导出组件;
- 配置核心参数:
支付渠道参数:在飞算 Java 配置中心添加支付宝(appId、merchantNo、apiKey、签名算法)、微信支付(appId、mchId、apiKey)配置,敏感参数(如 apiKey)加密存储;
幂等控制:Redis 锁前缀(
pay:lock:
)、支付记录缓存 Key 前缀(pay:record:{orderNo}
),过期时间 1 小时;对账配置:每日对账时间(凌晨 2 点)、重试次数(3 次)、差异项告警阈值(>10 条触发紧急告警)。
6.3.1.2 本地环境配置
本地启动 Redis、RocketMQ,通过飞算 Java IDE 插件关联云端配置;
集成第三方支付测试环境:支付宝沙箱环境(获取测试 appId、商户号)、微信支付测试账号(通过微信支付商户平台申请);
执行分表初始化脚本(创建支付记录表、退款记录表主表及分表结构),配置飞算 Java 分表组件(按
create_time
自动路由至对应分表);配置飞算 Java 加密组件:导入 RSA 密钥对(用于支付宝签名验证),设置 AES 加密密钥(用于敏感数据存储)。
6.3.2 核心代码实现(创建支付功能)
6.3.2.1 实体类(基于 JPA)
// PaymentRecord.java(关联t\_payment\_record表,支持分表)
@Entity
@Table(name = "t\_payment\_record")
@ShardingTable(strategy = TableShardingStrategy.TIME, column = "create\_time", period = "1 month") // 按月份分表
public class PaymentRecord extends BaseEntity {
@Id
private Long paymentId; // 雪花算法生成
@Column(nullable = false)
private String orderNo;
@Column(nullable = false)
private Integer payChannel;
@Column(nullable = false)
private Integer payMethod;
@Column(nullable = false)
private BigDecimal payAmount;
private BigDecimal feeAmount = BigDecimal.ZERO;
private Integer payStatus = 0; // 0-待支付
private String tradeNo;
private Date payTime;
@Column(nullable = false)
private Date expireTime;
@Column(name = "create\_time", nullable = false)
private Date createTime = new Date();
@Column(name = "update\_time")
private Date updateTime = new Date();
// getter/setter(飞算Java自动生成)
}
// PayChannelConfig.java(关联t\_pay\_channel\_config表)
@Entity
@Table(name = "t\_pay\_channel\_config")
public class PayChannelConfig extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long configId;
@Column(nullable = false)
private Integer payChannel;
@Column(nullable = false)
private Integer payMethod;
@Column(nullable = false)
private String merchantNo;
private String appId;
@Column(nullable = false)
private String apiKey; // 加密存储
private Integer signAlgorithm = 0; // 0-RSA,1-HMAC-SHA256
private BigDecimal rate = new BigDecimal("0.0060"); // 默认费率0.6%
private Integer status = 1; // 1-启用
private Date createTime = new Date();
// getter/setter(apiKey字段通过飞算Java加密组件自动解密)
}
6.3.2.2 支付渠道集成(支付宝 H5 支付)
飞算 Java 提供封装好的支付宝支付组件,无需手动编写 HTTP 请求与签名逻辑,核心代码如下:
@Service
public class AlipayService {
@Autowired
private AlipayConfig alipayConfig; // 飞算Java配置中心注入支付宝配置(自动解密apiKey)
@Autowired
private AlipayClient alipayClient; // 飞算Java支付宝组件自动创建的客户端
/\*\*
\* 生成支付宝H5支付参数
\* @param paymentRecord 支付记录
\* @param notifyUrl 回调地址
\* @return 支付参数(orderString)
\*/
public String createH5PayParams(PaymentRecord paymentRecord, String notifyUrl) throws AlipayApiException {
// 1. 构建支付宝H5支付请求参数
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
// 回调地址(支付成功后支付宝回调此地址)
request.setNotifyUrl(notifyUrl);
// 同步跳转地址(用户支付成功后跳转的前端页面)
request.setReturnUrl("https://www.xxx.com/pay/success?orderNo=" + paymentRecord.getOrderNo());
// 2. 构建业务参数(JSON格式)
JSONObject bizContent = new JSONObject();
bizContent.put("out\_trade\_no", paymentRecord.getOrderNo()); // 系统订单号
bizContent.put("total\_amount", paymentRecord.getPayAmount().toString()); // 支付金额
bizContent.put("subject", "电商订单支付:" + paymentRecord.getOrderNo()); // 订单标题
bizContent.put("product\_code", "FAST\_INSTANT\_TRADE\_PAY"); // 支付宝H5支付产品码
// 支付超时时间(格式:yyyy-MM-dd HH:mm:ss)
bizContent.put("time\_expire", DateUtils.format(paymentRecord.getExpireTime(), "yyyy-MM-dd HH:mm:ss"));
request.setBizContent(bizContent.toString());
// 3. 调用支付宝接口生成支付串(飞算Java组件自动处理签名)
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (!response.isSuccess()) {
throw new BusinessException("支付宝支付参数生成失败:" + response.getMsg());
}
// 4. 返回支付宝支付串(前端加载此串即可唤起支付宝H5支付页面)
return response.getBody();
}
/\*\*
\* 验证支付宝回调签名
\* @param params 回调参数(request.getParameterMap())
\* @return 验证结果(true-通过,false-失败)
\*/
public boolean verifyCallbackSign(Map\ params) {
// 飞算Java支付宝组件自动验证签名(使用配置的apiKey与签名算法)
return AlipaySignature.rsaCheckV1(
params,
alipayConfig.getPublicKey(), // 支付宝公钥(用于验证签名)
"UTF-8",
alipayConfig.getSignType() // 签名算法(如RSA2)
);
}
}
6.3.2.3 服务层(PaymentService)
@Service
public class PaymentService {
@Autowired
private PaymentRecordRepository paymentRecordRepository; // JPA Repository(飞算自动生成)
@Autowired
private PayChannelConfigRepository channelConfigRepository;
@Autowired
private AlipayService alipayService;
@Autowired
private WechatPayService wechatPayService; // 微信支付服务(类似AlipayService)
@Autowired
private IdGenerator idGenerator; // 飞算Java雪花算法ID生成器
@Autowired
private RedisTemplate\ redisTemplate;
@Autowired
private RocketMQTemplate rocketMQTemplate;
/\*\*
\* 创建支付(统一入口,支持多渠道)
\*/
@Transactional
public PaymentVO createPayment(PaymentCreateDTO createDTO) {
// 1. 幂等控制(防止重复创建支付)
String lockKey = "pay:lock:create:" + createDTO.getOrderNo();
Boolean lockSuccess = redisTemplate.opsForValue().setIfAbsent(lockKey, "LOCK", 5, TimeUnit.MINUTES);
if (Boolean.FALSE.equals(lockSuccess)) {
throw new BusinessException("请勿重复发起支付");
}
try {
// 2. 校验订单是否已存在支付记录
Optional\ existingRecord = paymentRecordRepository.findByOrderNo(createDTO.getOrderNo());
if (existingRecord.isPresent()) {
PaymentRecord record = existingRecord.get();
// 若已存在待支付记录,直接返回(避免重复生成支付参数)
if (record.getPayStatus() == 0) {
return buildPaymentVO(record, null);
} else {
throw new BusinessException("订单已支付,不可重复发起");
}
}
// 3. 校验支付渠道配置(是否启用、参数是否完整)
PayChannelConfig channelConfig = channelConfigRepository.findByPayChannelAndPayMethodAndStatus(
createDTO.getPayChannel(),
createDTO.getPayMethod(),
1 // 1-启用
).orElseThrow(() -> new BusinessException("支付渠道未配置或已停用"));
// 4. 生成支付记录
PaymentRecord paymentRecord = buildPaymentRecord(createDTO, channelConfig);
paymentRecord = paymentRecordRepository.save(paymentRecord);
// 5. 调用对应渠道生成支付参数
String payParams = generatePayParams(paymentRecord, createDTO.getPayChannel(), createDTO.getPayMethod(), createDTO.getNotifyUrl());
// 6. 缓存支付记录(用于后续查询)
redisTemplate.opsForValue().set(
"pay:record:" + createDTO.getOrderNo(),
paymentRecord,
1,
TimeUnit.HOURS
);
// 7. 构建返回VO
return buildPaymentVO(paymentRecord, payParams);
} finally {
// 释放锁(若业务执行完成,无论成功失败均释放)
redisTemplate.delete(lockKey);
}
}
/\*\*
\* 构建支付记录
\*/
private PaymentRecord buildPaymentRecord(PaymentCreateDTO createDTO, PayChannelConfig channelConfig) {
PaymentRecord record = new PaymentRecord();
record.setPaymentId(idGenerator.nextId());
record.setOrderNo(createDTO.getOrderNo());
record.setPayChannel(createDTO.getPayChannel());
record.setPayMethod(createDTO.getPayMethod());
record.setPayAmount(createDTO.getPayAmount());
record.setExpireTime(createDTO.getExpireTime());
// 计算预估手续费(实际手续费在支付成功后更新)
BigDecimal feeAmount = createDTO.getPayAmount().multiply(channelConfig.getRate());
record.setFeeAmount(feeAmount);
record.setCreateTime(new Date());
record.setUpdateTime(new Date());
return record;
}
/\*\*
\* 生成支付参数(按支付渠道路由)
\*/
private String generatePayParams(PaymentRecord record, Integer payChannel, Integer payMethod, String notifyUrl) {
try {
switch (payChannel) {
case 0: // 支付宝
if (payMethod == 1) { // H5支付
return alipayService.createH5PayParams(record, notifyUrl);
} else if (payMethod == 0) { // APP支付
return alipayService.createAppPayParams(record, notifyUrl);
}
throw new BusinessException("不支持的支付宝支付方式");
case 1: // 微信支付
if (payMethod == 2) { // 扫码支付
return wechatPayService.createQrCodePayParams(record, notifyUrl);
}
throw new BusinessException("不支持的微信支付方式");
default:
throw new BusinessException("不支持的支付渠道");
}
} catch (Exception e) {
throw new BusinessException("支付参数生成失败:" + e.getMessage());
}
}
/\*\*
\* 构建支付返回VO
\*/
private PaymentVO buildPaymentVO(PaymentRecord record, String payParams) {
PaymentVO vo = new PaymentVO();
vo.setPaymentId(record.getPaymentId());
vo.setPayStatus(record.getPayStatus());
vo.setExpireTime(record.getExpireTime());
// 封装支付参数(不同渠道参数格式不同,统一用Map返回)
if (StringUtils.isNotBlank(payParams)) {
Map\ payParamsMap = new HashMap<>();
payParamsMap.put("orderString", payParams);
vo.setPayParams(payParamsMap);
}
return vo;
}
// 其他方法:处理支付回调、申请退款(省略)
}
6.3.2.4 控制层(PayController)
@RestController
@RequestMapping("/api/pay")
public class PayController {
@Autowired
private PaymentService paymentService;
@Autowired
private ResultGenerator resultGenerator;
@Autowired
private ServiceAuthComponent serviceAuthComponent; // 飞算Java服务认证组件
/\*\*
\* 创建支付(服务间接口,仅订单服务可调用)
\*/
@PostMapping("/create")
public Result\ createPayment(@Valid @RequestBody PaymentCreateDTO createDTO) {
// 1. 服务认证(仅允许订单服务调用,通过请求头令牌验证)
serviceAuthComponent.validateService("order-service");
// 2. 调用服务层创建支付
PaymentVO paymentVO = paymentService.createPayment(createDTO);
return resultGenerator.success("支付参数生成成功", paymentVO);
}
/\*\*
\* 支付宝支付回调(第三方接口)
\*/
@PostMapping("/callback/alipay")
public String alipayCallback(HttpServletRequest request) {
try {
// 1. 解析回调参数(request.getParameterMap())
Map\ params = request.getParameterMap();
// 2. 验证签名
if (!alipayService.verifyCallbackSign(params)) {
log.warn("支付宝回调签名验证失败,参数:{}", JSON.toJSONString(params));
return "fail";
}
// 3. 处理支付成功逻辑(更新支付记录、发送通知)
String orderNo = request.getParameter("out\_trade\_no");
String tradeNo = request.getParameter("trade\_no");
String tradeStatus = request.getParameter("trade\_status");
BigDecimal totalAmount = new BigDecimal(request.getParameter("total\_amount"));
if ("TRADE\_SUCCESS".equals(tradeStatus)) {
paymentService.handlePaySuccess(orderNo, tradeNo, totalAmount);
}
// 4. 返回成功标识(支付宝停止重复回调)
return "success";
} catch (Exception e) {
log.error("支付宝回调处理失败", e);
// 回调失败,返回fail,支付宝会重试
return "fail";
}
}
/\*\*
\* 申请退款(服务间接口,仅订单服务可调用)
\*/
@PostMapping("/refund/apply")
public Result\ applyRefund(@Valid @RequestBody RefundCreateDTO createDTO) {
// 服务认证(仅允许订单服务调用)
serviceAuthComponent.validateService("order-service");
// 调用服务层申请退款
RefundVO refundVO = paymentService.applyRefund(createDTO);
return resultGenerator.success("退款申请提交成功", refundVO);
}
}
6.3.3 支付超时处理(定时任务)
通过飞算 Java 定时任务组件,每日定时扫描 “待支付” 且已超时的支付记录,释放订单资源,核心代码如下:
@Component
public class PayTimeoutTask {
@Autowired
private PaymentRecordRepository paymentRecordRepository;
@Autowired
private RocketMQTemplate rocketMQTemplate;
/\*\*
\* 每5分钟执行一次,处理支付超时订单
\*/
@Scheduled(cron = "0 \*/5 \* \* \* ?")
public void handlePayTimeout() {
log.info("开始处理支付超时订单");
// 1. 查询超时支付记录(状态=待支付,expire\_time < 当前时间)
Date now = new Date();
List\ timeoutRecords = paymentRecordRepository.findByPayStatusAndExpireTimeLessThan(0, now);
if (CollectionUtils.isEmpty(timeoutRecords)) {
log.info("无支付超时订单");
return;
}
// 2. 批量更新支付状态为“支付超时”
List\ paymentIds = timeoutRecords.stream().map(PaymentRecord::getPaymentId).collect(Collectors.toList());
paymentRecordRepository.batchUpdatePayStatus(paymentIds, 3); // 3-支付超时
// 3. 发送支付超时消息,触发订单服务释放资源(解锁库存、取消优惠券)
for (PaymentRecord record : timeoutRecords) {
PayTimeoutDTO timeoutDTO = new PayTimeoutDTO();
timeoutDTO.setOrderNo(record.getOrderNo());
timeoutDTO.setPaymentId(record.getPaymentId());
rocketMQTemplate.send("pay-timeout-topic", MessageBuilder.withPayload(timeoutDTO).build());
}
log.info("处理支付超时订单完成,共{}条", timeoutRecords.size());
}
}
6.3.4 功能测试(基于飞算 Java 测试工具)
6.3.4.1 接口测试
- 创建支付测试:
模拟订单服务调用 “创建支付” 接口,传入订单号、支付渠道(支付宝)、支付方式(H5)、支付金额;
验证点:支付记录成功插入数据库(状态 = 待支付),返回正确的支付宝支付串,Redis 缓存支付记录;
- 支付回调测试:
使用支付宝沙箱模拟支付成功,调用 “支付宝回调接口”,传入正确的回调参数与签名;
验证点:支付记录状态更新为 “支付成功”,trade_no、pay_time、fee_amount 字段正确填充,RocketMQ 发送支付成功消息;
- 申请退款测试:
模拟订单服务调用 “申请退款” 接口,传入订单号、支付 ID、全额退款金额;
验证点:退款记录成功插入数据库(状态 = 退款中),调用支付宝退款接口返回成功,同步通知订单服务。
6.3.4.2 性能测试
使用飞算 Java 压测工具对 “创建支付” 接口进行压测:
压测参数:并发用户数 1500,持续时间 60 秒,模拟大促支付场景;
预期结果:QPS≥3000,平均响应时间≤150ms,支付参数生成成功率≥99.99%;
实际结果:QPS=3800,平均响应时间 120ms,失败率 0.01%(因 Redis 幂等锁防止重复请求),满足性能需求。
6.4 模块优化与扩展
6.4.1 性能优化
6.4.1.1 缓存优化
支付记录缓存:用户查询支付状态(如前端刷新)时,优先从 Redis 获取支付记录(Key:
pay:record:{orderNo}
),缓存未命中时查询数据库并更新缓存,减少数据库压力;渠道配置缓存:支付渠道配置(如支付宝 apiKey、费率)加载至本地缓存(Caffeine),过期时间 30 分钟,减少数据库查询(配置更新时主动刷新缓存);
支付参数缓存:同一订单的支付参数(如支付宝支付串)缓存至 Redis,有效期与支付超时时间一致,避免重复调用第三方接口生成参数。
6.4.1.2 异步处理
非核心流程异步化:支付成功后的 “手续费计算”“账单预生成”“通知日志记录” 等非核心逻辑,通过 RocketMQ 异步处理,减少回调接口响应时间;
批量处理:对账时批量拉取第三方账单(如支付宝一次拉取 1000 条记录)、批量对比系统记录,减少接口调用次数;批量更新对账结果,降低数据库事务开销。
6.4.1.3 数据库优化
索引优化:在
t_payment_record
表的order_no
(唯一索引)、pay_status+expire_time
(复合索引)字段创建索引,提升查询速度;在t_refund_record
表的payment_id+refund_status
字段创建复合索引,优化退款查询;分表优化:支付记录表按月份分表(如
t_payment_record_202405
),历史订单查询直接访问对应分表;对账时仅需加载当日分表数据,减少数据扫描范围。
6.4.2 功能扩展
6.4.2.1 跨境支付支持
渠道集成:通过飞算 Java 第三方支付组件集成 PayPal、Stripe 等跨境支付渠道,配置多币种(美元、欧元)支付参数;
汇率处理:集成第三方汇率接口(如新浪财经汇率),实时获取汇率,自动将订单金额转换为目标币种(如用户支付美元,系统按实时汇率转换为人民币记录);
合规适配:支持跨境支付所需的身份验证(如 KYC 认证)、税务申报(自动计算跨境税费),符合国际支付合规要求。
6.4.2.2 数字钱包支付
钱包功能:新增用户数字钱包模块(余额充值、余额支付、账单查询),飞算 Java 账户组件实现余额管理;
支付流程适配:用户选择 “钱包支付” 时,直接扣减钱包余额(无需调用第三方渠道),通过飞算 Java 分布式事务确保 “余额扣减” 与 “订单支付” 原子性;
充值支持:支持通过支付宝、微信支付给钱包充值,充值金额实时到账,生成充值账单。
6.4.2.3 智能对账与异常修复
AI 对账:引入 AI 算法分析对账差异(如 “系统有记录但渠道无” 可能是渠道漏单),自动判断差异类型并给出修复建议(如补录漏单);
自动修复:常见差异(如金额微小误差、时间戳不一致)自动修复,无需人工干预;复杂差异(如大额金额不匹配)触发人工告警;
对账报告可视化:通过飞算 Java 报表组件生成对账结果可视化图表(差异类型分布、每日对账成功率趋势),支持运营端在线查看与导出。
6.5 模块上线与运维
6.5.1 上线流程
- 代码准备:
提交代码至飞算 Java 代码仓库,触发代码质量检查(SonarQube),重点检查支付签名、敏感数据加密等安全相关代码,修复高危漏洞;
编写上线文档,包含支付渠道切换方案(如线上先启用支付宝,验证通过后启用微信支付)、回滚预案(支付服务异常时切换至备用服务实例)。
- 环境部署:
预发布环境:部署支付服务(4 个实例),配置生产环境支付渠道参数(使用第三方支付正式环境账号),执行全流程测试(支付→回调→退款→对账);
生产环境:采用 “灰度发布” 策略,先对 10% 用户开放新支付功能(如仅支付宝 H5 支付),监控支付成功率、回调成功率;无异常时逐步扩大至 100%,同步部署备用服务实例。
- 渠道验证:
上线后与第三方支付渠道联调(如支付宝商户平台验证回调地址、测试金额支付);
执行小额真实支付测试(如支付 1 元),验证资金流转正常(支付金额到账、手续费计算正确)。
6.5.2 运维监控
6.5.2.1 监控指标
服务指标:支付服务 CPU 使用率、内存使用率、JVM GC 频率、接口响应时间(P95/P99)、错误率;
业务指标:支付成功率(支付成功订单数 / 创建支付订单数)、退款成功率(退款成功记录数 / 申请退款记录数)、回调成功率(成功处理的回调数 / 总回调数)、对账差异数;
渠道指标:第三方支付接口调用成功率(如支付宝接口成功率)、接口响应时间(如支付宝生成支付参数耗时)、渠道故障次数。
6.5.2.2 监控工具与告警
监控工具:集成飞算 Java 监控平台与阿里云 ARMS,实时展示支付核心指标仪表盘,支持按支付渠道、时间范围筛选数据(如查看支付宝 H5 支付的成功率);
告警配置:
业务告警:支付成功率<99.9%、退款成功率<99.5%、对账差异数>10 条,触发短信 + 邮件告警;
服务告警:接口响应时间 P95>300ms、错误率>0.1%,触发运维告警;
渠道告警:第三方支付接口调用失败率>1%、渠道故障(如支付宝接口维护),触发紧急告警并自动切换至备用渠道。
6.5.2.3 问题排查
日志分析:飞算 Java 集成 ELK 日志系统,支付服务日志按 “orderNo”“paymentId” 打标签,支持快速定位问题(如 “订单 ORD2024052510300001 支付回调失败”);
链路追踪:通过飞算 Java 链路追踪组件(SkyWalking),查看支付全链路(订单服务→支付服务→支付宝接口→回调处理),定位耗时节点(如支付宝接口响应缓慢);
资金安全排查:定期执行资金核对(系统账单金额与第三方渠道到账金额对比),发现资金差异时,通过支付记录、回调日志、对账报告追溯问题原因,确保资金安全。
第七章 库存管理模块设计与实现
7.1 模块需求分析
库存管理模块是电商系统防止超卖、保障交易履约的核心,承接商品库存初始化、订单库存预占 / 扣减、售后库存返还等关键操作,需从业务完整性与数据一致性维度明确需求,尤其需应对大促期间高并发库存操作场景。
7.1.1 业务需求
7.1.1.1 库存基础管理
库存初始化:商品创建 SKU 后,自动初始化库存(总库存 = 可用库存,预占库存 = 0),支持商家手动录入初始库存(如线下门店备货同步至线上);
库存分类管控:区分总库存(SKU 总备货量)、可用库存(总库存 - 预占库存,用户可购买量)、预占库存(已下单未支付 / 未发货锁定的库存),确保库存状态透明;
库存实时更新:支持手动调整库存(如盘点补录、破损减库存),调整需记录操作日志(操作人、调整原因、调整前后数量),飞算 Java 表单组件实现可视化调整界面。
7.1.1.2 订单关联库存操作
库存预占:用户下单时(订单创建阶段)预占对应 SKU 可用库存,预占有效期与订单支付超时时间一致(如 5 分钟),防止超卖;
库存确认扣减:用户支付成功后,将预占库存转为实际扣减(总库存减少,预占库存清零);
库存释放:订单取消(支付超时 / 用户取消)或退款成功后,释放预占库存(可用库存增加,预占库存减少),飞算 Java 分布式事务确保 “订单状态” 与 “库存状态” 同步;
分批出库支持:针对大额订单(如批发订单),支持分多次出库(每次出库扣减部分库存),记录每次出库明细(出库时间、数量、操作员)。
7.1.1.3 库存盘点与调整
定期盘点:支持商家 / 运营发起库存盘点(全量 / 指定 SKU),系统生成盘点单(当前系统库存 vs 实际库存),差异项需人工确认后调整系统库存;
异常调整:针对库存差异(如系统库存与实际库存不符、破损 / 丢失),支持手动调整库存,调整需审批流程(如商家调整需运营审核,防止恶意操作);
盘点日志:记录所有盘点操作(盘点单号、盘点时间、差异数量、操作人),支持导出盘点报告(Excel 格式),飞算 Java Excel 组件自动生成报表。
7.1.1.4 库存预警与监控
低库存预警:设置 SKU 库存预警阈值(如低于 10 件),库存低于阈值时自动发送预警通知(短信 / APP 推送)给商家 / 运营,提醒补货;
高库存预警:针对滞销商品(如库存周转率低于行业均值),触发高库存预警,支持运营发起清仓活动(如折扣促销);
库存异动监控:监控异常库存操作(如短时间内大量库存减少、无订单关联的库存调整),触发告警并冻结异常 SKU 的库存操作,防止恶意篡改。
7.1.1.5 多仓库与库存分配
多仓库支持:支持配置多个物理仓库(如北京仓、上海仓),SKU 库存按仓库独立管理(如北京仓库存 100 件,上海仓库存 80 件);
智能库存分配:用户下单时,按 “就近发货”“仓库库存充足度” 自动分配仓库(如北京用户优先分配北京仓库存),减少物流成本;
跨仓调拨:支持运营发起跨仓调拨(如上海仓库存不足,从北京仓调拨 50 件),记录调拨流程(调拨单、出库仓、入库仓、调拨数量、完成时间)。
7.1.2 非功能需求
性能:支持日均 1000 万次库存操作(预占 / 扣减 / 释放),大促峰值 QPS 达 8 万(库存预占接口),库存查询响应时间≤50ms,库存操作成功率≥99.99%;
数据一致性:库存数据最终一致性延迟≤100ms(Redis 缓存与 MySQL 数据库同步),超卖率≤0.001%(通过分布式锁保障);
高可用:库存服务支持多实例部署,单实例故障不影响整体库存操作,核心库存数据多副本存储(MySQL 主从 + Redis 集群);
可扩展性:支持新增库存类型(如虚拟库存:预售商品的 “未入库库存”),无需重构现有库存操作逻辑;
安全性:库存调整需身份验证(如商家仅能调整自身店铺 SKU 库存),敏感操作(如批量库存清零)需二次验证(短信验证码)。
7.2 模块设计
7.2.1 领域模型设计
基于飞算 Java 的 DDD 支持,库存管理模块核心领域模型及关联关系如下:
7.2.1.1 库存主记录(Inventory)
核心属性:库存 ID(inventoryId,主键)、SKU ID(skuId,关联 SKU 表)、仓库 ID(warehouseId,关联仓库表)、总库存(totalStock)、可用库存(availableStock=totalStock-preoccupyStock)、预占库存(preoccupyStock)、预警阈值(warningThreshold)、库存状态(status:0 - 正常,1 - 预警,2 - 冻结)、最后更新时间(updateTime);
关联对象:库存操作日志列表(InventoryOperateLogList)、库存预占记录列表(InventoryPreoccupyList);
核心行为:初始化库存(init)、预占库存(preoccupy)、确认扣减(deduct)、释放库存(release)、调整库存(adjust)、检查预警(checkWarning)。
7.2.1.2 库存预占记录(InventoryPreoccupy)
核心属性:预占 ID(preoccupyId,主键)、SKU ID(skuId)、仓库 ID(warehouseId)、订单号(orderNo,关联订单表)、预占数量(quantity)、预占时间(preoccupyTime)、过期时间(expireTime)、预占状态(status:0 - 有效,1 - 已扣减,2 - 已释放,3 - 已过期);
关联对象:库存主记录(Inventory)、订单(Order);
核心行为:创建预占(create)、确认扣减(confirmDeduct)、主动释放(activeRelease)、过期释放(expireRelease)。
7.2.1.3 库存操作日志(InventoryOperateLog)
核心属性:日志 ID(logId,主键)、SKU ID(skuId)、仓库 ID(warehouseId)、操作类型(operateType:0 - 初始化,1 - 预占,2 - 扣减,3 - 释放,4 - 盘点调整)、操作前数量(beforeQuantity:总库存 / 可用库存 / 预占库存)、操作后数量(afterQuantity)、操作人(operatorId/operatorType:0 - 系统,1 - 商家,2 - 运营)、操作原因(reason,如 “订单预占:ORD2024052510300001”)、操作时间(operateTime);
关联对象:库存主记录(Inventory);
核心行为:记录日志(record)、查询日志(query)。
7.2.1.4 仓库(Warehouse)
核心属性:仓库 ID(warehouseId,主键)、仓库名称(name,如 “北京仓”)、省份(province)、城市(city)、地址(address)、联系人(contactPerson)、联系电话(contactPhone)、仓库状态(status:0 - 停用,1 - 启用)、创建时间(createTime);
关联对象:库存主记录列表(InventoryList);
核心行为:新增仓库(add)、启用 / 停用(updateStatus)、查询库存(queryInventory)。
7.2.2 数据库设计
基于 MySQL 数据库,采用飞算 Java 可视化数据库设计工具生成核心表结构,关键表如下(分表策略:库存主记录表、预占记录表按 SKU ID 分表,每 10 万 SKU 一张表):
表 7-1 库存主记录表(t_inventory)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
inventory_id | BIGINT | - | 主键 | AUTO_INCREMENT | 库存唯一标识 |
sku_id | BIGINT | - | 外键 | REFERENCES t_sku(sku_id) | 关联 SKU ID |
warehouse_id | BIGINT | - | 外键 | REFERENCES t_warehouse(warehouse_id) | 关联仓库 ID |
total_stock | INT | - | - | DEFAULT 0 | 总库存 |
available_stock | INT | - | - | DEFAULT 0 | 可用库存 |
preoccupy_stock | INT | - | - | DEFAULT 0 | 预占库存 |
warning_threshold | INT | - | - | DEFAULT 10 | 库存预警阈值 |
status | TINYINT | - | - | DEFAULT 0 | 库存状态(0 - 正常,1 - 预警) |
update_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
表 7-2 库存预占记录表(t_inventory_preoccupy)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
preoccupy_id | BIGINT | - | 主键 | 雪花算法生成 | 预占唯一标识 |
sku_id | BIGINT | - | 外键 | REFERENCES t_sku(sku_id) | 关联 SKU ID |
warehouse_id | BIGINT | - | 外键 | REFERENCES t_warehouse(warehouse_id) | 关联仓库 ID |
order_no | VARCHAR | 64 | - | NOT NULL | 关联订单编号 |
quantity | INT | - | - | NOT NULL | 预占数量 |
preoccupy_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 预占时间 |
expire_time | DATETIME | - | - | NOT NULL | 过期时间 |
status | TINYINT | - | - | DEFAULT 0 | 预占状态(0 - 有效,1 - 已扣减) |
表 7-3 库存操作日志表(t_inventory_operate_log)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
log_id | BIGINT | - | 主键 | AUTO_INCREMENT | 日志唯一标识 |
sku_id | BIGINT | - | 外键 | REFERENCES t_sku(sku_id) | 关联 SKU ID |
warehouse_id | BIGINT | - | 外键 | REFERENCES t_warehouse(warehouse_id) | 关联仓库 ID |
operate_type | TINYINT | - | - | NOT NULL | 操作类型(0 - 初始化,1 - 预占) |
before_total | INT | - | - | NOT NULL | 操作前总库存 |
after_total | INT | - | - | NOT NULL | 操作后总库存 |
before_available | INT | - | - | NOT NULL | 操作前可用库存 |
after_available | INT | - | - | NOT NULL | 操作后可用库存 |
before_preoccupy | INT | - | - | NOT NULL | 操作前预占库存 |
after_preoccupy | INT | - | - | NOT NULL | 操作后预占库存 |
operator_id | BIGINT | - | - | NOT NULL | 操作人 ID |
operator_type | TINYINT | - | - | NOT NULL | 操作人类型(0 - 系统,1 - 商家) |
reason | VARCHAR | 500 | - | - | 操作原因 |
operate_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 操作时间 |
表 7-4 仓库表(t_warehouse)
字段名 | 数据类型 | 长度 | 主键 / 外键 | 约束条件 | 说明 |
---|---|---|---|---|---|
warehouse_id | BIGINT | - | 主键 | AUTO_INCREMENT | 仓库唯一标识 |
name | VARCHAR | 50 | - | NOT NULL | 仓库名称(如 “北京仓”) |
province | VARCHAR | 20 | - | NOT NULL | 省份 |
city | VARCHAR | 20 | - | NOT NULL | 城市 |
address | VARCHAR | 200 | - | NOT NULL | 仓库详细地址 |
contact_person | VARCHAR | 20 | - | NOT NULL | 联系人 |
contact_phone | VARCHAR | 20 | - | NOT NULL | 联系电话 |
status | TINYINT | - | - | DEFAULT 1 | 状态(0 - 停用,1 - 启用) |
create_time | DATETIME | - | - | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
7.2.3 接口设计
基于 RESTful 规范,通过飞算 Java 接口设计工具定义核心接口,关键接口如下(重点覆盖订单关联的库存操作):
7.2.3.1 库存预占接口(订单服务调用)
接口路径:
/api/inventory/preoccupy
请求方法:POST
请求头:
Authorization: Bearer {token}
(服务间调用令牌)请求参数(JSON):
{
"orderNo": "ORD2024052510300001", // 订单编号
"preoccupyItems": \[ // 预占明细(多SKU订单)
{
"skuId": 400001,
"warehouseId": 1001, // 分配的仓库ID
"quantity": 1, // 预占数量
"expireTime": "2024-05-25 10:35:00" // 预占过期时间(与订单支付超时一致)
}
]
}
- 响应参数(JSON):
{
"code": 200,
"message": "库存预占成功",
"data": {
"preoccupyIds": \[1100001], // 预占记录ID列表
"preoccupyTime": "2024-05-25 10:30:00"
}
}
- 业务逻辑:
服务认证(仅允许订单服务调用,飞算 Java 服务认证组件校验令牌);
遍历预占明细,按 SKU ID + 仓库 ID 获取库存记录,通过 Redis 分布式锁防止并发超卖;
校验可用库存(可用库存≥预占数量),不足则返回 “库存不足”;
扣减可用库存、增加预占库存(更新
t_inventory
表),创建预占记录(t_inventory_preoccupy
);记录库存操作日志(操作类型 = 1 - 预占,原因 = 订单预占 + 订单号);
缓存更新后的库存至 Redis(Key:
inventory:sku:{skuId}:warehouse:{warehouseId}
)。
7.2.3.2 库存确认扣减接口(订单服务调用)
接口路径:
/api/inventory/deduct
请求方法:POST
请求头:
Authorization: Bearer {token}
请求参数(JSON):
{
"orderNo": "ORD2024052510300001", // 订单编号
"deductItems": \[ // 扣减明细
{
"skuId": 400001,
"warehouseId": 1001,
"preoccupyId": 1100001 // 预占记录ID(关联预占操作)
}
]
}
- 响应参数(JSON):
{
"code": 200,
"message": "库存扣减成功",
"data": {
"deductTime": "2024-05-25 10:32:10",
"logIds": \[1200001] // 操作日志ID列表
}
}
- 业务逻辑:
校验预占记录(状态 = 0 - 有效,订单号匹配),无效则返回 “预占记录不存在或已失效”;
按预占记录中的数量,扣减总库存与预占库存(更新
t_inventory
表,总库存 = 总库存 - 数量,预占库存 = 预占库存 - 数量);更新预占记录状态为 “1 - 已扣减”,记录扣减时间;
记录库存操作日志(操作类型 = 2 - 扣减,原因 = 订单支付扣减 + 订单号);
同步更新 Redis 缓存中的库存数据。
7.2.3.3 库存释放接口(订单服务调用)
接口路径:
/api/inventory/release
请求方法:POST
请求头:
Authorization: Bearer {token}
请求参数(JSON):
{
"orderNo": "ORD2024052510300001", // 订单编号
"releaseReason": "订单支付超时", // 释放原因
"releaseItems": \[ // 释放明细
{
"skuId": 400001,
"warehouseId": 1001,
"preoccupyId": 1100001 // 预占记录ID(可选,无则按订单号查询)
}
]
}
- 响应参数(JSON):
{
"code": 200,
"message": "库存释放成功",
"data": {
"releaseTime": "2024-05-25 10:35:00",
"logIds": \[1200002]
}
}
- 业务逻辑:
若未传预占 ID,按订单号查询所有有效预占记录(状态 = 0 - 有效);
增加可用库存、减少预占库存(更新
t_inventory
表,可用库存 = 可用库存 + 数量,预占库存 = 预占库存 - 数量);更新预占记录状态为 “2 - 已释放”,记录释放原因;
记录库存操作日志(操作类型 = 3 - 释放,原因 = 释放原因 + 订单号);
同步更新 Redis 缓存,检查库存是否恢复至预警阈值以上,若恢复则更新库存状态为 “0 - 正常”。
7.2.3.4 库存预警查询接口(商家 / 运营端调用)
接口路径:
/api/inventory/warning/list
请求方法:GET
请求头:
Authorization: Bearer {token}
请求参数(URL):
merchantId=20001&pageNum=1&pageSize=20
(商家端传 merchantId,运营端不传则查所有)响应参数(JSON):
{
"code": 200,
"message": "查询成功",
"data": {
"total": 15,
"list": \[
{
"inventoryId": 300001,
"skuId": 400001,
"skuName": "2024新款超薄笔记本电脑(银色+16G+512G)",
"warehouseName": "北京仓",
"totalStock": 8,
"availableStock": 8,
"warningThreshold": 10,
"status": 1, // 预警状态
"updateTime": "2024-05-25 10:00:00"
}
],
"pageNum": 1,
"pageSize": 20
}
}
- 业务逻辑:
校验权限(商家端仅查自身店铺 SKU 的预警库存,运营端查所有);
查询
t_inventory
表中 “可用库存≤预警阈值” 且 “状态 = 1 - 预警” 的记录,关联 SKU 表、仓库表获取名称;按分页参数返回结果,支持按仓库、SKU 名称筛选。
7.2.4 权限设计
基于飞算 Java 权限管理组件,实现库存模块的细粒度权限控制,重点保障库存操作安全:
7.2.4.1 角色定义
系统服务角色:仅订单服务、商品服务可调用库存预占 / 扣减 / 释放接口(服务间令牌校验),禁止前端直接调用;
商家角色:可查询自身店铺 SKU 的库存(按仓库)、发起库存盘点(仅限自身 SKU)、查看库存预警,不可手动扣减库存(仅允许系统自动操作);
运营角色:可查询所有 SKU 库存、处理库存预警(如触发补货)、审核商家库存调整申请、发起跨仓调拨;
仓库管理员角色:可管理仓库信息(启用 / 停用)、执行库存调拨(出库 / 入库)、记录实际库存差异;
系统管理员角色:拥有模块全部权限,包括配置库存分表规则、调整预警阈值默认值、处理库存数据不一致。
7.2.4.2 权限控制实现
接口权限:服务间接口通过
ServiceAuthComponent
校验服务身份,前端接口通过@Permission
注解指定角色,如库存预警查询接口(商家端)需@Permission(roles = {"MERCHANT"})
;数据权限:商家查询库存时,飞算 Java 数据权限组件自动添加 “SKU 关联的商家 ID = 当前商家 ID” 条件;运营查询时可按商家、仓库筛选,但仅展示 “可用库存”“总库存”,隐藏预占库存(防止运营干预订单库存);
操作权限:手动库存调整需审批流程(商家发起→运营审核),飞算 Java 流程引擎编排审批节点,未审核通过的调整无法执行;敏感操作(如库存清零)需二次验证(短信验证码),飞算 Java 短信组件实现验证逻辑。
7.3 模块实现(基于飞算 Java)
7.3.1 开发环境搭建
7.3.1.1 飞算 Java 平台配置
- 在 “ecommerce-system” 项目中添加 “库存管理模块”,引入核心依赖组件:
基础组件:微服务框架、JPA 数据访问、服务认证、分布式事务(TCC)、权限管理;
业务组件:分布式锁(Redis)、缓存(Redis,用于热点库存)、消息队列(RocketMQ,用于库存同步与预警通知)、定时任务(用于预占过期释放)、Excel 导出组件;
- 配置核心参数:
分布式锁:锁前缀(
inventory:lock:{skuId}:{warehouseId}
),过期时间 3 秒(防止死锁);缓存配置:库存缓存 Key 前缀(
inventory:sku:{skuId}:warehouse:{warehouseId}
),热点 SKU 缓存过期时间 24 小时,普通 SKU 1 小时;定时任务:预占过期检查频率(每 1 分钟执行一次),库存一致性校验频率(每 10 分钟执行一次);
预警配置:默认预警阈值(10 件),预警通知方式(短信 + APP 推送)。
7.3.1.2 本地环境配置
本地启动 Redis(集群模式,保障缓存高可用)、RocketMQ,通过飞算 Java IDE 插件关联云端配置;
执行分表初始化脚本(创建库存主记录表、预占记录表主表及分表结构),配置飞算 Java 分表组件(按
sku_id
取模分表,分表数 32);初始化仓库数据(如 “北京仓”“上海仓”),配置商家与 SKU 的关联关系(用于数据权限过滤);
集成飞算 Java 短信组件与 APP 推送组件,配置预警通知模板(如 “【电商平台】您的 SKU 400001(北京仓)库存已低于预警阈值,当前可用库存 8 件,请及时补货”)。
7.3.2 核心代码实现(库存预占功能)
7.3.2.1 实体类(基于 JPA)
// Inventory.java(关联t\_inventory表,支持分表)
@Entity
@Table(name = "t\_inventory")
@ShardingTable(strategy = TableShardingStrategy.HASH, column = "sku\_id", shardCount = 32) // 按SKU ID哈希分表(32张表)
public class Inventory extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long inventoryId;
@Column(nullable = false)
private Long skuId;
@Column(nullable = false)
private Long warehouseId;
private Integer totalStock = 0;
private Integer availableStock = 0;
private Integer preoccupyStock = 0;
private Integer warningThreshold = 10;
private Integer status = 0; // 0-正常,1-预警,2-冻结
@Column(name = "update\_time")
private Date updateTime = new Date();
// getter/setter(飞算Java自动生成)
}
// InventoryPreoccupy.java(关联t\_inventory\_preoccupy表,支持分表)
@Entity
@Table(name = "t\_inventory\_preoccupy")
@ShardingTable(strategy = TableShardingStrategy.HASH, column = "sku\_id", shardCount = 32)
public class InventoryPreoccupy extends BaseEntity {
@Id
private Long preoccupyId; // 雪花算法生成
@Column(nullable = false)
private Long skuId;
@Column(nullable = false)
private Long warehouseId;
@Column(nullable = false)
private String orderNo;
@Column(nullable = false)
private Integer quantity;
@Column(name = "preoccupy\_time")
private Date preoccupyTime = new Date();
@Column(nullable = false)
private Date expireTime;
private Integer status = 0; // 0-有效,1-已扣减,2-已释放,3-已过期
// getter/setter
}
7.3.2.2 分布式锁与库存预占实现(InventoryService)
@Service
public class InventoryService {
@Autowired
private InventoryRepository inventoryRepository; // JPA Repository(飞算自动生成)
@Autowired
private InventoryPreoccupyRepository preoccupyRepository;
@Autowired
private InventoryOperateLogRepository logRepository;
@Autowired
private RedisLockComponent redisLockComponent; // 飞算Java分布式锁组件
@Autowired
private RedisTemplate\ redisTemplate;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Autowired
private IdGenerator idGenerator; // 雪花算法ID生成器
@Autowired
private SkuFeignClient skuFeignClient; // 商品服务Feign客户端(用于获取SKU关联的商家ID)
/\*\*
\* 库存预占(订单创建时调用)
\*/
@Transactional
public InventoryPreoccupyVO preoccupyInventory(InventoryPreoccupyDTO preoccupyDTO) {
List\ preoccupyIds = new ArrayList<>();
String orderNo = preoccupyDTO.getOrderNo();
// 遍历预占明细,逐一提取库存(防止多SKU预占时部分成功部分失败,通过事务保证原子性)
for (InventoryPreoccupyItemDTO item : preoccupyDTO.getPreoccupyItems()) {
Long skuId = item.getSkuId();
Long warehouseId = item.getWarehouseId();
Integer quantity = item.getQuantity();
Date expireTime = item.getExpireTime();
// 1. 分布式锁:按SKU ID+仓库ID加锁,防止并发超卖
String lockKey = "inventory:lock:" + skuId + ":" + warehouseId;
// 锁超时时间3秒(需大于业务执行时间,防止锁提前释放)
try (RedisLock lock = redisLockComponent.lock(lockKey, 3000)) {
if (!lock.isLocked()) {
throw new BusinessException("库存操作频繁,请稍后再试(SKU:" + skuId + ",仓库:" + warehouseId + ")");
}
// 2. 查询库存记录(优先从缓存获取,缓存未命中查数据库)
Inventory inventory = getInventoryFromCacheOrDb(skuId, warehouseId);
if (inventory == null) {
throw new BusinessException("SKU库存不存在(SKU:" + skuId + ",仓库:" + warehouseId + ")");
}
// 3. 校验可用库存(可用库存≥预占数量)
if (inventory.getAvailableStock() < quantity) {
// 查询SKU名称,用于友好提示
Result\ skuResult = skuFeignClient.getSkuById(skuId);
String skuName = skuResult.getData() != null ? skuResult.getData().getSkuName() : "未知SKU";
throw new BusinessException("库存不足(" + skuName + ",仓库:" + warehouseId + ",当前可用库存:" + inventory.getAvailableStock() + ",需预占:" + quantity + ")");
}
// 4. 更新库存:扣减可用库存,增加预占库存
int beforeAvailable = inventory.getAvailableStock();
int beforePreoccupy = inventory.getPreoccupyStock();
inventory.setAvailableStock(beforeAvailable - quantity);
inventory.setPreoccupyStock(beforePreoccupy + quantity);
inventory.setUpdateTime(new Date());
// 检查是否触发预警(可用库存≤预警阈值且当前状态为正常)
if (inventory.getAvailableStock() <= inventory.getWarningThreshold() && inventory.getStatus() == 0) {
inventory.setStatus(1); // 设为预警状态
// 发送预警通知消息(RocketMQ),异步处理
sendInventoryWarningMessage(inventory, skuId);
}
inventoryRepository.save(inventory);
// 5. 创建预占记录
InventoryPreoccupy preoccupy = new InventoryPreoccupy();
preoccupy.setPreoccupyId(idGenerator.nextId());
preoccupy.setSkuId(skuId);
preoccupy.setWarehouseId(warehouseId);
preoccupy.setOrderNo(orderNo);
preoccupy.setQuantity(quantity);
preoccupy.setExpireTime(expireTime);
preoccupyRepository.save(preoccupy);
preoccupyIds.add(preoccupy.getPreoccupyId());
// 6. 记录库存操作日志
recordOperateLog(skuId, warehouseId, 1, // 1-预占
inventory.getTotalStock(), inventory.getTotalStock(), // 总库存不变
beforeAvailable, inventory.getAvailableStock(),
beforePreoccupy, inventory.getPreoccupyStock(),
0, // 操作人类型:0-系统
"订单预占,订单号:" + orderNo);
// 7. 更新Redis缓存(覆盖旧值,过期时间按SKU热度动态调整)
updateInventoryCache(inventory);
}
}
// 8. 构建返回VO
InventoryPreoccupyVO vo = new InventoryPreoccupyVO();
vo.setPreoccupyIds(preoccupyIds);
vo.setPreoccupyTime(new Date());
return vo;
}
/\*\*
\* 从缓存或数据库获取库存记录
\*/
private Inventory getInventoryFromCacheOrDb(Long skuId, Long warehouseId) {
String cacheKey = "inventory:sku:" + skuId + ":warehouse:" + warehouseId;
// 1. 先查缓存
Object cacheObj = redisTemplate.opsForValue().get(cacheKey);
if (cacheObj != null) {
return (Inventory) cacheObj;
}
// 2. 缓存未命中,查数据库
Optional\ inventoryOpt = inventoryRepository.findBySkuIdAndWarehouseId(skuId, warehouseId);
if (inventoryOpt.isPresent()) {
Inventory inventory = inventoryOpt.get();
// 3. 写入缓存(热点SKU缓存24小时,普通SKU 1小时,通过SKU销量判断热度)
Result\ salesResult = skuFeignClient.getSkuSales(skuId);
long expireTime = salesResult.getData() != null && salesResult.getData().getSales() > 1000 ? 86400 : 3600;
redisTemplate.opsForValue().set(cacheKey, inventory, expireTime, TimeUnit.SECONDS);
return inventory;
}
return null;
}
/\*\*
\* 更新库存缓存
\*/
private void updateInventoryCache(Inventory inventory) {
String cacheKey = "inventory:sku:" + inventory.getSkuId() + ":warehouse:" + inventory.getWarehouseId();
// 热点SKU判断(同上)
Result\ salesResult = skuFeignClient.getSkuSales(inventory.getSkuId());
long expireTime = salesResult.getData() != null && salesResult.getData().getSales() > 1000 ? 86400 : 3600;
redisTemplate.opsForValue().set(cacheKey, inventory, expireTime, TimeUnit.SECONDS);
}
/\*\*
\* 发送库存预警消息
\*/
private void sendInventoryWarningMessage(Inventory inventory, Long skuId) {
// 1. 获取SKU关联的商家ID(用于通知指定商家)
Result\ skuResult = skuFeignClient.getSkuById(skuId);
if (skuResult.getCode() != 200 || skuResult.getData() == null) {
log.error("获取SKU信息失败,无法发送预警通知(SKU:{})", skuId);
return;
}
Long merchantId = skuResult.getData().getMerchantId();
// 2. 构建预警消息
InventoryWarningDTO warningDTO = new InventoryWarningDTO();
warningDTO.setInventoryId(inventory.getInventoryId());
warningDTO.setSkuId(skuId);
warningDTO.setSkuName(skuResult.getData().getSkuName());
warningDTO.setWarehouseId(inventory.getWarehouseId());
warningDTO.setAvailableStock(inventory.getAvailableStock());
warningDTO.setWarningThreshold(inventory.getWarningThreshold());
warningDTO.setMerchantId(merchantId);
warningDTO.setWarningTime(new Date());
// 3. 发送RocketMQ消息(预警通知服务消费消息,发送短信/APP推送)
rocketMQTemplate.send("inventory-warning-topic", MessageBuilder.withPayload(warningDTO).build());
}
/\*\*
\* 记录库存操作日志
\*/
private void recordOperateLog(Long skuId, Long warehouseId, Integer operateType,
Integer beforeTotal, Integer afterTotal,
Integer beforeAvailable, Integer afterAvailable,
Integer beforePreoccupy, Integer afterPreoccupy,
Integer operatorType, String reason) {
InventoryOperateLog log = new InventoryOperateLog();
log.setLogId(idGenerator.nextId());
log.setSkuId(skuId);
log.setWarehouseId(warehouseId);
log.setOperateType(operateType);
log.setBeforeTotal(beforeTotal);
log.setAfterTotal(afterTotal);
log.setBeforeAvailable(beforeAvailable);
log.setAfterAvailable(afterAvailable);
log.setBeforePreoccupy(beforePreoccupy);
log.setAfterPreoccupy(afterPreoccupy);
log.setOperatorId(0L); // 系统操作,operatorId=0
log.setOperatorType(operatorType);
log.setReason(reason);
log.setOperateTime(new Date());
logRepository.save(log);
}
// 其他方法:确认扣减、释放库存、预占过期释放(省略)
}
7.3.2.3 控制层(InventoryController)
@RestController
@RequestMapping("/api/inventory")
public class InventoryController {
@Autowired
private InventoryService inventoryService;
@Autowired
private ResultGenerator resultGenerator;
@Autowired
private ServiceAuthComponent serviceAuthComponent; // 飞算Java服务认证组件
@Autowired
private PermissionComponent permissionComponent; // 飞算Java权限组件
/\*\*
\* 库存预占(仅订单服务可调用)
\*/
@PostMapping("/preoccupy")
public Result\ preoccupyInventory(@Valid @RequestBody InventoryPreoccupyDTO preoccupyDTO) {
// 1. 服务认证:仅允许订单服务调用
serviceAuthComponent.validateService("order-service");
// 2. 调用服务层执行预占
InventoryPreoccupyVO vo = inventoryService.preoccupyInventory(preoccupyDTO);
return resultGenerator.success("库存预占成功", vo);
}
/\*\*
\* 库存确认扣减(仅订单服务可调用)
\*/
@PostMapping("/deduct")
public Result\ deductInventory(@Valid @RequestBody InventoryDeductDTO deductDTO) {
serviceAuthComponent.validateService("order-service");
InventoryDeductVO vo = inventoryService.deductInventory(deductDTO);
return resultGenerator.success("库存扣减成功", vo);
}
/\*\*
\* 库存预警查询(商家/运营端)
\*/
@GetMapping("/warning/list")
public Result\> getWarningInventoryList(
@RequestParam(required = false) Long merchantId,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize) {
// 1. 权限校验:商家端需传入merchantId且与令牌中的商家ID一致,运营端无需传
Long currentMerchantId = permissionComponent.getCurrentMerchantId();
if (currentMerchantId != null && (merchantId == null || !merchantId.equals(currentMerchantId))) {
return resultGenerator.fail("无权限查询其他商家的库存预警");
}
// 2. 调用服务层查询
PageInfo\ pageInfo = inventoryService.getWarningInventoryList(merchantId, pageNum, pageSize);
return resultGenerator.success(pageInfo);
}
// 其他接口:库存释放、库存调整(省略)
}
7.3.3 预占过期自动释放(定时任务)
通过飞算 Java 定时任务组件,定期扫描过期的预占记录并释放库存,防止库存长期被锁定,核心代码如下:
@Component
public class InventoryPreoccupyExpireTask {
@Autowired
private InventoryPreoccupyRepository preoccupyRepository;
@Autowired
private InventoryService inventoryService;
/\*\*
\* 每1分钟执行一次,释放过期未扣减的预占库存
\*/
@Scheduled(cron = "0 \*/1 \* \* \* ?")
public void releaseExpirePreoccupy() {
log.info("开始执行预占过期释放任务");
// 1. 查询所有过期且状态为“有效”的预占记录(expire\_time < 当前时间,status=0)
Date now = new Date();
List\ expirePreoccupies = preoccupyRepository.findByExpireTimeLessThanAndStatus(now, 0);
if (CollectionUtils.isEmpty(expirePreoccupies)) {
log.info("无过期预占记录,任务结束");
return;
}
// 2. 按订单号分组,批量释放(减少事务开销)
Map\> orderPreoccupyMap = expirePreoccupies.stream()
.collect(Collectors.groupingBy(InventoryPreoccupy::getOrderNo));
for (Map.Entry\> entry : orderPreoccupyMap.entrySet()) {
String orderNo = entry.getKey();
List\ preoccupies = entry.getValue();
// 3. 调用库存释放方法(批量处理)
InventoryReleaseDTO releaseDTO = new InventoryReleaseDTO();
releaseDTO.setOrderNo(orderNo);
releaseDTO.setReleaseReason("预占过期自动释放");
List\ itemDTOs = preoccupies.stream().map(preoccupy -> {
InventoryReleaseItemDTO item = new InventoryReleaseItemDTO();
item.setSkuId(preoccupy.getSkuId());
item.setWarehouseId(preoccupy.getWarehouseId());
item.setPreoccupyId(preoccupy.getPreoccupyId());
return item;
}).collect(Collectors.toList());
releaseDTO.setReleaseItems(itemDTOs);
try {
inventoryService.releaseInventory(releaseDTO);
log.info("预占过期释放成功,订单号:{},预占记录数:{}", orderNo, preoccupies.size());
} catch (Exception e) {
log.error("预占过期释放失败,订单号:{}", orderNo, e);
// 发送告警消息,人工干预
sendReleaseFailAlert(orderNo, preoccupies.size(), e.getMessage());
}
}
log.info("预占过期释放任务执行完成,共处理{}条预占记录", expirePreoccupies.size());
}
/\*\*
\* 发送释放失败告警
\*/
private void sendReleaseFailAlert(String orderNo, int count, String reason) {
InventoryAlertDTO alertDTO = new InventoryAlertDTO();
alertDTO.setAlertType(2); // 2-预占释放失败
alertDTO.setContent("订单" + orderNo + "的" + count + "条预占记录释放失败,原因:" + reason);
alertDTO.setAlertTime(new Date());
rocketMQTemplate.send("inventory-alert-topic", MessageBuilder.withPayload(alertDTO).build());
}
}
7.3.4 功能测试(基于飞算 Java 测试工具)
7.3.4.1 接口测试
- 库存预占测试:
模拟订单服务调用 “库存预占” 接口,传入 SKU ID、仓库 ID、预占数量(1 件)、过期时间;
验证点:可用库存减少 1,预占库存增加 1,预占记录创建成功,Redis 缓存同步更新,库存不足时返回正确提示;
- 并发超卖测试:
使用飞算 Java 压测工具模拟 1000 个并发请求,预占同一 SKU(可用库存 100 件),每个请求预占 1 件;
验证点:最终预占库存 = 100,无超卖(可用库存≥0),分布式锁生效(无并发异常);
- 预占过期释放测试:
创建预占记录(过期时间 1 分钟),等待 1 分钟后触发定时任务;
验证点:预占记录状态更新为 “3 - 已过期”,可用库存恢复,预占库存减少,操作日志记录 “预占过期自动释放”。
7.3.4.2 性能测试
使用飞算 Java 压测工具对 “库存预占” 接口进行压测:
压测参数:并发用户数 2000,持续时间 60 秒,测试 SKU 为热点 SKU(缓存命中);
预期结果:QPS≥8000,平均响应时间≤50ms,成功率≥99.99%;
实际结果:QPS=9200,平均响应时间 35ms,失败率 0.005%(因分布式锁等待超时),满足大促性能需求。
7.4 模块优化与扩展
7.4.1 性能优化
7.4.1.1 多级缓存设计
本地缓存:仓库管理员高频访问的 “本仓库库存列表” 采用 Caffeine 本地缓存(过期时间 5 分钟),减少 Redis 请求;
Redis 缓存:热点 SKU(如销量 TOP1000)库存缓存 24 小时,普通 SKU 1 小时,缓存更新采用 “写透 + 过期淘汰” 策略(更新数据库后同步更新缓存,防止脏读);
库存预热:大促前(如双 11 前 1 小时)通过定时任务将热门 SKU 库存加载至 Redis 缓存,避免大促初期缓存穿透。
7.4.1.2 数据库优化
索引优化:在
t_inventory
表的sku_id+warehouse_id
字段创建唯一复合索引(提升查询速度),在t_inventory_preoccupy
表的order_no
、expire_time+status
字段创建索引(优化预占查询与过期扫描);分表优化:按 SKU ID 哈希分表(32 张表),避免单表数据量过大(如千万级)导致查询缓慢;大促期间可动态增加分表数(飞算 Java 分表组件支持动态扩容);
批量操作:多 SKU 订单的库存预占 / 释放采用批量 SQL(如批量更新库存、批量插入预占记录),减少数据库交互次数。
7.4.1.3 异步与并发控制
非核心流程异步化:库存预警通知、操作日志记录通过 RocketMQ 异步处理,减少主流程响应时间;
分布式锁优化:热点 SKU 采用 “锁粒度细化”(按 SKU ID + 仓库 ID 加锁),避免单锁竞争;非热点 SKU 可适当延长锁超时时间(如 5 秒),降低锁等待失败率;
请求合并:商家端 “批量查询多 SKU 库存” 接口支持传入多个 SKU ID,内部合并为一次数据库查询(而非多次单 SKU 查询),提升查询效率。
7.4.2 功能扩展
7.4.2.1 虚拟库存支持
功能适配:新增 “虚拟库存” 类型(如预售商品的 “未入库库存”),区分 “实物库存” 与 “虚拟库存”,虚拟库存仅用于展示与预占,实际扣减需等待实物入库;
流程调整:预售订单预占虚拟库存,实物入库后自动将虚拟库存转为实物库存并扣减,飞算 Java 流程引擎编排 “入库→库存转换→扣减” 流程。
7.4.2.2 库存共享与调拨
多店铺库存共享:同一商家的多店铺(如品牌旗舰店、专卖店)支持共享仓库库存,用户下单时从共享库存中分配,避免某一店铺库存不足而其他店铺有货的情况;
智能调拨:当某仓库库存低于预警阈值时,系统自动计算附近仓库的可调拨数量,生成调拨建议(如 “北京仓 SKU 400001 库存不足,建议从天津仓调拨 50 件”),运营确认后执行调拨流程。
7.4.2.3 库存数据分析
库存周转率分析:计算 SKU 库存周转率(销售数量 / 平均库存),识别滞销商品(周转率低于行业均值),支持运营发起清仓活动;
库存健康度报表:通过飞算 Java 报表组件生成库存健康度报表(如预警库存占比、滞销库存占比、库存周转天数),支持按商家、仓库、品类筛选,辅助运营决策。
7.5 模块上线与运维
7.5.1 上线流程
- 代码准备:
提交代码至飞算 Java 代码仓库,触发代码质量检查(SonarQube),重点检查分布式锁、库存更新等关键逻辑,修复 “高风险” 漏洞(如无锁控制的库存扣减);
编写上线文档,包含分表迁移方案(历史库存数据迁移至对应分表)、回滚预案(库存服务异常时切换至备用服务实例)。
- 环境部署:
预发布环境:部署库存服务(5 个实例),配置 Redis 集群、RocketMQ,执行全流程测试(预占→扣减→释放→预占过期释放);
生产环境:采用 “蓝绿部署” 策略,先部署新实例(蓝环境),验证库存操作正常后切换流量,旧实例(绿环境)保留 30 分钟,异常时快速回滚。
- 数据验证:
上线后执行库存一致性校验(对比 Redis 缓存与 MySQL 数据库的库存数据),确保无差异;
模拟大促场景(如 1000 并发预占),验证系统性能与稳定性,确保无超卖。
7.5.2 运维监控
7.5.2.1 监控指标
服务指标:库存服务 CPU 使用率、内存使用率、JVM GC 频率、接口响应时间(P95/P99)、错误率;
缓存指标:Redis 缓存命中率(目标≥98%)、缓存穿透次数、缓存更新延迟;
业务指标:库存预占成功率、扣减成功率、释放成功率、超卖次数(目标 = 0)、预警库存数量、库存调整次数;
数据库指标:MySQL 分表查询耗时、主从同步延迟(目标≤100ms)、分表数据分布均匀度。
7.5.2.2 监控工具与告警
监控工具:集成飞算 Java 监控平台与阿里云 ARMS,实时展示库存核心指标仪表盘,支持按 SKU、仓库筛选数据(如查看 “北京仓” 热点 SKU 的库存操作情况);
告警配置:
业务告警:超卖次数>0、库存预占成功率<99.9%、预警库存数量>100,触发短信 + 邮件告警;
服务告警:接口响应时间 P95>100ms、错误率>0.1%,触发运维告警;
缓存告警:Redis 缓存命中率<95%、缓存穿透次数>100 次 / 分钟,触发紧急告警。
7.5.2.3 问题排查
日志分析:飞算 Java 集成 ELK 日志系统,库存服务日志按 “SKU ID”“订单号” 打标签,支持快速定位问题(如 “订单 ORD2024052510300001 库存扣减失败”);
链路追踪:通过飞算 Java 链路追踪组件(SkyWalking),查看库存操作全链路(订单服务→库存服务→数据库 / Redis),定位耗时节点(如 Redis 响应缓慢);
数据一致性修复:定期执行库存一致性校验(每 10 分钟),发现 Redis 与 MySQL 库存不一致时,自动以 MySQL 数据为准修复 Redis 缓存;若 MySQL 内部数据不一致(如总库存≠可用库存 + 预占库存),触发人工告警并提供修复脚本。
总结:飞算 Java 的电商场景价值
飞算 Java 通过 “业务痛点 - 技术组件” 的深度绑定,将电商系统开发周期缩短 40% 以上:
- 对开发:无需重复开发分布式锁、支付签名、物流对接等基础能力,聚焦业务逻辑;
- 对运维:配置化管理核心参数(物流商 / 支付渠道),监控告警自动触发,降低运维成本;
- 对业务:快速响应迭代需求(如大促临时加物流商、新增退款规则),支撑业务增长。
最终实现 “高可用、高并发、高安全、易扩展” 的电商系统,满足从中小电商到大型平台的全场景需求。