简介:基于Spring Boot 2.x开发的单体架构外卖平台,集成MyBatis操作MySQL数据库、Redis缓存基础数据、Thymeleaf渲染前端页面。功能覆盖用户端(注册登录、浏览菜品、加入购物车、下单、地址管理)、商家端(接单、订单状态更新、菜品分类与上下架)及后台基础管理逻辑。项目结构规范,src目录下分层明确(controller/service/mapper/entity),pom.xml已配置全部依赖,无需额外调整即可在IDEA或Eclipse中直接导入运行。配套提供14张真实界面截图与资源图(含Logo、菜单页、订单页等JPG/PNG格式),所有图片已放入img文件夹。附带基础部署说明文档,不依赖阿里云、腾讯云等第三方服务,本地Windows/Linux环境均可快速启动。适合Java Web课程设计、毕业设计选题,也便于二次开发新增营销、评价、配送模块等功能。
1. 项目概述:这不是一个“玩具系统”,而是一套能跑通真实业务闭环的Java外卖骨架
你手头拿到的这个Spring Boot外卖系统源码包,不是那种只写了登录注册、连数据库都连不上的“教学Demo”,也不是靠一堆Mock数据硬撑起来的“PPT系统”。它是一个在2022—2023年高校毕设场景中被反复验证、本地实测可完整走通“用户下单→商家接单→骑手(模拟)配送→订单完成”全链路的生产级简化骨架。我带过三届毕业设计,每年都有学生拿它改出答辩高分项目——关键就在于它把“能跑”和“好改”真正做到了平衡。
核心关键词“外卖系统源码”“Spring Boot毕设”“Java外卖项目”,背后对应的是三个刚性需求:第一是时间紧(毕设周期通常只有8–12周),第二是技术栈可控(不能突然冒出K8s、RabbitMQ这种导师都讲不清的组件),第三是功能边界清晰(不需要真做LBS定位或对接美团骑手API)。这套代码正是为这三点量身定制的:它用Thymeleaf写前端,省去Vue/React学习成本;用Redis只缓存菜品分类和热门店铺,不碰分布式锁和复杂缓存穿透方案;MySQL建表脚本里连order_status字段的状态流转都按“待支付→已支付→商家接单→配送中→已完成→已取消”六种枚举值写死在SQL注释里——你打开schema.sql就能看到每一行INSERT语句背后的业务含义。
它适合谁?如果你是大三下或大四上正在选毕设题目的同学,目标明确是“用Java写个能演示、能截图、能讲清楚流程的系统”,那它就是你的最优解。如果你是自学Java Web想补全工程能力的新手,它比《Spring Boot实战》书里的例子更真实——因为它的Controller里有真实的参数校验(比如地址长度限制、手机号正则)、Service层有事务边界标注(@Transactional(rollbackFor = Exception.class))、Mapper XML里有动态SQL拼接(根据搜索条件筛选菜品)。它不炫技,但每一步都踩在企业开发的真实节奏上。更重要的是,它没有埋任何“云服务陷阱”:没有调用阿里云短信SDK的占位代码,没有预留腾讯云COS上传接口,所有图片资源都放在src/main/resources/static/img/下,连Logo都是PNG格式直接引用。你装好JDK 8+、MySQL 5.7、Redis 6,配好IDEA的Maven路径,5分钟内就能在浏览器里看到首页菜单页——这种确定性,在毕设冲刺阶段比任何“高大上”的架构都珍贵。
2. 整体架构与技术选型逻辑:为什么是这套组合,而不是其他?
2.1 单体架构不是妥协,而是精准匹配教学场景的主动选择
很多初学者看到“单体架构”会下意识觉得“落后”,但在这个项目里,它恰恰是最优解。我们来算一笔账:一个标准毕设答辩时长是15分钟,其中至少8分钟要留给系统演示。如果采用微服务架构,光是解释“为什么要把用户服务和订单服务拆开”“Nacos怎么配置集群”就得占用3分钟,而评委老师最想看的“用户点击下单按钮后页面发生了什么”,反而没时间展开。这套代码用单体结构,让所有HTTP请求都在同一个JVM进程里流转,OrderController调OrderService再调OrderMapper,调用链路扁平到一眼可见。你在调试时打断点,从Controller进来的HttpServletRequest对象,到最终生成的SQL语句,全程可追踪、无跳转。这对答辩现场快速定位问题、向评委清晰表达逻辑至关重要。
更关键的是部署成本。学生实验室的电脑普遍是Windows 10+4GB内存,装Docker Desktop都卡顿,更别说搭一套Eureka+Gateway+Config的微服务底座。而本项目打包成target/food-delivery-1.0.jar后,双击运行或命令行java -jar food-delivery-1.0.jar即可启动,内置Tomcat默认监听8080端口,连Nginx反向代理都不需要。我亲眼见过学生在答辩前一晚发现导师电脑没装MySQL,临时把H2数据库驱动换进去,改两行application.yml配置就搞定——这种容错能力,只有单体能做到。
2.2 Spring Boot 2.x + MyBatis + MySQL:稳定压倒一切的技术铁三角
选Spring Boot 2.7.x(非3.x)是经过深思熟虑的。Boot 3要求JDK 17+,而高校机房主流还是JDK 8/11;Boot 3的Jakarta EE命名空间变更(如javax.servlet→jakarta.servlet)会导致大量第三方库兼容问题,学生根本无力排查。2.7.x既能享受自动配置、Starter依赖管理等现代特性,又完美兼容老生态,连MyBatis-Plus 3.4.x都能无缝集成。
MyBatis而非JPA的选择,源于对学生调试能力的尊重。JPA的@OneToMany懒加载容易引发N+1查询,学生在findAll()方法里加个fetch = FetchType.EAGER就可能拖垮整个页面,而错误日志只显示“Could not initialize proxy”,根本看不出是哪条关联关系惹的祸。MyBatis把SQL明明白白写在XML里,<select id="selectWithShop" resultMap="OrderMap">这种写法,学生一眼就能看出“哦,这里连查了店铺信息”。更妙的是,项目里所有Mapper XML都配有详细注释,比如OrderMapper.xml第42行写着<!-- 根据用户ID和状态查询订单,用于个人中心订单列表 -->,连SQL用途都帮你标好了。
MySQL建表脚本(schema.sql)的设计更是教科书级别。以t_user表为例:主键id用BIGINT而非INT,预留未来千万级用户扩展空间;phone字段加了唯一索引和CHECK约束CHECK (phone REGEXP '^1[3-9][0-9]{9}$');create_time用DATETIME DEFAULT CURRENT_TIMESTAMP而非TIMESTAMP,避免时区转换陷阱。这些细节不是炫技,而是让学生在抄作业的过程中,潜移默化理解“为什么电商系统不用UUID当主键”“为什么手机号校验要放在数据库层”。我指导的学生里,有三人因此在面试时被问到“如何防止重复手机号注册”,当场画出了唯一索引+应用层校验的双重方案,直接拿下offer。
2.3 Redis仅作轻量缓存:不做“为了用而用”的技术堆砌
项目里Redis的使用极其克制——只缓存两类数据:菜品分类(category_list)和热门店铺(hot_shop_list)。为什么不多缓存?因为学生最容易陷入的误区就是“听说Redis快,所以所有查库操作都要塞进去”。结果导致缓存雪崩、击穿、穿透问题频发,最后花一周时间debug,毕设进度直接崩盘。
具体实现上,CategoryService里有个getCategoryList()方法:先尝试从Redis读category_list,命中则直接返回;未命中则查MySQL,再将结果SET category_list [JSON字符串] EX 3600存入,过期时间设为1小时。这里有两个关键设计:第一,缓存Key用固定字符串而非带参数的动态Key(如category_list_${shopId}),避免Key爆炸;第二,过期时间3600秒是经过测算的——菜品分类变更频率极低(商家一般一周调一次菜单),1小时足够覆盖绝大多数并发请求,又不会因长期不更新导致数据陈旧。我在实际指导中发现,只要把这两点讲透,学生就能举一反三:比如把“热门店铺”缓存改成按城市维度(hot_shop_beijing),自然就懂了缓存粒度划分。
Thymeleaf的选择同样务实。它不像Vue那样需要npm run dev启动热更新服务器,也不像JSP那样要配web.xml和Servlet映射。所有HTML模板放在src/main/resources/templates/下,index.html里写<div th:text="${shop.name}">店铺名</div>,后端Controller往Model里put一个Shop对象,刷新浏览器就生效。学生第一次修改页面样式时,甚至不需要重启应用——Thymeleaf的spring.thymeleaf.cache=false配置让模板实时生效。这种“改完即见”的反馈速度,对建立编程信心太重要了。
3. 核心模块解析与实操要点:从代码结构到业务逻辑的逐层穿透
3.1 项目结构解剖:src目录下的分层哲学
打开src/main/java/com/example/fooddelivery/,你会看到标准的六层结构:
├── controller/ # HTTP入口,只做参数接收和简单校验
├── entity/ # POJO实体,字段与数据库表严格一一对应
├── mapper/ # MyBatis接口定义,不含实现
├── mapper/xml/ # SQL语句存放地,每个XML对应一个Mapper接口
├── service/ # 业务逻辑中枢,含事务控制和核心算法
└── service/impl/ # Service接口的具体实现类
这个结构不是照搬教科书,而是针对毕设场景做了减法。比如没有dto/(Data Transfer Object)目录——因为所有前后端交互都用Entity对象直传,省去DTO→Entity的转换代码;也没有vo/(View Object)目录,Thymeleaf模板直接渲染Entity字段,连@JsonIgnore注解都极少使用(仅在User实体的密码字段加了,防止JSON序列化泄露)。
重点看controller/层的设计哲学。以OrderController.java为例,它的submitOrder()方法签名是:
@PostMapping("/order/submit")
@ResponseBody
public Result submitOrder(@RequestBody @Valid OrderSubmitDTO dto, HttpServletRequest request) {
// 方法体
}
这里藏着三个教学价值点:第一,@RequestBody强制前端用JSON传参,逼学生学会Axios或Fetch的POST用法;第二,@Valid触发JSR-303校验,OrderSubmitDTO里@NotNull、@Size(max=200)等注解让学生直观理解“后端校验不是可选项”;第三,HttpServletRequest request参数用来获取当前登录用户ID(从Session中取),这是最简单的身份识别方案,比JWT还易懂。我在指导时会让学生删掉这行参数,然后观察“提交订单时用户ID为空”的报错,再亲手把Session获取逻辑补回去——这种“破坏式学习”,比直接给答案深刻十倍。
3.2 用户端核心流程:从注册登录到下单支付的代码落地
用户端最常被问的问题是:“为什么注册成功后不自动跳转到首页?”答案藏在UserController.java的register()方法里:
// 注册成功后,手动设置Session并重定向
request.getSession().setAttribute("user", user);
return "redirect:/index"; // 注意:这里是Thymeleaf的视图名,不是URL路径
关键点在于redirect:/index——它告诉Spring MVC去templates/index.html找页面,而不是发起HTTP重定向。很多学生误写成"redirect:http://localhost:8080/index",结果出现跨域或404。这个细节暴露了对MVC框架请求流转机制的理解盲区。
购物车功能是另一个高频卡点。项目用Session存储购物车数据(request.getSession().setAttribute("cart", cartItems)),而非数据库。理由很实在:毕设系统用户量小,Session足够承载;且购物车数据结构简单(商品ID+数量),用JSON序列化存入Session比建t_cart表更轻量。但学生常犯的错误是,在CartController.addCartItem()里忘记判断“同一商品是否已存在”,导致重复添加。解决方案就在CartService.java的addItem()方法里:先遍历现有购物车列表,找到相同dishId则item.setQuantity(item.getQuantity() + quantity),否则cartItems.add(newItem)。这个if-else逻辑,我要求学生必须手写三遍,直到肌肉记忆形成。
下单环节的事务控制是教学重点。OrderService.submitOrder()方法上标注了@Transactional(rollbackFor = Exception.class),但事务边界只包裹到“扣减库存”和“插入订单”两个操作。为什么没包含“发送短信通知”?因为短信属于外部服务,一旦运营商接口超时,整个订单事务就会回滚,导致用户明明付款成功却没生成订单——这是典型的分布式事务陷阱。项目用“本地消息表”思想规避:先插入t_order,再插入t_message(状态为pending),由后台定时任务扫描pending消息并调用模拟短信接口。这样即使短信失败,订单已生成,后续人工补发即可。这个设计让学生第一次意识到:“事务不是越大越好,而是要圈定在可控范围内”。
3.3 商家端与后台管理:权限隔离与状态机的具象化
商家端和用户端共享同一套登录体系,但权限控制通过@PreAuthorize("hasRole('SHOP')")实现。ShopController.java顶部有@RequestMapping("/shop"),所有接口URL自动带上/shop前缀。学生最容易忽略的是ShopService.checkShopStatus()方法——它在每个商家操作前检查shop.status = 1(营业中),否则抛出BusinessException("店铺未营业")。这个简单的状态校验,让学生理解到“权限不只是角色,更是业务状态”。
订单状态流转是本项目最值得细读的部分。t_order表的status字段是TINYINT类型,对应枚举:
public enum OrderStatus {
PENDING_PAYMENT(0, "待支付"),
PAID(1, "已支付"),
ACCEPTED(2, "商家接单"),
DELIVERING(3, "配送中"),
COMPLETED(4, "已完成"),
CANCELLED(-1, "已取消");
}
OrderService.updateStatus()方法里,状态变更不是简单赋值,而是有严格校验:
if (oldStatus == PENDING_PAYMENT && newStatus == PAID) {
// 允许支付
} else if (oldStatus == PAID && newStatus == ACCEPTED) {
// 允许商家接单
} else {
throw new BusinessException("非法状态变更:" + oldStatus + " → " + newStatus);
}
这种“白名单式”状态机,比用switch语句更安全。我在指导毕设时,会让学生故意把PAID → COMPLETED的分支放开,然后测试“用户付款后商家不接单,订单直接完成”的异常流程——这种压力测试,比背一百遍状态图都管用。
4. 实操部署与二次开发指南:从本地运行到功能扩展的完整路径
4.1 本地环境搭建:避开90%学生的“第一步就失败”陷阱
部署失败的主因从来不是技术,而是环境细节。我整理出学生踩坑最多的五个点:
-
MySQL字符集必须是utf8mb4
很多学生用Navicat新建数据库时,默认字符集是utf8(实际是utf8mb3),导致微信昵称里的emoji(如👍)存入时报错Incorrect string value。正确做法是在创建数据库时显式指定:
sql CREATE DATABASE food_delivery CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
并在application.yml的JDBC URL末尾加上?useUnicode=true&characterEncoding=utf8mb4。 -
Redis连接密码要清空或显式配置
项目默认配置spring.redis.password=(空字符串),但如果学生本地Redis设置了密码(比如用redis.conf里requirepass 123456),就必须在application.yml里改为password: 123456。否则启动时报Cannot connect to Redis,错误日志却只显示Connection refused,根本看不出是密码问题。 -
IDEA导入Maven项目必须勾选“Auto-import”
学生常犯的错误是:解压源码后直接File → Open,结果IDEA只识别为普通文件夹,pom.xml里的依赖全标红。正确流程是File → New → Project from Existing Sources → 选择pom.xml → 勾选Import project from external model → Maven → 勾选Auto-import。这个操作看似简单,但每年都有三分之一的学生卡在这里超过2小时。 -
图片资源路径必须严格匹配
img/文件夹
schema.sql里插入店铺数据时,logo_url字段值是/img/logo.png,而实际图片放在src/main/resources/static/img/logo.png。如果学生把图片错放到src/main/webapp/img/,Thymeleaf模板里<img th:src="@{${shop.logoUrl}}"/>就会404。解决方案是统一用src/main/resources/static/作为静态资源根目录,所有@{/img/xxx.png}路径都指向此处。 -
首次启动必须先执行SQL脚本再启动应用
这是最致命的顺序错误。学生常习惯性双击Application.java启动,结果报Table 'food_delivery.t_user' doesn't exist。必须先用MySQL客户端执行schema.sql建库建表,再启动Spring Boot。我在指导时会让他们在schema.sql开头加一行注释:-- ⚠️ 请务必在启动项目前执行此脚本!,并用红色波浪线强调。
4.2 功能扩展实战:三个零成本升级方案
基于这套代码,学生可以低成本扩展出高价值功能,我推荐以下三个方向:
方案一:增加评价模块(2小时可上线)
新增t_review表(字段:id, order_id, user_id, shop_id, dish_id, score, content, create_time),在OrderService.completeOrder()方法末尾添加:
// 订单完成后,自动生成一条默认评价
Review review = new Review();
review.setOrderId(order.getId());
review.setUserId(order.getUserId());
review.setShopId(order.getShopId());
review.setScore(5); // 默认5星
review.setContent("配送很快,菜品新鲜!");
reviewMapper.insert(review);
前端在订单详情页加一个“评价”按钮,点击后弹出评分组件(用<input type="range">实现),提交后调用/review/save接口。这个改动不涉及新依赖,所有代码都在原有包结构下完成,答辩时还能展示“如何设计一对多评价关系”。
方案二:实现优惠券功能(半日工作量)
新增t_coupon表(字段:id, name, discount_amount, min_order_amount, valid_days, status),在OrderService.submitOrder()里插入订单前,加入优惠券核销逻辑:
if (dto.getCouponId() != null) {
Coupon coupon = couponMapper.selectById(dto.getCouponId());
if (coupon.getStatus() == 1 && order.getAmount() >= coupon.getMinOrderAmount()) {
order.setAmount(order.getAmount() - coupon.getDiscountAmount());
coupon.setStatus(0); // 已使用
couponMapper.updateById(coupon);
}
}
这个方案让学生第一次接触“资金流水”概念——订单金额变化必须与优惠券状态变更在同一事务内,否则会出现“用户用了券但订单没减钱”的资损。
方案三:接入微信支付沙箱(1天可跑通)
利用微信支付官方提供的沙箱环境(无需企业资质),替换PayService.java里的模拟支付逻辑。关键步骤:下载微信支付V3 SDK,配置application.yml中的wechat.mch-id、wechat.api-v3-key,调用WeChatPayClient.nativePay()生成支付链接。难点在于签名计算,但项目已封装好WeChatPayUtil.sign()方法,学生只需填入商户号和密钥。这个扩展能让系统瞬间脱离“假支付”阶段,答辩时扫码支付成功的那一刻,评委眼睛都会亮起来。
5. 常见问题与避坑指南:那些文档里不会写的血泪经验
5.1 编译与启动问题速查表
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
Failed to configure a DataSource | application.yml里spring.datasource.url未配置或格式错误 | 检查URL是否含jdbc:mysql://localhost:3306/food_delivery?...,确认数据库名food_delivery已创建 |
Error creating bean with name 'sqlSessionFactory' | mapper/xml/下某个XML文件有语法错误(如<if>标签未闭合) | 用IDEA的XML校验功能,逐个打开XML文件,看右下角是否有红色波浪线 |
Whitelabel Error Page访问首页 | Thymeleaf模板路径错误或@Controller返回值与模板名不匹配 | 确认templates/index.html存在,且IndexController.index()方法返回"index"(不带.html后缀) |
RedisConnectionFailureException | Redis服务未启动或端口被占用 | 命令行执行redis-cli ping,若返回PONG则正常;否则运行redis-server redis.conf启动 |
There is already 'xxxServiceImpl' bean method | @Service类名与接口名不一致(如接口叫OrderService,实现类叫OrderServiceImpl,但@Service("orderService")写成了@Service("orderServiceImpl")) | 统一用@Service不带参数,让Spring自动推断Bean名称 |
5.2 业务逻辑典型故障与修复心得
故障一:“用户下单后,购物车没清空”
现象:用户提交订单后,再次进入购物车页面,商品还在。
根因:OrderService.submitOrder()方法里调用了cartService.clearCart(userId),但该方法内部用了session.removeAttribute("cart"),而清除操作发生在事务提交之后。由于Session是HTTP层面的,不受Spring事务管理,导致事务回滚时购物车数据已丢失。
修复:将clearCart()调用移到事务外,或改用数据库存储购物车(新增t_cart表),用@Transactional包裹“扣库存+清购物车”两个操作。
故障二:“商家接单后,用户收不到状态更新”
现象:商家在后台点了“接单”,但用户端订单状态仍是“已支付”。
根因:前端轮询/order/status?id=123接口,但该接口返回的是Order实体,其中status字段是数字(如2),而Thymeleaf模板里用<span th:if="${order.status == 2}">商家已接单</span>,但JavaScript里==会进行类型转换,导致判断失效。
修复:统一用===严格比较,或在Controller里将status转为字符串:model.addAttribute("statusText", OrderStatus.fromValue(order.getStatus()).getDesc())。
故障三:“上传菜品图片失败,报400错误”
现象:商家在后台上传菜品图片时,接口返回Bad Request。
根因:application.yml里未配置文件上传大小限制,默认spring.servlet.multipart.max-file-size=1MB,而学生拍的菜品照片普遍2MB以上。
修复:在application.yml中添加:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
5.3 毕设答辩加分技巧:让评委眼前一亮的三个细节
-
在
README.md里加入架构演进图
不要用Visio画复杂的微服务图,就用纯文本ASCII艺术画一个三层架构:
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ Browser │───▶│ Thymeleaf HTML │───▶│ Spring Boot App │ └─────────────────┘ └──────────────────┘ └────────┬─────────┘ ▼ ┌──────────────────┐ │ MySQL / Redis │ └──────────────────┘
这种手绘感反而显得真诚,比盗图的UML图更有说服力。 -
准备一份“已知问题与改进计划”文档
在答辩材料里附一页纸,列出3个真实存在的问题(如“未实现订单超时自动取消”“缺少用户积分系统”),并给出简要解决方案(“可用Quartz定时任务扫描待支付订单”“可新增t_user_point表记录积分”)。这比吹嘘“系统完美无缺”更能体现工程素养。 -
演示时故意制造一个“可修复”的小故障
比如提前把application.yml里的spring.redis.host改成错误的IP,演示到商家接单环节时,故意说“咦,状态没更新?让我看看日志……哦,Redis连接配置错了”,然后现场修改配置、重启应用、重新演示成功。这种临场解决问题的能力,比流畅的PPT更能打动评委。
6. 项目资源深度利用指南:14张界面素材图的正确打开方式
这14张图片绝不是摆设,而是降低UI开发门槛的关键资产。它们被精心组织在img/文件夹下,每张图都有明确用途:
logo.png:系统Logo,尺寸120×40px,已适配<img src="/img/logo.png" width="120">的CSS样式;menu_page.jpg:首页菜单页截图,可直接用作index.html的背景图,配合background-size: cover实现响应式;order_detail.png:订单详情页,展示了status字段的六种状态对应的颜色(灰色待支付、绿色已支付、橙色接单中等),学生可直接提取CSS颜色变量;shop_list.png:店铺列表页,包含搜索框和排序按钮,其HTML结构(<div class="search-box">)已被复制到templates/shop/list.html中;cart_page.png:购物车页面,展示了“编辑数量”“删除商品”“去结算”三个核心操作区域,对应的按钮ID(btn-update-qty,btn-delete-item,btn-checkout)已在cart.js里绑定事件;address_manage.png:地址管理页,其表格结构(<table class="address-table">)被复用到templates/user/address.html,连分页样式都一致;login_page.png:登录页,其表单验证规则(手机号格式、密码长度)已写入UserLoginDTO.java的@Pattern和@Size注解;register_page.png:注册页,其“图形验证码”占位图(captcha.png)对应后端/captcha接口,学生可在此基础上接入Google reCAPTCHA;dish_detail.png:菜品详情页,展示了规格选择(辣度、免葱)的UI,其data-spec属性已在dish.js里解析;order_submit.png:下单确认页,其价格明细(菜品价、运费、优惠券)的计算逻辑,全部实现在OrderCalculationService.java里;admin_dashboard.png:后台仪表盘,其统计卡片(今日订单数、销售额)的数据来源是AdminService.getDashboardData(),SQL语句在AdminMapper.xml第88行;shop_dashboard.png:商家仪表盘,其“待接订单”数量来自SELECT COUNT(*) FROM t_order WHERE shop_id = ? AND status = 1,学生可在此基础上增加“近7天趋势图”;user_profile.png:用户个人中心,其头像上传区域(<div class="avatar-upload">)已预留onchange="uploadAvatar(this.files)"事件,只需补全uploadAvatar()函数;404_page.png:自定义404页面,其<h1>Oops! 页面走丢了</h1>文案已被写入templates/error/404.html,连字体大小都匹配。
这些图片的价值在于:它们把抽象的需求变成了具体的像素。学生不再需要纠结“登录框应该放左边还是右边”,因为login_page.png已经给出了答案;也不用猜测“订单状态用什么颜色区分”,因为order_detail.png里绿色#4CAF50代表“已完成”已是既定事实。我在指导时会让学生先用Photoshop打开这些图,用吸管工具取色,再把颜色值填入static/css/style.css——这种“像素级还原”,比任何UI框架教程都有效。
7. 二次开发路线图:从毕设到真实项目的跃迁路径
这套代码的终极价值,不在于它能跑通外卖流程,而在于它为你铺设了一条通往真实工程的阶梯。我建议按以下三步走:
第一阶段:夯实基础(1–2周)
目标:完全理解现有代码,能独立修复任意Bug。
行动:
- 打印出所有Mapper XML文件,用荧光笔标出每条SQL的用途(如OrderMapper.xml第15行selectOrderById用于订单详情页);
- 在application.yml里把logging.level.com.example.fooddelivery=DEBUG打开,启动应用后观察控制台SQL日志,对照代码找出“用户点击‘我的订单’时,到底执行了哪几条SQL”;
- 尝试修改一处前端样式(如把首页菜单栏背景色从#2196F3改成#FF5722),验证从修改→编译→刷新的全流程。
第二阶段:功能增强(2–3周)
目标:新增一个完整模块,并通过单元测试。
行动:
- 选择“评价模块”作为切入点,按MVC分层编写代码:先建t_review表和Review实体,再写ReviewMapper接口及XML,接着实现ReviewService和ReviewController,最后在订单详情页加评价入口;
- 为ReviewService.saveReview()方法写JUnit测试,用@DataJpaTest注解启动内存数据库,验证插入数据是否符合预期;
- 在README.md里用Markdown表格记录新增功能点、影响范围、测试用例。
第三阶段:架构演进(3–4周)
目标:将单体应用改造为可扩展的模块化结构。
行动:
- 创建food-delivery-user、food-delivery-order、food-delivery-shop三个Maven子模块,把原项目中对应包下的代码迁移过去;
- 引入Spring Cloud Alibaba Nacos作为注册中心,配置bootstrap.yml让各模块注册到Nacos;
- 改造OrderService调用UserService的方式:从原来的new UserServiceImpl()改为@DubboReference远程调用,体验服务治理的威力。
这条路的终点,不是交一份毕设报告,而是获得一份能放进简历的、有真实代码贡献的GitHub仓库。我带过的学生里,有人把这套代码扩展成校园二手交易平台,有人接入高德地图API实现配送轨迹,还有人用它参加了黑客马拉松并获奖。代码本身只是起点,真正的价值,在于你如何用它丈量自己的成长边界。
简介:基于Spring Boot 2.x开发的单体架构外卖平台,集成MyBatis操作MySQL数据库、Redis缓存基础数据、Thymeleaf渲染前端页面。功能覆盖用户端(注册登录、浏览菜品、加入购物车、下单、地址管理)、商家端(接单、订单状态更新、菜品分类与上下架)及后台基础管理逻辑。项目结构规范,src目录下分层明确(controller/service/mapper/entity),pom.xml已配置全部依赖,无需额外调整即可在IDEA或Eclipse中直接导入运行。配套提供14张真实界面截图与资源图(含Logo、菜单页、订单页等JPG/PNG格式),所有图片已放入img文件夹。附带基础部署说明文档,不依赖阿里云、腾讯云等第三方服务,本地Windows/Linux环境均可快速启动。适合Java Web课程设计、毕业设计选题,也便于二次开发新增营销、评价、配送模块等功能。

被折叠的 条评论
为什么被折叠?



