先说一下背景:我目前刚上大二,计算机相关专业。这个项目是我在大一升大二的暑假做的。在这之前,我学过Java和c基础语法,写过一些控制台小程序,学了一些前端三件套和vue,仅此而已。苍穹外卖是我第一个完整跑通的前后端分离项目。这篇文章记录的是我那个暑假一路摸索的真实过程。
一、为什么暑假要啃这个项目
大一由于还没开设java相关课程,我自己过了一遍Java se基础,但心里一直有个疙瘩:我写的代码全是在IDEA里跑的main方法,从来没有一个能打开浏览器看到页面的东西。
暑假回家前我给自己定了个目标:找一个完整的项目跟着做,不管多难,做出来一个能用的真正体会一下。
选苍穹外卖的原因很实际:B站上播放最多的完整前后端分离项目业务,应该有最完整的资源,不会做不出来。我当时想的是,跟着视频做,总不至于太难吧。
后来证明我还是太年轻了。
二、环境搭建:暑假前三天全耗在这了
- MySQL :之前装过5.7,项目要求8.0。卸载重装,导入
sky.sql的时候又报字符集错误,查了才知道要选utf8mb4 - Redis :Windows下没有官方安装包,下了个解压版。启动命令
redis-server.exe redis.windows.conf每次都要开一个黑窗口挂着,后来才知道可以注册成系统服务 - Nginx :解压后默认80端口,被系统占了,改成8081。然后前端页面能打开,但登录一直报500。查了一整天,最后发现是Nginx的
proxy_pass转发地址写错了 - 前端WebSocket:页面一直弹"服务器错误,无法接收实时报警信息"。那时候我还不懂什么叫反向代理,不知道WebSocket需要单独配转发规则。改了前端JS里的端口、重载了Nginx、清了浏览器缓存,折腾了好几个晚上
那几天我的浏览器历史记录全是CSDN、博客园和Stack Overflow。每解决一个问题就截一张图发朋友圈,现在回头看有点好笑,但当时那种"终于通了"的放松感是真的。
三、技术栈:边做边查,边查边记
这个项目用到的技术比我之前接触过的多了不少。暑假里我专门建了一个笔记文档,每碰到新东西就记一笔:
后端
| 技术 | 版本 | 我当时的理解过程 |
|---|---|---|
| Java | JDK 17 | 从8换到17,发现 var 关键字、switch表达式、Record类这些新特性 |
| SpringBoot | 3.1.2 | 之前只写过纯Java,第一次接触"约定优于配置",@SpringBootApplication 一个注解启动整个项目,很震撼 |
| Spring MVC | 内嵌 | @RestController、@RequestMapping 这些注解一开始死记硬背,后来才理解请求是怎么映射到方法的 |
| MyBatis | 3.x | 之前用JDBC写过连接数据库,但手写SQL拼接太痛苦了。MyBatis的XML映射让我第一次觉得"ORM真香" |
| PageHelper | 5.x | 分页查询不用自己算 LIMIT 的偏移量了,加一行 PageHelper.startPage() 就行 |
| MySQL | 8.0 | 建表、写SQL、事务这些在学校学过,但索引优化、连接池这些完全是现学的 |
| Redis | 7.x | 暑假前只知道"Redis是缓存",做完项目后理解了它还能做分布式锁、消息发布订阅、令牌存储 |
| JWT (jjwt) | 0.11.x | 第一次接触"无状态认证"的概念,之前一直以为登录就是session存服务器 |
| WebSocket | Jakarta API | 第一次写服务端主动推消息给浏览器的功能,理解了HTTP和WebSocket的区别 |
| Knife4j | 4.x | 接口文档自动生成,写完Controller就能在网页上测试,比Postman方便 |
| Lombok | 1.18.x | @Data 一个注解省掉所有getter/setter,当时觉得这是魔法 |
| Jackson | 内嵌 | JSON和Java对象互转,前后端数据交互的桥梁 |
| Apache POI | 5.x | 导出Excel报表,当时照着视频敲,后来自己研究了单元格样式怎么设置 |
| Quartz | 2.x | 定时任务框架,用来自动处理超时订单。cron表达式我背了好久 |
| Nginx | 1.20.2 | 反向代理、负载均衡、静态资源托管,暑假里花了很多时间理解"为什么前端不直接连后端" |
前端
| 技术 | 说明 |
|---|---|
| Vue 2 | 管理端用的框架,暑假前完全没接触过。跟着视频看 data、methods、mounted 这些概念,慢慢能看懂了 |
| Element UI | 组件库,表格、表单、弹窗直接拖。我不用自己写CSS,但得知道怎么改样式 |
| Axios | 前端发HTTP请求用的,拦截器、请求头设置这些跟着视频配的 |
| WebSocket API | 浏览器端接收实时推送,和后端对应 |
| 微信小程序 | C端用户端,WXML和WXSS的语法和HTML/CSS略有不同,暑假里跟着视频过了一遍 |
开发工具
IDEA(写Java)、Navicat(管数据库)、Postman(后来换成Knife4j)、PowerShell(操作Nginx和Redis)、Chrome开发者工具(F12看Network请求,虽然我笔记本按F12会打开计算器,得用Ctrl+Shift+I)
四、项目架构:从"看不懂目录"到"能讲给别人听"
暑假刚开始导入项目的时候,我看着 controller、service、mapper、entity、dto、vo 这些包名完全不知道为什么一个"员工"要搞出这么多类。
后来每写一个模块我就强迫自己画一遍请求链路,画了五六遍之后才真正理解:
请求从浏览器到数据库的完整路径
bash
浏览器 localhost:8081 输入账号密码点登录
│
▼
Nginx (监听8081)
├── 静态资源直接返回(HTML/CSS/JS)
└── /api/* 请求 → proxy_pass 转发到 localhost:8080
│
▼
SpringBoot后端 (8080)
│
┌──────────┼──────────────┐
▼ ▼ ▼
Filter Interceptor Controller
(字符编码) (JWT令牌校验) (接收参数)
│ │
▼ ▼
┌──────────┐ Service层
│ 校验失败 │ (业务逻辑、事务)
│ 返回401 │ │
└──────────┘ ┌───┼───┐
▼ ▼ ▼
Mapper Redis MySQL
(SQL) (缓存) (持久化)
我花了最长时间才搞懂的几个概念
DTO / VO / Entity 为什么要分开:
暑假里我一度觉得这是"过度设计"。后来自己写"新增员工"接口时才发现,前端传过来的参数(用户名、密码、姓名、手机号)和数据库表字段不完全对应,而且有些字段(比如密码)需要加密后再存。用DTO接收前端参数,用Entity映射数据库,中间在Service里转换,逻辑清晰很多。
为什么要有Service层:
刚开始我觉得Controller直接调Mapper就行了,为什么非得加一层Service?后来写"下单"功能时明白了------下单要同时操作订单表、订单明细表、购物车表、菜品库存表,还要发WebSocket通知。这些操作要么全成功要么全失败(@Transactional 事务管理),放在Service层统一管理才合理。
拦截器和过滤器的区别:
Filter是Servlet层面的,Interceptor是Spring层面的。JWT校验放在Interceptor里,因为需要用到Spring的容器(获取RedisTemplate)。这个区别我是踩了坑之后才记住的。
Redis在项目里的三个用途:
- 存JWT令牌黑名单(用户退出登录时把token加进去,拦截器校验时查)
- 存店铺营业状态(0/1,管理端可以切换,用户端查)
- WebSocket的Session管理(记录哪个商家端在线,有新订单时推送给对应的连接)
五、AI在暑假里帮了我什么
暑假做项目的时候,我大部分时间是跟着视频走的。但视频不可能覆盖所有问题,尤其是环境配置和报错排查。那时候我已经开始用AI工具了,说实话帮了不少忙。
帮我读懂报错信息:
IDEA控制台报红的时候,我以前的做法是复制第一行错误去百度搜。后来学会把整段报错贴给AI,它会帮我定位到关键行。比如那个WebSocket 404的问题,AI告诉我"404说明Nginx没把 /ws/ 请求转发到后端",一句话省了我两小时瞎试。
帮我解释概念:
视频里老师讲 @Transactional 的传播行为,一笔带过了。我追着AI问了好几轮:REQUIRED和REQUIRES_NEW到底什么区别、为什么同类方法互相调用事务不生效、什么情况下事务会失效。AI的回答比视频更细,而且我可以随时追问"为什么"。
帮我review自己写的代码:
暑假后期我开始尝试不跟视频、自己写一些接口。写完贴给AI让它帮我看,它指出过几次问题:比如我在Controller里直接调了Mapper没走Service(事务没生效),比如密码字段忘了加密,比如分页查询的 PageHelper.startPage() 放错了位置。
但也有帮不了的地方:
AI不能替我理解"为什么Nginx要配 proxy_set_header Upgrade 才能转发WebSocket"。这个东西我翻了Nginx官方文档、看了好几篇博客才搞明白。AI能给方向,但理解的过程还是得自己来。
六、手写代码还有没有必要
暑假里我确实动摇过。
有一次我让AI直接生成"员工分页查询"的代码,三秒钟出来了,能跑。但我看着那几行 LambdaQueryWrapper 的链式调用,完全不知道它在干什么------因为视频里教的是 PageHelper + XML 的写法。
从那以后我给自己定了个规矩:核心代码必须自己敲,AI用来辅助理解而不是代写。
我的做法是:先看视频理解思路 → 自己关掉视频凭记忆敲 → 卡住了再看一眼 → 敲完之后和视频对比 → 有空的话再让AI生成一版对比学习。
这样虽然慢,但暑假结束时我能不依赖视频,自己从零写一个"分类管理"模块的增删改查,包括Controller、Service、Mapper、XML全套。
我的感受是:手写的意义不在于记住语法,而在于建立"看到需求→想到实现方案→写出代码"这条链路。 AI能帮你跳过中间步骤,但跳过的东西迟早会在调试的时候找回来。
七、暑假结束时的状态
项目做完那天,我截图发了条朋友圈。但说实话,真正让我有成就感的不是"跑通了",而是暑假最后几天我试着自己改了一个小功能------给"菜品管理"加了一个"按分类筛选"的查询条件,从改SQL到改前端请求参数全是我自己搞定的。
那一刻我知道,这个暑假没白费。
八、大二开学后的计划
现在上了大二,课表比大一满了不少。但我还是想保持自学的节奏:
当前:✅ 苍穹外卖(暑假完成)
↓
本学期:SpringCloud Alibaba(Nacos、OpenFeign、Gateway、Sentinel)
↓
并行:MySQL深入(索引原理、Explain执行计划、慢查询优化)
↓
寒假目标:Redis深入(底层数据结构、缓存三大问题、分布式锁实战)
↓
大二下学期:JVM + 并发编程(这是校招面试重点,得认真啃)
↓
最终目标:大三前能独立设计一个中小型系统,从架构到部署全流程自己搞定
九、最后想说的
暑假做这个项目的时候,我妈好几次路过我房间看到我盯着屏幕发呆,问我是不是在打游戏。我说我在debug,她不懂,但那种"明明每一行代码都认识,合在一起就报错"的无力感,估计只有做过项目的人才懂。
如果你也是大一大二的学生,也在自学Java,也想找个完整项目练手,我的建议是:
别怕慢,别怕报错,别怕问AI,但也别让AI替你思考。
每一行你亲手敲出来的代码,都会变成你理解下一个概念的基础。暑假里那些让我头疼的报错,现在回头看都是最值钱的学习经历。
写这篇文章的时候,那个暑假的很多细节又浮上来了。如果你也在做苍穹外卖,或者也在自学路上,评论区可以交流。大二菜鸟互相鼓励,一起进步。