ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java+uniapp小程序商城源码:快速搭建与二次开发指南

Java+uniapp小程序商城源码:快速搭建与二次开发指南 简介这是一套基于Java与uniapp开发的智能小程序商城系统源码面向具备一定Java与前端基础、希望快速搭建多角色电商平台的开发者与学习者。项目后端采用Java编写数据库使用MySQL前端以uniapp实现小程序端并配有后台管理界面覆盖管理员、商家、用户三类角色可支撑商品发布与编辑、用户注册登录与信息修改、商品浏览下单支付、商品分类与订单处理、图片上传管理等完整业务链路适合作为课程设计、毕业设计或二次开发的基础工程。压缩包共1449个文件约23.86MB其中266个vue与175个js构成前端页面与逻辑145个java承载后端服务另有158个json、59个wxss、58个wxml等小程序配置与样式文件以及sql建库脚本、yml配置和bat启动脚本目录结构清晰便于按模块定位与调试。目前已有36人学习下载读者可据此快速理解多角色商城的权限划分、接口组织与前后端联调方式并在此基础上扩展支付、营销等模块。1. 一套 Java uniapp 的小程序商城源码到底能省下多少重复造轮子的时间如果你接过私活或者在公司里被临时抽调去做一个「带后台的微信小程序商城」大概率经历过这种局面前端要写商品列表、购物车、订单、个人中心后端要写用户、商品、订单、支付回调数据库要设计 SKU、库存、优惠券。真正从零开始光是登录态打通和订单状态机就能耗掉一周。这套基于 Java 和 uniapp 的智能小程序商城系统源码解决的就是这个「从零搭骨架」的问题——它把前后端都给你了Java 做服务端接口uniapp 做跨端小程序前端商城该有的模块基本齐活。适合谁适合想快速跑通一套商城闭环的独立开发者、接外包需要交付原型的团队以及想拿一个完整项目练手 Java 后端 uniapp 前端联调的工程师。它不是玩具 demo而是一套可以拆开、改掉、重新组装的工程骨架。2. 先看清工程骨架Java 后端与 uniapp 前端怎么分工拿到一个 zip 包最忌讳的就是直接双击打开然后一脸茫然。我一般会先花十分钟把目录结构摸清楚搞清楚哪部分是后端、哪部分是前端、它们靠什么通信。这套源码的分工很典型Java 后端提供 RESTful 接口uniapp 前端通过 HTTP 请求消费这些接口两端通过 JSON 交换数据。2.1 后端技术栈与目录职责后端是标准的 Java Web 工程常见做法是 Spring Boot MyBatis-Plus 的组合。为什么是 MyBatis-Plus 而不是原生 MyBatis因为商城系统里大量是单表 CRUD比如商品表的增删改查、订单列表分页MyBatis-Plus 的BaseMapper和LambdaQueryWrapper能把这类重复代码压到最少。你打开后端目录通常能看到这样的分层mall-backend/ ├── src/main/java/com/mall/ │ ├── controller/ # 接口层对外暴露 REST 接口 │ ├── service/ # 业务逻辑订单状态流转在这里 │ ├── mapper/ # 数据访问层继承 MyBatis-Plus 的 BaseMapper │ ├── entity/ # 数据库实体和表一一对应 │ └── config/ # 拦截器、跨域、支付配置 ├── src/main/resources/ │ ├── application.yml # 数据库、端口、第三方 key 配置 │ └── mapper/ # 复杂 SQL 的 XML 文件 └── pom.xml # Maven 依赖清单这个分层不是摆设。controller 只做参数校验和调用 serviceservice 里才是真正的业务判断比如「下单时库存够不够」「优惠券有没有过期」。你改需求时绝大多数情况只需要动 service 和 mappercontroller 基本不用碰。这就是分层带来的好处——改一处不影响全局。2.2 uniapp 前端的页面组织与请求封装前端是 uniapp 工程能编译到微信小程序、H5、App 多个端。商城类小程序的页面结构高度固定你打开 pages 目录基本能看到这些mall-uniapp/ ├── pages/ │ ├── index/ # 首页商品推荐、轮播 │ ├── category/ # 分类页 │ ├── cart/ # 购物车 │ ├── order/ # 订单列表与详情 │ └── user/ # 个人中心、登录 ├── common/ │ └── request.js # 统一请求封装拦截 token ├── static/ # 图片、图标资源 ├── manifest.json # 各端打包配置 └── pages.json # 页面路由与导航栏配置重点看common/request.js。这是整个前端的数据出入口所有接口调用都走它。常见写法是封装一个request函数统一拼接 baseURL、统一带上 token、统一处理 401 跳登录// common/request.js const BASE_URL http://localhost:8080/api function request(options) { // 每次请求前从本地缓存取 token塞进请求头 const token uni.getStorageSync(token) return new Promise((resolve, reject) { uni.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: token ? Bearer token : }, success: (res) { // 后端约定 code200 为成功其余走错误分支 if (res.data.code 200) { resolve(res.data.data) } else if (res.data.code 401) { // token 失效清缓存并跳登录页 uni.removeStorageSync(token) uni.navigateTo({ url: /pages/user/login }) reject(res.data) } else { uni.showToast({ title: res.data.msg, icon: none }) reject(res.data) } }, fail: reject }) }) } export default request这段代码的关键点有三个一是BASE_URL必须和你后端实际启动的地址端口一致本地调试时后端跑 8080前端就写 8080二是 token 的存取用uni.getStorageSync这是 uniapp 跨端的本地存储 API小程序和 App 都支持三是 401 的处理逻辑token 过期自动跳登录避免用户卡在空白页。参数上options.url是相对路径比如/goods/list不要写完整域名否则换环境时到处改。2.3 前后端联调前必须确认的三件事在真正跑起来之前有三件事必须先确认否则你会浪费大量时间在「为什么请求发不出去」上。第一后端数据库配置。打开application.yml把数据库地址、用户名、密码改成你本地的然后执行项目自带的 SQL 文件建表。第二跨域配置。小程序开发工具里请求本地接口如果后端没开跨域会直接报错。常见做法是在后端加一个全局 CORS 配置类或者在application.yml里放开。第三前端manifest.json里的 appid。微信小程序调试需要填一个测试号 appid在微信开发者工具里申请即可不填的话没法预览。提示数据库 SQL 文件一般在项目根目录的sql/或doc/文件夹下导入时注意字符集用 utf8mb4否则商品名称里的特殊符号会乱码。3. 把项目跑起来数据库导入、后端启动、前端编译的完整链路骨架看清了接下来就是让它真正跑起来。这一章我按实际操作顺序走一遍每一步都给出命令和参数说明。你照着做大概率能在半小时内看到首页商品列表。3.1 数据库建表与初始数据导入第一步永远是数据库。找到项目里的 SQL 文件通常叫mall.sql或者按模块拆成多个文件。用命令行导入# 登录 MySQL创建数据库字符集必须是 utf8mb4 mysql -u root -p -e CREATE DATABASE mall_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 导入表结构和初始数据 mysql -u root -p mall_db mall.sql # 验证表是否建好应该能看到 goods、orders、user 等表 mysql -u root -p mall_db -e SHOW TABLES;这里有个血泪经验很多人导入 SQL 时报「Unknown character set」或者导入后中文变问号原因就是数据库字符集建成了 latin1 或者 utf8注意 utf8 在 MySQL 里不是真正的 utf8mb4。商城系统里商品描述、用户昵称都可能包含 emoji 或生僻字必须用 utf8mb4。另外如果 SQL 文件里带了CREATE DATABASE语句你手动建库那步可以跳过但字符集还是要检查。导入完成后检查一下关键表的数据量。商品表goods里应该有初始商品数据如果为空前端首页就是一片空白你会误以为接口挂了。常见做法是 SQL 文件里带了几条测试商品如果没有自己手动插两条INSERT INTO goods (name, price, stock, cover) VALUES (测试商品A, 99.00, 100, /static/demo/a.jpg), (测试商品B, 199.00, 50, /static/demo/b.jpg);3.2 后端启动与接口自测数据库好了启动后端。如果你用 IDEA直接找到启动类 run 就行如果用命令行走 Maven# 在项目根目录执行跳过测试加快启动 mvn clean package -DskipTests # 启动 jar 包指定配置文件如果有多个环境 java -jar target/mall-backend-1.0.0.jar --spring.profiles.activedev启动日志里重点看两行一是Started Application in X seconds说明启动成功二是数据库连接池初始化信息如果报Access denied就是用户名密码不对报Unknown database就是库名写错了。启动成功后别急着开前端先用 curl 或者浏览器测一个接口# 测试商品列表接口确认后端能正常返回 JSON curl http://localhost:8080/api/goods/list?page1size10正常返回应该是{code:200,data:{list:[...]}}这样的结构。如果返回 404检查 controller 的RequestMapping路径和你的请求路径是否一致如果返回 500看后端控制台堆栈大概率是 SQL 写错了或者字段没对上。这一步是分水岭——后端接口通了前端问题就只剩请求地址和参数格式。3.3 uniapp 前端编译到微信小程序后端通了前端就好办。用 HBuilderX 打开 uniapp 工程或者用命令行。先改common/request.js里的BASE_URL指向你后端的地址。然后编译到微信小程序# 如果用 CLI 方式先安装依赖 npm install # 编译到微信小程序平台输出到 dist/dev/mp-weixin npm run dev:mp-weixin编译完成后用微信开发者工具打开dist/dev/mp-weixin目录。这里有个高频翻车点开发者工具里要勾选「不校验合法域名」否则请求http://localhost:8080会被拦截。勾选位置在「详情」→「本地设置」→「不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书」。打开后如果首页空白按 F12 看 Network 面板确认请求有没有发出去、返回了什么。常见情况是请求发出去了但返回 401说明登录态没建立需要先走一遍登录流程拿到 token。登录接口一般是/api/user/login传 code 给后端换 openid这套流程在源码里已经写好了你只需要在微信开发者工具里点登录按钮触发。注意uniapp 编译到微信小程序时如果报source size exceed max limit 2mb说明主包体积超了。常见做法是把非首屏页面拆到分包里在pages.json里配置subPackages。4. 商城核心模块拆解登录、商品、订单、支付怎么串起来跑起来只是第一步真正要用这套源码你得理解它的核心模块是怎么设计的。这一章我挑四个最关键的模块讲登录态怎么维持、商品 SKU 怎么组织、订单状态怎么流转、支付回调怎么处理。这四个搞懂了改需求就是改参数的事。4.1 微信登录与 token 维持机制小程序的登录和网页不一样它没有传统的账号密码而是靠微信的code换openid。流程是这样的前端调uni.login()拿到 code把 code 发给后端后端用 code appid secret 调微信接口换 openid然后生成一个自己的 token 返回给前端。前端把 token 存本地后续请求都带上。// 前端登录逻辑 uni.login({ provider: weixin, success: (loginRes) { // loginRes.code 就是临时凭证五分钟内有效 request({ url: /user/login, method: POST, data: { code: loginRes.code } }).then(res { // 后端返回的 token 存本地后续请求自动带上 uni.setStorageSync(token, res.token) uni.setStorageSync(userInfo, res.userInfo) }) } })后端拿到 code 后调微信的jscode2session接口拿到 openid 和 session_key。如果 openid 在用户表里不存在就自动注册一条新用户记录。这里的关键参数是 appid 和 secret必须配在application.yml里而且要和前端manifest.json里的 appid 一致否则换出来的 openid 对不上。token 的生成常见做法是用 JWT设置一个过期时间比如 7 天前端每次请求带上后端拦截器校验。4.2 商品 SKU 与购物车的数据结构商城的商品不是简单的一条记录它涉及 SPU标准产品单位和 SKU库存量单位。比如一件衣服有颜色和尺码两个规格红色 L 码就是一个 SKU有自己的价格和库存。这套源码里通常用两张表goods存 SPU 信息goods_sku存具体规格组合。-- 商品主表 CREATE TABLE goods ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(128) NOT NULL, price DECIMAL(10,2) NOT NULL, cover VARCHAR(255), detail TEXT ); -- SKU 表specs 字段存 JSON 格式的规格组合 CREATE TABLE goods_sku ( id BIGINT PRIMARY KEY AUTO_INCREMENT, goods_id BIGINT NOT NULL, specs VARCHAR(255) COMMENT 如 {颜色:红,尺码:L}, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0 );购物车表cart存的是 user_id sku_id 数量。加购时如果同一个 sku 已经存在就累加数量而不是插新记录。这个逻辑在 service 层用selectOne判断一下就行。下单时从购物车读取选中的记录生成订单和订单明细同时扣减 SKU 库存。扣库存一定要用UPDATE goods_sku SET stock stock - ? WHERE id ? AND stock ?这种带条件的更新防止超卖。4.3 订单状态机与支付回调处理订单状态是商城系统里最容易出 bug 的地方。这套源码一般定义了这几个状态待付款、待发货、待收货、已完成、已取消。状态流转必须单向不能从「已完成」跳回「待付款」。常见做法是在 service 层写一个状态校验方法每次变更前检查当前状态是否允许目标操作。支付回调是另一个坑。微信支付成功后微信服务器会异步通知你的后端这个通知可能重复发送。所以回调处理必须做幂等——先查订单状态如果已经是「已支付」就直接返回成功不要重复加积分、重复改库存。回调接口的签名验证也不能省否则别人伪造一个请求就能把你的订单改成已支付。// 支付回调的幂等处理伪代码 public String payCallback(String orderNo, String transactionId) { Order order orderMapper.selectByOrderNo(orderNo); // 已经处理过直接返回成功避免重复业务 if (order.getStatus() OrderStatus.PAID) { return SUCCESS; } // 校验签名防止伪造回调 if (!verifySign(...)) { return FAIL; } order.setStatus(OrderStatus.PAID); order.setTransactionId(transactionId); orderMapper.updateById(order); return SUCCESS; }提示本地调试支付回调时微信服务器没法通知你的 localhost。常见做法是用内网穿透工具把本地端口映射出去或者在后端写一个测试接口手动触发回调逻辑。5. 避坑与排查这套源码最容易翻车的五个地方源码跑通不代表能用真正上线前你会遇到一堆环境、配置、兼容性问题。这一章我列五个最常见的坑每个都按「现象 → 原因 → 解决」写清楚。这些都是我实际踩过的不是网上抄的。5.1 小程序请求本地接口全部失败现象前端编译到微信开发者工具后所有接口请求都报request:failNetwork 面板里看不到请求。原因微信开发者工具默认校验合法域名http://localhost不在白名单里。解决在开发者工具「详情」→「本地设置」里勾选「不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书」。如果是在真机上调试localhost 要换成电脑的局域网 IP比如http://192.168.1.100:8080并且手机和电脑要在同一个 WiFi 下。5.2 后端启动报数据库连接失败现象java -jar启动后日志报Communications link failure或Access denied for user。原因application.yml里的数据库地址、端口、用户名、密码和你本地实际的不一致。解决逐项核对配置特别注意端口——MySQL 默认 3306但有些人本地装了两个版本会改成 3307。另外如果密码里有特殊字符比如或#在 yml 里要用引号包起来否则会被解析成注释或分隔符。5.3 商品图片不显示现象首页商品列表有数据但图片位置是空白或者裂图。原因数据库里存的图片路径是相对路径比如/static/demo/a.jpg但前端实际请求的是后端域名下的路径或者图片根本没放进static目录。解决确认图片文件是否存在于前端static目录如果图片存在后端服务器上数据库里要存完整 URL 或者前端拼接后端地址。常见做法是后端返回图片时统一拼上 CDN 前缀前端直接用。5.4 订单金额计算出现小数误差现象购物车结算时总价和实际支付金额差几分钱。原因Java 的double和float做金额计算会有精度丢失比如0.1 0.2 0.30000000000000004。解决金额字段一律用BigDecimal数据库用DECIMAL(10,2)。计算时用BigDecimal.add()和multiply()不要用和*。这个坑在商城系统里是致命的用户投诉金额不对查起来还特别费劲。5.5 uniapp 编译到 App 端白屏现象小程序端正常编译到 App 后打开白屏。原因App 端和微信小程序的运行环境不同某些小程序专有 API 在 App 端不存在比如wx.开头的调用。解决统一用uni.开头的 APIuniapp 会自动做平台适配。另外检查manifest.json里的 App 模块配置比如定位、支付等权限有没有勾选。如果用了原生插件App 端需要单独打包基座才能调试。6. 二次开发进阶改造成多商户或接入新支付渠道的思路这套源码的默认形态是单商户商城但实际接活时经常遇到「能不能改成多商户」或者「能不能接汇付天下」这类需求。这一章我讲两个进阶改造方向都是在这套骨架上动刀不需要推倒重来。6.1 从单商户到多商户的最小改动路径多商户的核心是「每个商品属于一个商户每个订单要拆分成多个子订单」。最小改动路径是加一张merchant表然后在goods表加merchant_id字段在orders表加merchant_id。下单时如果购物车里有多个商户的商品就按商户拆单生成一个主订单和多个子订单。主订单记录总金额和支付状态子订单记录各商户的商品和分账金额。-- 新增商户表 CREATE TABLE merchant ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL, contact VARCHAR(32), status TINYINT DEFAULT 1 COMMENT 1正常 0禁用 ); -- 商品表关联商户 ALTER TABLE goods ADD COLUMN merchant_id BIGINT NOT NULL DEFAULT 1; CREATE INDEX idx_merchant ON goods(merchant_id); -- 订单表关联商户支持拆单 ALTER TABLE orders ADD COLUMN merchant_id BIGINT NOT NULL DEFAULT 1; ALTER TABLE orders ADD COLUMN parent_order_no VARCHAR(64) COMMENT 主订单号拆单时使用;改完之后前端商品列表要按商户筛选购物车要按商户分组显示订单列表要区分主订单和子订单。工作量主要在 service 层的拆单逻辑和前端的分组展示controller 改动不大。这个改造我做过两次第一次没拆单直接按商户分表结果退款时对不上账后来老老实实拆单才理顺。6.2 接入新支付渠道的适配层设计支付渠道的接入最忌讳把支付逻辑写死在订单 service 里。常见做法是抽一个PayService接口定义createPay、queryPay、refund三个方法然后每个渠道写一个实现类。微信支付一个实现汇付天下一个实现支付宝一个实现。订单 service 只依赖接口不依赖具体实现通过工厂模式或者 Spring 的Qualifier选择渠道。public interface PayService { // 创建支付返回前端调起支付所需的参数 PayResult createPay(String orderNo, BigDecimal amount); // 查询支付状态 PayStatus queryPay(String orderNo); // 退款 RefundResult refund(String orderNo, BigDecimal amount); } Service(wechatPay) public class WechatPayService implements PayService { // 微信支付的具体实现 } Service(huifuPay) public class HuifuPayService implements PayService { // 汇付天下的具体实现 }这样改的好处是以后再加支付渠道只需要新增一个实现类订单逻辑一行不用动。参数配置上每个渠道的 appid、密钥、回调地址都放在application.yml里用ConfigurationProperties绑定到一个配置类。回调地址要区分渠道比如/api/pay/callback/wechat和/api/pay/callback/huifu各自处理各自的签名验证。从那以后我每次拿到一套新源码都强制先跑通「登录 → 加购 → 下单 → 支付回调」这条最小闭环再去看其他模块。因为这条链路串不起来后面改什么都是空中楼阁。这套 Java uniapp 的商城源码骨架是完整的坑也集中在环境和配置上把上面这些点过一遍基本就能拿来改造成自己的项目了。希望帮到你。本文还有配套的精品资源点击获取
返回列表