1. 项目概述与设计思路
这个奶茶点餐小程序是我去年指导的一个本科毕业设计项目,采用前后端分离架构实现。核心目标是打造一个轻量级但功能完整的饮品订购系统,既要满足基本的点餐需求,又要考虑实际商用场景中的扩展性。
为什么选择SpringBoot+Vue这个技术栈?从多年开发经验来看,这种组合特别适合学生项目:
- SpringBoot的自动配置特性让学生能快速搭建后端服务,不用花大量时间在XML配置上
- Vue的渐进式特性让前端开发可以按需引入功能,学习曲线相对平缓
- 小程序端用uni-app跨平台方案,一套代码可以同时发布到微信、支付宝等平台
系统设计时重点考虑了三个维度:
- 用户体验:简化点餐流程,将传统五步下单压缩到三步完成
- 商家管理:提供可视化的销售数据看板和库存预警
- 技术实现:采用模块化开发,各层职责清晰分离
2. 技术架构详解
2.1 后端SpringBoot实现
后端采用经典的三层架构:
code复制controller(API入口)
↓
service(业务逻辑)
↓
dao(数据持久层)
几个关键设计点:
- 使用MyBatis-Plus作为ORM框架,它的ActiveRecord模式特别适合快速开发
- 采用JWT进行接口鉴权,避免每次请求都查数据库
- 商品模块使用Redis缓存热点数据,实测QPS提升3倍
数据库表设计示例(商品核心表):
sql复制CREATE TABLE `product` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '商品名称',
`category_id` int NOT NULL COMMENT '分类ID',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`cost` decimal(10,2) DEFAULT NULL COMMENT '成本价',
`stock` int NOT NULL DEFAULT '0' COMMENT '库存',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:1-上架 0-下架',
`sales` int NOT NULL DEFAULT '0' COMMENT '销量',
`image_url` varchar(255) DEFAULT NULL COMMENT '主图URL',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.2 前端Vue实现技巧
前端项目通过Vue CLI搭建,几个值得分享的实现细节:
- 组件化设计:
- 将商品卡片抽离为独立组件
ProductItem.vue - 购物车使用Vuex管理全局状态
- 路由懒加载优化首屏速度
- 性能优化:
javascript复制// 图片懒加载实现
Vue.directive('lazy', {
inserted: (el, binding) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = binding.value
observer.unobserve(el)
}
})
})
observer.observe(el)
}
})
- 移动端适配方案:
- 使用postcss-pxtorem自动转换px为rem
- 配置viewport meta标签
html复制<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
3. 核心功能实现
3.1 购物车模块设计
购物车实现有几个技术难点需要特别注意:
- 数据结构设计:
javascript复制{
items: [
{
id: 1,
name: "珍珠奶茶",
price: 15,
quantity: 2,
specs: ["少糖", "去冰"], // 商品规格
toppings: ["珍珠", "椰果"] // 加料
}
],
total: 30
}
- 本地存储策略:
- 未登录用户:使用localStorage存储
- 已登录用户:同步到服务端
- 关键代码:
javascript复制// 混合存储策略
saveCart() {
if(this.$store.state.user.token) {
// 已登录,调用API保存
api.saveCart(this.cart).then(...)
} else {
// 未登录,存本地
localStorage.setItem('cart', JSON.stringify(this.cart))
}
}
3.2 订单支付流程
支付环节是系统最复杂的部分,我们采用状态机模式管理订单状态:
java复制// 订单状态枚举
public enum OrderStatus {
UNPAID(1, "待支付"),
PAID(2, "已支付"),
MAKING(3, "制作中"),
COMPLETED(4, "已完成"),
CANCELLED(5, "已取消");
// 状态转换校验逻辑
public static boolean canChangeTo(OrderStatus from, OrderStatus to) {
switch(from) {
case UNPAID:
return to == PAID || to == CANCELLED;
case PAID:
return to == MAKING || to == CANCELLED;
// 其他状态转换规则...
}
}
}
支付超时处理方案:
- 创建订单时写入延迟队列
- 30分钟后检查订单状态
- 若仍为未支付状态则自动取消
4. 开发中的坑与解决方案
4.1 跨域问题处理
开发阶段遇到的典型问题及解决方案:
问题现象:
前端请求时报错:Access-Control-Allow-Origin
解决方案:
- 后端配置CORS(生产环境要指定具体域名)
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
- 前端开发环境配置代理(vue.config.js)
javascript复制devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
4.2 微信支付集成
微信小程序支付集成主要步骤:
- 后端统一下单接口实现:
java复制public String createWxPayment(Order order) throws Exception {
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<>();
data.put("body", "奶茶点餐-订单支付");
data.put("out_trade_no", order.getOrderNo());
data.put("total_fee", order.getActualPrice().multiply(new BigDecimal(100)).intValue() + "");
data.put("spbill_create_ip", "123.12.12.123");
data.put("notify_url", "https://yourdomain.com/api/pay/notify");
data.put("trade_type", "JSAPI");
data.put("openid", order.getUser().getWxOpenid());
Map<String, String> resp = wxpay.unifiedOrder(data);
if("SUCCESS".equals(resp.get("return_code"))){
// 二次签名返回给前端
return buildPaymentParams(resp);
}
throw new RuntimeException("微信支付下单失败");
}
- 前端调起支付:
javascript复制wx.requestPayment({
timeStamp: timestamp,
nonceStr: nonceStr,
package: `prepay_id=${prepayId}`,
signType: 'MD5',
paySign: sign,
success(res) {
// 支付成功处理
},
fail(err) {
// 失败处理
}
})
5. 项目部署方案
5.1 后端部署
推荐使用Docker容器化部署:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
启动命令:
bash复制docker build -t milktea-api .
docker run -d -p 8080:8080 \
-e SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/milktea \
-e SPRING_DATASOURCE_USERNAME=root \
-e SPRING_DATASOURCE_PASSWORD=123456 \
--name milktea-api \
milktea-api
5.2 前端部署
Nginx配置示例:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
}
}
性能优化建议:
- 开启gzip压缩
- 配置静态资源缓存
- 启用HTTP/2
6. 扩展功能建议
如果想进一步提升项目质量,可以考虑:
- 管理后台增强:
- 销售数据可视化(使用ECharts)
- 库存预警自动通知(集成短信/邮件)
- 会员积分系统设计
- 小程序端优化:
- 加入购物车动画效果
- 商品分类快速导航
- 历史订单搜索功能
- 技术深度扩展:
- 引入Spring Cloud实现微服务化
- 使用Elasticsearch实现商品搜索
- 采用WebSocket实现订单状态实时推送
这个项目从技术选型到实现都经过精心设计,既保证了毕业设计的学术要求,又具备实际商业价值。在开发过程中,特别要注意小程序审核规范,比如支付功能必须使用企业账号申请,个人开发者账号是无法上线的。