1. 项目概述与背景
电子商城购物平台小程序是基于Java后端和微信小程序前端开发的完整电商解决方案。这个项目最初源于我在指导计算机专业学生毕业设计时的需求——他们需要一个既能体现完整开发流程,又具备实际应用价值的实战案例。
在移动互联网时代,微信小程序因其无需安装、即用即走的特性,成为电商领域的重要入口。根据腾讯2022年财报数据,微信小程序日活跃用户已突破5亿,其中电商类小程序占比达28%。这种背景下,开发一个功能完备的电子商城小程序,不仅具有教学意义,也能为中小商家提供快速上线的电商解决方案。
2. 技术选型与架构设计
2.1 核心技术栈
后端技术栈:
- Spring Boot 2.7.3:提供快速应用开发框架
- MyBatis-Plus 3.5.1:简化数据库操作
- MySQL 8.0:关系型数据库
- Redis 6.2:缓存和会话管理
- Swagger 3.0:API文档生成
前端技术栈:
- 微信小程序原生框架
- WXML/WXSS:页面布局和样式
- JavaScript ES6:业务逻辑实现
- Vant Weapp 1.10.0:UI组件库
2.2 架构设计考量
采用前后端分离架构,主要基于以下考虑:
- 微信小程序天然适合前后端分离模式
- 便于后期扩展多端应用(如H5、App)
- 团队分工明确,提高开发效率
系统架构分为四层:
- 表现层:微信小程序界面
- 应用层:Spring Boot RESTful API
- 业务逻辑层:核心业务处理
- 数据访问层:MySQL+Redis数据持久化
提示:在小型电商项目中,这种分层架构既能保证系统扩展性,又不会引入过多复杂性。对于毕业设计级别的项目,建议不要过度设计架构。
3. 数据库设计与实现
3.1 核心表结构
用户表(user)
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` varchar(100) NOT NULL COMMENT '密码',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`gender` tinyint DEFAULT '0' COMMENT '性别(0:未知 1:男 2:女)',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
`status` tinyint DEFAULT '1' COMMENT '状态(0:禁用 1:正常)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
商品表(product)
sql复制CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`category_id` bigint NOT NULL COMMENT '分类ID',
`name` varchar(100) NOT NULL COMMENT '商品名称',
`images` text COMMENT '商品图片(JSON数组)',
`brand` varchar(50) DEFAULT NULL COMMENT '品牌',
`spec` varchar(100) DEFAULT NULL COMMENT '规格',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`origin_price` decimal(10,2) DEFAULT NULL COMMENT '原价',
`stock` int DEFAULT '0' COMMENT '库存',
`sales` int DEFAULT '0' COMMENT '销量',
`detail` text COMMENT '商品详情',
`status` tinyint DEFAULT '1' COMMENT '状态(0:下架 1:上架)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 数据库优化实践
-
索引设计:
- 为所有外键字段添加普通索引
- 为高频查询条件(username, phone)添加唯一索引或普通索引
- 避免过度索引,特别是对频繁更新的表
-
字段类型选择:
- 金额使用DECIMAL(10,2)避免精度丢失
- 大文本使用TEXT类型
- 状态字段使用TINYINT而非VARCHAR
-
分表策略:
- 订单表按月份分表(order_202301, order_202302)
- 日志表按业务类型分表(log_login, log_operation)
4. 核心功能实现
4.1 用户认证流程
微信小程序登录采用官方提供的登录凭证校验流程:
- 前端调用wx.login获取code
- 将code发送到后端服务器
- 后端用code向微信接口服务换取openid和session_key
- 生成自定义登录态(token)返回给小程序
- 小程序存储token用于后续接口鉴权
关键代码实现:
java复制@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Value("${wx.appid}")
private String appid;
@Value("${wx.secret}")
private String secret;
@PostMapping("/login")
public Result login(@RequestParam String code) {
// 构建请求URL
String url = "https://api.weixin.qq.com/sns/jscode2session?" +
"appid=" + appid +
"&secret=" + secret +
"&js_code=" + code +
"&grant_type=authorization_code";
// 发送HTTP请求
String response = restTemplate.getForObject(url, String.class);
JSONObject json = JSON.parseObject(response);
// 处理响应
if(json.containsKey("errcode")) {
return Result.error("登录失败: " + json.getString("errmsg"));
}
String openid = json.getString("openid");
String sessionKey = json.getString("session_key");
// 查询或创建用户
User user = userService.getOrCreateUser(openid);
// 生成token
String token = JwtUtil.generateToken(user.getId());
return Result.success(token);
}
}
4.2 商品展示与搜索
商品列表接口实现要点:
- 分页查询:使用MyBatis-Plus的Page对象
- 多条件筛选:构建动态查询条件
- 排序支持:价格、销量、上架时间等
- 缓存优化:热门商品加入Redis缓存
商品搜索采用Elasticsearch实现全文检索(简化版可用MySQL LIKE):
java复制@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Page<Product> searchProducts(ProductQuery query, Pageable pageable) {
// 构建查询条件
QueryWrapper<Product> wrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(query.getKeyword())) {
wrapper.like("name", query.getKeyword())
.or().like("brand", query.getKeyword());
}
if(query.getCategoryId() != null) {
wrapper.eq("category_id", query.getCategoryId());
}
// 价格区间
if(query.getMinPrice() != null) {
wrapper.ge("price", query.getMinPrice());
}
if(query.getMaxPrice() != null) {
wrapper.le("price", query.getMaxPrice());
}
// 排序
if(StringUtils.isNotBlank(query.getSortBy())) {
if("price_asc".equals(query.getSortBy())) {
wrapper.orderByAsc("price");
} else if("price_desc".equals(query.getSortBy())) {
wrapper.orderByDesc("price");
} else if("sales".equals(query.getSortBy())) {
wrapper.orderByDesc("sales");
}
}
// 分页查询
Page<Product> page = new Page<>(pageable.getPageNumber(), pageable.getPageSize());
return productMapper.selectPage(page, wrapper);
}
}
5. 订单系统实现
5.1 订单状态机设计
订单状态流转是电商系统的核心,我们采用状态模式实现:
code复制待支付 --支付成功--> 待发货 --发货--> 待收货 --确认收货--> 已完成
\ \ \
\--取消订单--> 已取消 \--申请退款--> 退款中 \--申请售后--> 售后中
状态变更关键代码:
java复制public class Order {
private Long id;
private OrderStatus status;
public void pay() {
if(status != OrderStatus.UNPAID) {
throw new IllegalStateException("当前状态不能支付");
}
this.status = OrderStatus.PAID;
}
public void cancel() {
if(status != OrderStatus.UNPAID) {
throw new IllegalStateException("当前状态不能取消");
}
this.status = OrderStatus.CANCELLED;
}
// 其他状态变更方法...
}
public enum OrderStatus {
UNPAID("待支付"),
PAID("已支付"),
SHIPPED("已发货"),
COMPLETED("已完成"),
CANCELLED("已取消"),
REFUNDING("退款中"),
AFTER_SALE("售后中");
private String desc;
OrderStatus(String desc) {
this.desc = desc;
}
}
5.2 库存扣减方案
解决超卖问题的三种方案对比:
- 悲观锁方案:
java复制@Transactional
public boolean deductStock(Long productId, int quantity) {
// SELECT ... FOR UPDATE
Product product = productMapper.selectByIdForUpdate(productId);
if(product.getStock() < quantity) {
return false;
}
product.setStock(product.getStock() - quantity);
productMapper.updateById(product);
return true;
}
- 乐观锁方案:
java复制public boolean deductStock(Long productId, int quantity) {
int rows = productMapper.deductStock(productId, quantity);
return rows > 0;
}
<!-- MyBatis映射文件 -->
<update id="deductStock">
UPDATE product
SET stock = stock - #{quantity},
version = version + 1
WHERE id = #{id} AND stock >= #{quantity}
</update>
- Redis原子操作方案:
java复制public boolean deductStock(Long productId, int quantity) {
String key = "product:stock:" + productId;
long value = redisTemplate.opsForValue().increment(key, -quantity);
if(value >= 0) {
// 异步更新数据库
mqTemplate.send("stock.update",
new StockUpdateMessage(productId, quantity));
return true;
} else {
// 回滚
redisTemplate.opsForValue().increment(key, quantity);
return false;
}
}
提示:对于毕业设计项目,乐观锁方案实现简单且能满足需求。实际高并发场景建议采用Redis+MQ的方案。
6. 部署与运维
6.1 小程序端部署流程
- 在微信公众平台注册小程序账号
- 配置服务器域名(需HTTPS)
- 使用微信开发者工具上传代码
- 提交审核并发布
6.2 后端服务部署
推荐使用Docker Compose部署:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: mall
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
- SPRING_PROFILES_ACTIVE=prod
6.3 性能优化建议
-
前端优化:
- 图片使用CDN加速
- 合理使用小程序分包加载
- 减少setData调用频率
-
后端优化:
- 启用Spring Boot Actuator监控
- 配置合理的线程池参数
- 慢SQL监控与优化
-
数据库优化:
- 配置连接池参数(HikariCP推荐)
- 定期执行ANALYZE TABLE更新统计信息
- 重要表定期优化(OPTIMIZE TABLE)
7. 常见问题与解决方案
7.1 微信登录失败排查
- 错误码40029:检查appid和secret是否正确
- 错误码40163:code已被使用,确保每次登录使用新code
- 获取不到unionid:需要用户授权且小程序已绑定开放平台
7.2 图片上传问题
微信小程序图片上传流程:
- 调用wx.chooseImage选择图片
- 使用wx.uploadFile上传到服务器
- 服务器返回图片URL
常见问题:
- 图片大小限制:建议压缩到1MB以内
- 图片格式问题:统一转换为JPG/PNG
- 上传超时:调整服务器超时时间
7.3 支付功能实现
微信支付接入步骤:
- 申请微信支付商户号
- 配置支付域名和授权目录
- 实现统一下单接口
- 小程序端调用wx.requestPayment
支付回调处理要点:
- 验证签名确保请求来自微信
- 处理重复通知
- 记录完整的通知日志
8. 项目扩展方向
-
营销功能扩展:
- 优惠券系统
- 拼团/秒杀活动
- 积分商城
-
数据分析功能:
- 用户行为分析
- 商品销售统计
- 交易报表生成
-
多端适配:
- H5版本开发
- 微信小程序转其他平台(支付宝、百度等)
- 管理后台使用Vue.js重构
-
微服务改造:
- 按业务拆分服务(用户服务、商品服务、订单服务等)
- 引入Spring Cloud Alibaba生态
- 配置中心与服务发现
在实际开发中,我发现电商系统最关键的三个要素是:可靠的商品管理、稳定的订单流程、灵活的用户体系。这个项目虽然作为毕业设计开发,但按照生产标准实现了核心电商功能,可以作为商业项目的基础框架。