1. 项目概述
"SSM+Vue美食城网站"是一个典型的毕业设计级别全栈项目,采用Java技术栈的SSM框架(Spring+SpringMVC+MyBatis)作为后端,配合前端Vue.js框架实现前后端分离架构。这个项目模拟在线美食订购平台的完整业务流程,包含用户端、商家端和管理员端三个核心模块。
我在指导类似项目时发现,90%的初学者会遇到前后端联调问题。这个项目最大的技术价值在于:它完整演示了如何用最主流的Java+JavaScript技术栈,构建一个具备实际业务价值的Web应用。相比简单的CRUD演示项目,美食城系统涉及更复杂的业务场景,比如订单状态流转、支付模拟、菜品库存管理等真实业务逻辑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型解析
2.1 后端技术栈
SSM框架组合是Java Web开发的经典选择:
- Spring 5.x:控制反转(IoC)和面向切面(AOP)的实现核心
- Spring MVC:基于DispatcherServlet的MVC架构
- MyBatis 3.x:替代Hibernate的轻量级ORM框架
选择SSM而非Spring Boot的考虑:
- 毕业设计需要展示更底层的配置能力
- 手动整合三大框架能更好理解原理
- XML+Annotation混合配置更符合教学需求
关键配置示例:
xml复制<!-- spring-context.xml -->
<context:component-scan base-package="com.foodcity"/>
<aop:aspectj-autoproxy/>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- mybatis-config.xml -->
<typeAliases>
<package name="com.foodcity.entity"/>
</typeAliases>
2.2 前端技术栈
Vue 2.x + Element UI的组合优势:
- Vue CLI:标准化项目脚手架
- Vue Router:实现SPA路由跳转
- Vuex:集中式状态管理
- Axios:处理HTTP请求
- Element UI:提供丰富的PC端组件
注意:Vue 3虽然已发布,但建议毕业设计使用更成熟的Vue 2.x版本,避免遇到兼容性问题
3. 核心功能实现
3.1 数据库设计
典型五表结构设计:
- 用户表(user):用户ID、账号、密码(MD5加密)、手机号
- 商家表(merchant):商家ID、营业执照信息、审核状态
- 菜品表(food):菜品ID、分类、价格、库存、图片URL
- 订单表(order):订单编号、支付状态、配送地址
- 订单明细表(order_detail):关联订单与菜品
sql复制CREATE TABLE `order` (
`id` varchar(32) NOT NULL COMMENT '订单ID',
`user_id` int(11) NOT NULL COMMENT '用户ID',
`total_amount` decimal(10,2) NOT NULL COMMENT '总金额',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态(0未支付1已支付2已取消)',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 前后端交互实现
RESTful API设计规范:
/api/user/loginPOST 用户登录/api/food/listGET 分页查询菜品/api/order/createPOST 创建订单/api/merchant/updatePUT 商家信息更新
跨域解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
}
3.3 典型业务逻辑实现
订单创建流程:
- 前端提交订单数据(JSON格式)
- 后端验证库存(乐观锁方案)
java复制@Transactional
public String createOrder(OrderDTO orderDTO) {
// 检查库存
for (OrderDetail detail : orderDTO.getDetails()) {
Food food = foodMapper.selectById(detail.getFoodId());
if (food.getStock() < detail.getQuantity()) {
throw new BusinessException(food.getName()+"库存不足");
}
}
// 扣减库存
for (OrderDetail detail : orderDTO.getDetails()) {
foodMapper.reduceStock(detail.getFoodId(), detail.getQuantity());
}
// 生成订单
Order order = new Order();
BeanUtils.copyProperties(orderDTO, order);
orderMapper.insert(order);
return order.getId();
}
- 生成订单编号(雪花算法)
- 返回订单创建结果
4. 关键问题解决方案
4.1 图片上传与访问
存储方案选择:
- 开发环境:本地存储(resources/static/upload)
- 生产环境:阿里云OSS
Vue前端实现:
html复制<el-upload
action="/api/upload"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
Java后端处理:
java复制@PostMapping("/upload")
public ResultVO upload(@RequestParam("file") MultipartFile file) {
String fileName = UUID.randomUUID() + file.getOriginalFilename();
File dest = new File(uploadPath + fileName);
file.transferTo(dest);
return ResultVO.success("/upload/" + fileName);
}
4.2 支付功能模拟
由于毕业设计通常不需要真实支付,推荐两种模拟方案:
- 纯前端模拟:
javascript复制// 在Vue组件中
payOrder() {
this.$confirm('确认支付?', '提示').then(() => {
this.loading = true;
setTimeout(() => {
this.$message.success('支付成功');
this.loading = false;
}, 1500);
});
}
- 后端状态变更:
java复制@PostMapping("/pay/{orderId}")
public ResultVO pay(@PathVariable String orderId) {
Order order = orderMapper.selectById(orderId);
if (order.getStatus() != 0) {
return ResultVO.error("订单状态异常");
}
order.setStatus(1);
orderMapper.updateById(order);
return ResultVO.success();
}
5. 项目部署指南
5.1 开发环境搭建
后端环境:
- JDK 1.8+
- Maven 3.6+
- MySQL 5.7+
- Tomcat 8.5+
前端环境:
- Node.js 12+
- Vue CLI 4.x
- npm/yarn
5.2 生产环境部署
后端部署:
bash复制# 打包war文件
mvn clean package -Dmaven.test.skip=true
# 上传到Tomcat webapps目录
scp target/foodcity.war user@server:/usr/local/tomcat/webapps/
前端部署:
bash复制# 生产环境构建
npm run build
# 部署到Nginx
cp -r dist/* /usr/share/nginx/html/
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://localhost:8080;
proxy_set_header Host $host;
}
}
6. 常见问题排查
6.1 跨域问题
现象:前端请求出现CORS policy错误
解决方案:
- 确认后端已添加CORS配置(见3.2节)
- 检查前端axios baseURL配置是否正确
- 开发环境可配置vue.config.js代理:
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
}
6.2 页面刷新404
原因:Vue路由history模式需要服务器配合
解决:
- Nginx添加try_files配置(见5.2节)
- 或改用hash模式:
javascript复制const router = new VueRouter({
mode: 'hash',
routes
});
6.3 MyBatis查询结果为空
排查步骤:
- 检查SQL日志确认语句是否正确
- 验证实体类字段与数据库列名是否匹配
- 检查MyBatis映射文件resultMap配置
- 确认数据库连接参数正确
典型错误示例:
xml复制<!-- 错误:Java属性与数据库列名不一致未指定映射 -->
<select id="selectById" resultType="com.foodcity.entity.Food">
SELECT food_name FROM t_food WHERE id=#{id}
</select>
<!-- 正确方案 -->
<resultMap id="foodMap" type="com.foodcity.entity.Food">
<result property="name" column="food_name"/>
</resultMap>
7. 项目扩展建议
- 引入Redis缓存:缓存热门菜品数据,减轻数据库压力
java复制@Cacheable(value = "food", key = "#id")
public Food getById(Integer id) {
return foodMapper.selectById(id);
}
-
添加Elasticsearch搜索:实现菜品全文检索功能
-
微信小程序端:基于uni-app开发多端应用
-
数据可视化:使用ECharts展示销售数据统计
-
Docker容器化:编写Dockerfile实现一键部署
我在实际开发中发现,订单超时取消是个值得深入的功能点。可以通过Spring的@Scheduled实现:
java复制@Scheduled(cron = "0 0/30 * * * ?")
public void cancelTimeoutOrders() {
List<Order> orders = orderMapper.selectTimeoutOrders();
orders.forEach(order -> {
order.setStatus(2); // 已取消
orderMapper.updateById(order);
// 恢复库存
order.getDetails().forEach(detail -> {
foodMapper.addStock(detail.getFoodId(), detail.getQuantity());
});
});
}
