Java成人用品商城源码二次开发:从部署到订单状态机的完整避坑指南

简介:新版JAVA开源成人用品零售商城APP源码整合了安卓、iOS双端原生工程及微信小程序端,面向有自营货源的两性健康产品商家,解决线上选品、下单与订单管理需求,适合具备Java/小程序开发基础、希望快速搭建商城原型或研究移动端多端架构的中高级开发者。压缩包共2021个文件,以java、h、m、js、json、html、css等为主,涵盖后端接口、原生页面、前端逻辑、静态资源及配置文件;另含sql、xml、yaml、sh等部署或构建辅助文件,整体包体约346.02MB。资源描述显示项目聚焦产品分类、主页爆款展示、简洁购买流程、促销与优惠券模块,便于后续扩展会员与营销功能。已有558人学习下载,完整目录结构便于按端与功能模块检索,适合用于二次开发、架构参考或毕业设计素材。注意包内未附带搭建教程,下载后需自行研究环境配置与运行方式。

1. JAVA 成人用品商城源码:先想清哪个端才是你的主力

别以为拿到这套新版 JAVA 成人用品零售商城 APP 源码、双击 IDE 就能跑。资源包里是后端 + 安卓原生 + iOS 原生 + 微信小程序四份工程一起打包的,我拆包后的第一感觉是:东西是真的全,商品分类、首页推荐位、购物车、订单、促销、优惠券都有,但因为压缩包里没有搭建教程,想跑起来最省力的路径不是三端齐推,而是先让后端和小程序形成闭环。适合两类人:一类是有货源、想快速上一套能用的两性健康产品商城做线上渠道的老板;另一类是手里有商城开发需求、想找现成 JAVA 后端做二次开发的程序员。先想清楚谁是你的主力端,后面每一步都会省很多时间。

2. 源码结构先看懂:四份工程如何组织、后端技术栈怎么判断

2.1 从目录和静态资源推断项目底子

老的开源商城压缩包,顶层目录一般不像新项目那么规整,但万变不离其宗。不要一上来就全局搜索启动类,先按“后端接口、后台管理、买家端接口、安卓、iOS、小程序、SQL”这个维度把文件夹归归类,十有八九能对上。我一般会先画一个这样的文件树:

shop-api/ # 后端接口服务(Spring Boot/Spring MVC 工程) shop-admin/ # 后台管理:JSP + Bootstrap/LayUI 页面 shop-services/ # 后端业务逻辑模块(部分项目叫 core 或 mapper) android/ # 安卓原生工程(Java/Kotlin) ios/ # iOS 原生工程(Objective-C/Swift) miniapp/ # 微信小程序原生工程 sql/ # 数据库初始化脚本 doc/ # 文档目录,这个包大概率是空的

这个文件树的组织逻辑是:接口服务只对外提供 REST API,后台管理是运营人员用的网页,买家用的则是安卓、iOS、小程序三个壳。它们的共同点是都要访问同一套后端接口,所以后端是绝对核心。

包内出现的 bootstrap.css、layui.css、ueditor.css、font-awesome.css 这几个文件名,其实已经能把技术栈交代大半:后台管理界面用的是 Bootstrap 和 LayUI 两套经典前端框架,font-awesome 提供后台的图标字体,ueditor.css 是 UEditor 富文本编辑器的样式,说明商品详情、公告这类内容是在后台用富文本编辑后存进数据库的,买家端拿到的是存好的 HTML。这种组合是前几年 JAVA 商城项目里非常主流的一套,特点是资料多、改起来不玄学。

提示:如果解压后没有看到类似 shop-api 这样的后端目录,只有一堆 JSP 页面和 Java 类混在一起,那大概率是 SSM(Spring + Spring MVC + MyBatis)结构的单体项目,部署方式还是 war 包配 Tomcat 那套。

技术栈可以按这个思路判断:

层次常见选型判断依据
后端框架Spring Boot 2.x / Spring MVC有启动类或 web.xml、pom.xml 依赖
ORMMyBatis / tk.mybatismapper.xml 或 @Select 注解,SQL 和 Java 混排
数据库MySQL 5.7/8.0sql 目录下的 .sql 脚本
缓存Redis登录 token、购物车、验证码
后台管理JSP + Bootstrap + LayUI包内静态资源文件名可判断
富文本UEditorueditor.css

如果发现项目是用 Maven 管理的,后面所有编译、打包、启动操作都用 Maven 命令走一遍,比在 IDE 里乱点按钮可靠。

2.2 后端业务模块与数据库表设计看门道

商城类项目的核心模块说白了就五块:会员、商品、购物车、订单、营销。成人用品商城在这之外对购买流程的匿名性要求比普通电商高,好在大多数源码在会员昵称、收货地址上已经用了通用字段,不需要大改。

从“产品分类清晰、首页突出主打产品、购买流程不繁琐、方便查看订单、有促销和优惠券”这几条需求逆推,数据库里至少要出现这些表:

表职责关键字段(常见命名)
member会员主表mobile、nickname、balance、create_time
goods商品主表(SPU)title、category_id、main_image、is_on_sale、recommend_flag
goods_sku商品规格(SKU)goods_id、spec、price、stock
cart购物车member_id、sku_id、quantity
order_info订单主表order_no、member_id、status、pay_amount、coupon_id
order_item订单明细order_id、sku_id、goods_name、price、quantity
coupon优惠券模板type、amount、min_amount、valid_start、valid_end
coupon_member会员领券记录member_id、coupon_id、status
address收货地址member_id、consignee、mobile、province/city/district、is_default
shipping物流信息order_id、company、tracking_no

订单表拆成 order_info 和 order_item 两张,是商城项目里必须的习惯:订单主表只存一次支付相关的信息,明细表存 SKU 快照。快照这个词很关键——商品改价、下架甚至删除,都不影响历史订单里“当时买的是什么价格、什么规格”。

首页“突出主打产品”这个需求,在数据结构上一般靠 goods 表的 recommend_flag 或 is_hot 字段,后台把某件商品置为推荐,前端首页接口就按这个标志倒序取;促销信息则体现在两个位置:商品 SKU 的促销价,以及优惠券模板的满减规则。看源码时先顺着 member → goods → cart → order → coupon 这条线读,别从后台管理那些页面开始,那是运营视角,不是数据流转视角。

2.3 三端共用一套接口协议:动手前先列接口清单

后端给安卓、iOS、小程序提供的是同一套 RESTful JSON 接口,鉴权方式一般是通过登录接口拿 token,后续请求把 token 放进 Header 的 Authorization 或自定义字段里。虽然是老项目,但接口路径命名大体有规律,建议动手改之前先把关键接口列成一张表:

模块接口方法说明
登录注册/api/member/loginPOST手机号+密码登录,返回 token
商品/api/goods/listGET分页商品列表,支持分类和推荐位
商品/api/goods/detailGET详情、SKU、富文本详情
购物车/api/cart/addPOST加购,传 sku_id 和数量
购物车/api/cart/listGET当前用户购物车
优惠券/api/coupon/listGET可领取的券列表
优惠券/api/coupon/receivePOST领取操作
订单/api/order/createPOST从购物车或直接购买创建订单
订单/api/order/listGET按状态查订单
支付/api/pay/notifyPOST微信支付回调

先列这张表的理由很直接:三端同时开发,最怕安卓调 /api/goods/detail?id=1,iOS 调 /api/goods/detail?goodsId=1,后端一改参数名,总有一个端在翻车。把接口清单贴在项目 README 里,之后每改一个接口,照着清单把三端对应调用一起回归,能省掉大量联调时间。

列完清单再读代码,你会发现后端 service 层的方法和这张表几乎一一对应,调用的入口在 Controller,业务规则在 Service,SQL 在 Mapper 里。改动的优先级建议是:先改 Mapper 的 SQL 验证数据,再动 Service 补业务,最后才碰 Controller 的出入参,这个顺序能少踩一半的坑。

3. 把后端和小程序端跑起来:部署顺序与关键配置

3.1 环境准备:JDK8、MySQL、Redis 一个不能少

因为包内没有搭建教程,第一步就是自己把环境对齐。这类老 JAVA 商城几乎没有跑在 JDK 11 以上的,老老实实装 JDK 8 能省很多事。MySQL 和 Redis 也一样,版本别太激进。

# 先确认三个基础组件的版本 java -version mysql -V redis-cli ping # 建库;很多老 SQL 脚本默认不带 CREATE DATABASE mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS shop_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"

这段命令里,redis-cli ping 返回 PONG 才算正常;建库指定 utf8mb4 是因为商品详情、用户备注里可能出现 emoji 字符,用 utf8 会直接报 Incorrect string value。库名如果和源码配置里不一致,后续统一改 application.yml,不要把库建了又删。

如果本地用 Docker,也可以直接起容器,但要注意宿主机的 3306、6379 端口别和已有服务冲突。启动后端前先看一眼 8080 端口是否空闲:

lsof -i :8080 # Linux/macOS netstat -ano | findstr 8080 # Windows

端口被占用是老项目启动失败最容易被忽略的原因之一,后端日志里报端口占用时,很多人第一反应是去改代码,其实该换端口或者杀掉占用进程。

3.2 数据库初始化:SQL 导入前先看编码和表前缀

后面所有功能验证都建立在数据库干净可用的基础上,所以 SQL 导入这步值得多花两分钟。老项目导出的脚本经常是 GBK 编码,直接在 Navicat 里执行完,中文注释、初始化数据全是乱码,看起来是小事,后面排查商品名乱码时会特别抓狂。

# 先看脚本到底是什么编码 file sql/shop.sql # 如果显示 ISO-8859,多半来自 GBK iconv -f GBK -t UTF-8 sql/shop.sql -o sql/shop_utf8.sql # 指定字符集导入 mysql -uroot -p --default-character-set=utf8mb4 shop_db < sql/shop_utf8.sql # 确认表数量,老商城一般 20 到 40 张表 mysql -uroot -p -e "USE shop_db; SHOW TABLES;"

file 命令输出如果带 UTF-8 Unicode text,那直接导入即可,不用转码。还有一种常见情况是 SQL 脚本里所有表名都带统一前缀,比如 pre_goods、pre_order_info,这种前缀会让后续手写 SQL 时容易漏加,建议先在配置里搜“prefix”或“tablePrefix”关键字,MyBatis 体系里有个全局配置可以自动加前缀。

导入完成后随便查一张表验证数据:

SELECT id, title, is_on_sale, recommend_flag FROM goods LIMIT 5;

如果返回的商品标题是可读中文,说明字符集没出问题。接下来才去动代码配置。

3.3 改配置:数据库、Redis、微信支付参数

后端配置文件一般叫 application.yml 或 application-dev.properties,最常见的是 application.yml。核心改动点有三个:数据源、Redis、微信支付。

server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/shop_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: 127.0.0.1 port: 6379 password: # 本地 Redis 没密码就留空 database: 0 wx: pay: appid: wx8888888888888888 mch-id: 1600000000 api-v3-key: 你的 APIv3 密钥 notify-url: https://mall.example.com/api/pay/notify

这里有几个细节:driver-class-name 如果是老项目,默认可能是 com.mysql.jdbc.Driver,在高版本 MySQL 驱动下会报类找不到,换成新驱动即可;url 里的 serverTimezone 必须保留,否则启动时直接报时区异常。Redis 的 database 默认 0,很多老代码写死配置,改数据库编号会导致 token 和购物车数据互相找不到。微信支付参数先留着占位,本地联调阶段不要让真实支付走通,等域名和商户号都备好再填。

改完配置启动后端前,先确认 Maven 依赖有没有下载完整。老项目里用到的一些旧版本依赖在国内下载慢,可以给 Maven 配阿里云镜像,这一步不做,启动时会在依赖下载上卡很久。

mvn clean package -DskipTests java -jar target/shop-api.jar

启动日志里看到 Tomcat started on port(s): 8080 才算成功。很多老项目启动后报一堆 BeanCreationException,十有八九是数据库缺表或者 Redis 没连上,按这个顺序排查,比反复改配置有效。

3.4 小程序端:改 baseUrl 与请求合法域名

后端起来之后,小程序端要先改接口地址。小程序工程里一般有一个 config.js 或 request.js 专门管理接口根路径,这一步决定你所有请求是否发对地方。

// utils/config.js module.exports = { // 开发阶段:电脑 IP,手机需要和电脑在同一局域网 baseUrl: 'http://192.168.1.100:8080/api', // 正式环境:换成已备案的 HTTPS 域名 // baseUrl: 'https://mall.example.com/api' }

改完根路径还不够,还要看 request.js 里封装的请求函数有没有统一带 token。常见做法是 wx.login 拿到 code,后端换 openid 并签发 token,前端存在 wx.setStorageSync 里,每次请求从 storage 取出来塞进 Header。

开发阶段有两个开关要打开:微信开发者工具右上角“详情-本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”,不然用 http://IP 请求会因为域名不合法直接被拦。真机预览时,需要在手机微信里打开调试模式才能看到请求日志。用 Charles 这类抓包工具去调小程序请求时,只要把抓包工具配好,就能看到 /api/goods/list 这种请求到底是否返回了 200 和 JSON 数据。

3.5 走通最小闭环:注册、上架、购买、查看订单

环境和配置就绪后,不要急着调优惠券和促销,先走一条最朴素的下单链路:

  1. 小程序端注册一个测试账号;
  2. 打开后台管理,把任意一件商品设为在售并推荐到首页;
  3. 小程序首页能刷出该商品,点击进详情;
  4. 加入购物车,结算下单;
  5. 后台订单列表能看到这笔订单,状态为“待发货”。

这一步相当于打通血管。大多数老商城在这一步暴露的问题不是业务逻辑,而是基础联通问题:IP 不通、端口不通、token 没生效。用 curl 可以直接验证后端接口:

curl -s "http://127.0.0.1:8080/api/goods/list?page=1&limit=10" | head -c 500

返回 JSON 数组或包含 total 的对象,说明 Controller、Service、Mapper 链路是通的;返回 HTML 或 404,先查 URL 有没有带对上下文路径,老项目经常是把整个应用部署在 /shop-api 这种路径下,接口根地址就变成 http://IP:8080/shop-api/api。

4. 安卓与 iOS 原生端适配:老代码在新设备上的三关

4.1 安卓端:明文流量限制与图片加载失败

安卓工程如果用的还是 Java 原生写法,拿到手直接在 Android Studio 里打开,第一关几乎一定是网络请求失败。Android 9(API 28)之后,系统默认禁止应用发起明文 HTTP 请求,而老代码里的接口和图片地址大概率是 http。

<!-- AndroidManifest.xml --> <application android:usesCleartextTraffic="true" android:networkSecurityConfig="@xml/network_security_config">

直接加 usesCleartextTraffic="true" 最简单,开发阶段完全够用。更规范的做法是新建 xml/network_security_config.xml,只对开发域名放行明文:

<network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">192.168.1.100</domain> </domain-config> </network-security-config>

第二个高频问题是图片加载。老商城商品图片路径往往是相对路径,像 /upload/goods/123.jpg,而 Glide 或 ImageLoader 需要完整 URL。联调时看到首页商品有文字没图片,先去后端的商品表里看一眼 image_url 字段值,再在图片加载代码里补一个拼接逻辑:

// ImageLoader 加载前统一拼接域名 String fullUrl = imageUrl.startsWith("http") ? imageUrl : baseUrl + imageUrl; imageLoader.display(imageView, fullUrl);

除此之外还要检查安卓工程里 build.gradle 的 minSdk 和 targetSdk。老项目如果 targetSdk 太低,上架新应用市场会被拒审;一下子升到 33 或 34,则要处理分区存储、通知运行时权限这些新规则。我的建议是保持老代码的业务层不动,只把网络、存储、权限这几块按新规范适配。另一个容易忽略的是回调线程:老代码里网络请求的回调如果直接在子线程更新 UI,Android 会直接抛 CalledFromWrongThreadException,需要在回调里切回主线程再刷新列表。

4.2 iOS 端:ATS 限制与 URL Scheme

iOS 工程拿过来,第一件事是看 Info.plist。iOS 9 之后系统默认开启 ATS(App Transport Security),不允许 HTTP 明文请求,老项目里的接口地址全是 http,不配置直接白屏。

<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>

这个 key 是全局放行所有 HTTP,调试阶段用没问题,上架前最好收紧成按域名白名单放行。第二个关键配置是 URL Scheme,微信支付和微信登录都靠它在支付完成后跳回 App,配置长这样:

<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>wx6b57f0e0c0e0c0e0</string> </array> </dict> </array>

这个值必须和微信开放平台里登记的 AppID 对应,否则支付成功后微信无法拉起你的 App。iOS 端还有签名问题:个人免费 Apple ID 可以装到自己的真机调试,但多设备分发和上架必须用开发者账号;老代码的 Bundle Identifier 建议顺便改掉,避免和 App Store 里已有的应用冲突。

如果 iOS 工程用了 CocoaPods 管理第三方库,先 pod install 再打开 .xcworkspace,直接打开 .xcodeproj 会导致依赖找不到。这个坑在老项目里出现频率很高。

4.3 双端通用配置:包名、推送与地图

安卓和 iOS 在联调阶段会同时撞上三个通用问题:包名、推送、地图。

包名要统一改掉源码作者留下的 com.example 或 com.shop 这类后缀,改成自己公司的域名反写,否则推送、分享这类第三方 SDK 会校验不通过。推送 SDK 如果是友盟或极光,需要到官网重新注册应用,拿到新的 AppKey 填进两端工程;这一步经常被忽略,结果就是安卓能推送 iOS 不能,或者反过来。成人用品商城这种私密品类,推送文案尤其要克制,建议只发订单状态提醒,不做营销推送。

地图选点和收货地址解析如果接了高德或腾讯地图,源码里写死的 Key 也是作者的,到了你手里会报 INVALID_USER_KEY,需要重新申请并把 SDK 包名、Bundle ID 更新到地图开放平台后台。这个改起来不复杂,但很容易在联调最后阶段突然冒出来,我习惯在拆包第一天就把所有第三方 Key 全部列成一张表:

第三方服务需要检查的配置典型报错
微信支付/登录AppID、URL Scheme、商户号支付回调没反应
友盟/极光推送AppKey、包名推送收不到
高德/腾讯地图Key、包名、Bundle IDINVALID_USER_KEY
即时通讯(如果有)AppID、证书登录失败

到这里,三端就都能连上同一套后端了。但真正的上线开发,还会被一批“看起来不要紧,实际很致命”的问题绊住,下一章说几个我拆这类源码时踩过的坑。

5. 避坑:六条能省你两天的翻车记录

拆这种老商城源码,代码本身的问题往往不是最耗时的,环境、字符集、权限这类外围问题才是。以下几条都是我在类似项目上遇到过的真实情况,按现象到解决的顺序写。

5.1 环境与数据层的三个坑

第一条:SQL 导入后中文乱码。 现象:后台商品列表全是问号或乱码,新添加的商品正常,老数据全花。 原因:SQL 脚本是 GBK 编码,导入时没有转成 UTF-8,还指定了 utf8mb4 字符集。 解决:按 3.2 里用 file 和 iconv 先转码再导入。如果已经导乱了,把库删掉重建重新导入,别在乱码数据上补丁。这条算血泪经验:导入前多花 3 分钟看编码,比导入后清数据重建表快得多。

第二条:8080 端口被占用或者防火墙拦着。 现象:后端日志显示启动成功,但小程序和安卓请求全部超时。 原因:Tomcat 起在 8080,但本机防火墙或云服务器安全组没有放行;或者端口被别的进程占用,应用实际起在了随机端口上。 解决:先 lsof -i:8080 看进程,再 telnet 127.0.0.1 8080 验证本地连通,最后检查防火墙放行。这一步每次部署我都会先做,比改半天代码有效。

第三条:JDK 版本过高导致编译不过。 现象:mvn clean package 报错,有的错误信息指向 Lombok 或某个不兼容新 JDK 的依赖。 原因:老工程是为 JDK 8 写的,用了 JDK 9+ 才移除的内部 API 或旧版 Lombok。 解决:装 JDK 8,把 JAVA_HOME 指过去,再重试。不要为了“新版本”硬着头皮升级依赖,商城这种业务系统,别折腾,够用就行。

5.2 多端联调里的三个坑

第四条:小程序真机预览白屏,开发者工具却一切正常。 现象:开发者工具里接口正常、页面正常,换了真机预览就是白屏或转圈。 原因:真机上微信的“不校验合法域名”开关不生效,请求被微信拦截;也可能是手机和服务器不在同一网络,局域网 IP 不通。 解决:开发阶段用“预览”时勾选“忽略域名校验”,或者改用开发版体验;最省事的方式是小程序后台配置合法域名,但在没有备案时,局域网联调需要真机和电脑同一 WiFi。用抓包工具看一眼请求是否发出,能快速区分是网络问题还是微信拦截。

第五条:金额单位不一致,导致支付金额翻了一百倍或变成 0。 现象:订单列表金额显示正常,但支付时提示金额不对,或者后台统计对不上账。 原因:后端金额用“分”存,前端展示时除以 100 转成“元”;但某个接口返回的是元,另一个接口返回的是分,前端没有统一处理。 解决:全局搜索所有金额字段,规定后端一律整数“分”,前端展示统一除以 100。这个约定要写进接口清单里,前端不再做任何乘除。否则对账对不上时,你会怀疑人生。

第六条:支付回调没走到后端。 现象:用户付了款,小程序里还是“待支付”,后台订单也没变化。 原因:微信支付回调地址需要外网能访问,本地开发时回调打不进来。 解决:开发阶段在微信支付平台把回调地址配成内网映射工具的临时域名,联调通了再换成正式域名;上线前务必确认回调地址是 HTTPS 且不能被防火墙拦。同时检查后端回调接口里有没有验签逻辑,验签失败会静默返回 success,订单就一直停在待支付。我每次部署支付相关项目都强制自己先打一行日志确认回调真的进来了,再做业务处理。

6. 订单状态机与优惠券并发:上线前先补的两块木板

小程序和双端 App 都能跑通之后,这个商城已经能用了,但距离“敢让真实用户下单”还差两块木板:订单状态流转和优惠券并发。老源码里的订单状态通常散落在 Service 层的一堆 if 判断里,读起来费劲,改起来容易漏。

我拿到手的第一件事是建一个状态表,把所有状态整理成一张流转关系:

状态可流转到触发动作
待支付(0)已取消/待发货用户取消/支付回调
待发货(1)待收货商家后台发货
待收货(2)待评价/已取消用户确认收货/超时自动确认
待评价(3)已完成提交评价
已完成(4)无终态
已取消(9)无终态

然后在代码里把状态判断收拢成一个枚举,所有流转都走同一个定义:

public enum OrderStatus { WAIT_PAY(0), WAIT_SEND(1), WAIT_RECEIVE(2), WAIT_COMMENT(3), FINISHED(4), CANCELED(9); private final int value; OrderStatus(int value) { this.value = value; } public int value() { return value; } }

这样做的收益是:任何一处需要判断状态的地方,不再出现散落的魔法数字 0、1、2,而是 OrderStatus.WAIT_PAY.value()。改状态时只在定义处改,三端接口返回的状态值不会因为某个 Service 方法漏改而出错。

优惠券并发问题更隐蔽。老代码里领券一般是“先 select 再 insert”:

if (couponMapper.countByMember(memberId, couponId) > 0) { return Result.error("您已领取过该券"); } couponMapper.insert(memberId, couponId);

如果两个请求同时来,这两行之间存在时间差,用户就能领到两张同款券,甚至把库存领穿。解决方法是加唯一索引,让数据库兜底:

ALTER TABLE coupon_member ADD UNIQUE KEY uk_member_coupon (member_id, coupon_id);

然后应用层捕获 DuplicateKeyException 后统一返回“已领取过”。如果优惠券模板带数量限制,还可以在发放前用 Redis 的原子自减校验余量,业务量起来后再上 Lua 脚本扣减,避免超发。

这套源码最大的价值是业务流程完整、三端齐全,作为二次开发底座比从零搭省太多时间。但它终究是“别人写好的代码”,接手的重点不是读懂每一行,而是先把状态和金额这两个最容易出乱子的地方钉死。

我之前接过一个老商城维护的活儿,就是因为订单状态散落各处,用户退款后后台还能发货,最后对账对了一星期。从那以后,我每接手一套商城源码,都强制自己先把订单状态流转和金额单位约定画出来,再碰其他模块。希望这点经验帮到你,也让你少走一次这种弯路。

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