1. 项目概述
校园外卖服务系统是当前高校信息化建设的重要组成部分。作为一名长期从事校园信息化系统开发的工程师,我发现传统的外卖系统普遍存在几个痛点:前端页面响应迟缓、后端接口混乱、系统扩展困难。这促使我设计了一套基于SpringBoot+Vue的前后端分离架构解决方案。
这个系统最核心的价值在于:通过前后端彻底解耦,实现了开发效率与运行性能的双重提升。前端采用Vue.js构建动态交互界面,后端通过SpringBoot提供稳定的RESTful API服务,两者通过Axios进行数据通信。在实际测试中,这种架构的页面加载速度比传统JSP方案快3倍以上。
2. 技术栈选型解析
2.1 后端技术组合
选择SpringBoot作为后端框架主要基于三个考量:
- 自动配置特性大幅减少了XML配置工作量
- 内嵌Tomcat服务器简化了部署流程
- 丰富的Starter依赖可以快速集成常用组件
数据库操作层选用MyBatis而非JPA的原因是:
- 需要精细控制复杂SQL语句
- 已有数据库Schema需要直接映射
- 动态SQL构建需求较多
java复制// 典型MyBatis Mapper接口示例
@Mapper
public interface OrderMapper {
@Select("SELECT * FROM order_info WHERE user_id = #{userId}")
List<Order> findByUserId(@Param("userId") Long userId);
}
2.2 前端技术方案
Vue.js 2.x版本的选择权衡:
- 比React更轻量级的学习曲线
- 模板语法对前端新手更友好
- 完善的生态系统(Vuex+Vue Router)
- 与Element UI组件库完美兼容
重要提示:实际开发中发现Vue 3.x的Composition API虽然强大,但对团队现有技术栈迁移成本较高,因此暂缓升级。
3. 数据库设计精要
3.1 核心表关系设计
系统采用经典的RBAC(基于角色的访问控制)模型,主要包含6张核心表:
- 用户表(user_info)
- 角色表(role)
- 权限表(permission)
- 菜品表(dish_info)
- 店铺表(shop_info)
- 订单表(order_info)
sql复制-- 建表示例
CREATE TABLE `order_info` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`total_amount` decimal(10,2) NOT NULL,
`status` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`order_id`),
KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 关键字段设计原则
- 金额字段统一使用DECIMAL(10,2)
- 状态字段采用TINYINT而非VARCHAR
- 时间字段精确到毫秒级
- 所有表必须包含create_time和update_time
4. 核心功能实现
4.1 JWT认证流程
- 用户登录成功后生成Token
- 前端存储Token至localStorage
- 每次请求携带Token头部
- 后端通过拦截器验证Token
java复制// JWT生成示例
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
4.2 订单状态机设计
采用状态模式实现订单流转:
code复制待支付 → 已支付 → 商家接单 → 配送中 → 已完成
↘ ↘
取消订单 退款中
5. 性能优化实践
5.1 缓存策略
- 菜品信息使用Redis缓存
- 采用多级缓存架构
- 热点数据预加载机制
java复制@Cacheable(value = "dishes", key = "#shopId")
public List<Dish> getDishesByShop(Long shopId) {
return dishMapper.selectByShopId(shopId);
}
5.2 SQL优化要点
- 为所有查询条件添加索引
- 避免SELECT * 操作
- 复杂查询使用EXPLAIN分析
- 批量操作使用rewriteBatchedStatements
6. 部署方案
6.1 生产环境配置
推荐使用Docker Compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
redis:
image: redis:alpine
backend:
build: ./backend
ports:
- "8080:8080"
frontend:
build: ./frontend
ports:
- "80:80"
6.2 Nginx配置要点
nginx复制server {
listen 80;
location /api {
proxy_pass http://backend:8080;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}
7. 常见问题排查
7.1 跨域问题解决方案
- 后端配置CORS过滤器
- 前端设置withCredentials
- Nginx添加跨域头
java复制@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
7.2 事务失效场景
- 方法非public修饰
- 自调用问题
- 异常类型不匹配
- 数据库引擎不支持
8. 扩展建议
- 接入微信小程序端
- 实现智能推荐算法
- 增加骑手轨迹跟踪
- 开发商家数据分析面板
这个项目从设计到落地历时3个月,最大的收获是:在技术选型时要充分考虑团队现有技术栈的延续性,不能盲目追求新技术。特别是在校园环境下,系统的稳定性和可维护性往往比炫酷的功能更重要。