ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SpringBoot+Vue宠物商城毕设全链路实战:从数据库设计到部署答辩

SpringBoot+Vue宠物商城毕设全链路实战:从数据库设计到部署答辩 每年到这个节点总会有一批人为毕业设计挠头。尤其是Java Web方向如果你正在犹豫这个SpringBootVue宠物商城项目到底能不能选、值不值得投入时间我可以直接给结论这套组合是目前Java Web毕设里性价比相当高的选题方向。它能把后端框架、前端工程化、数据库设计、接口规范、部署上线全链路都覆盖到无论你是想拿高分还是单纯想学点真东西都有足够的发挥空间。这个项目的核心技术栈是SpringBoot做后端接口、Vue做前端页面、MySQL存数据外加SQL脚本和接口文档这几个交付物。它对应的是一个完整的电商业务闭环用户注册登录、商品浏览搜索、购物车管理、下单结算、订单状态流转、后台商品管理。换句话说你不需要刻意堆砌技术只要把这一条链路跑通就已经超过了大多数只做了CRUD展示的毕设。这篇文章我会从技术选型、数据库设计、后端核心实现、前端工程化、接口文档规范、部署演示再到最后的答辩准备把整个项目从0到1的完整思路拆开来讲。里面包含我自己在做类似项目时踩过的坑和沉淀下来的经验希望能帮你少走一些弯路。1. 技术选型背后为什么这套组合能成为毕设万金油1.1 从SSM到SpringBoot省掉的不只是配置很多教科书和学校课程还在讲SSM框架SpringSpringMVCMyBatis但实际就业市场和毕设评审眼中SpringBoot已经成了事实上的主流。SpringBoot解决的核心痛点是SSM时代繁琐的XML配置——数据源、事务管理、视图解析器、组件扫描每一块都要手动配置光是让项目跑起来就能劝退一堆人。SpringBoot通过自动装配机制把这些默认配置全部封装好。当你引入spring-boot-starter-web依赖SpringBoot会自动帮你在内嵌的Tomcat上启动一个Web应用引入spring-boot-starter-jdbc或相关的数据源starter数据源连接池也会自动配置好。你只需要在application.yml里写上数据库地址、用户名、密码就行了。这种约定大于配置的设计理念让你可以跳过繁琐的环境搭建直接进入业务代码编写。这里顺带提一嘴答辩时老师大概率会问SpringBoot自动装配原理是什么。你得能说清楚三件事SpringBootApplication是一个组合注解其中EnableAutoConfiguration是核心它通过AutoConfigurationImportSelector去读取META-INF/spring.factoriesSpringBoot 2.7开始改为AutoConfiguration.imports文件中的自动配置类列表每个自动配置类配合ConditionalOnClass、ConditionalOnMissingBean这些条件注解只在满足条件时才真正生效。把这个讲明白了比背十条八股强得多。1.2 前端为什么选Vue而不是其他框架毕设的前端选择很多人纠结React、Vue还是Angular。从项目落地的角度Vue是更适合个人毕设的选择原因有三点。第一Vue的上手曲线比React更平缓模板语法接近HTML中文资料和教程极其丰富第二Vue的配套生态Vue Router、Vuex/Pinia、Element UI/Element Plus对中后台管理系统和电商前台的支持非常成熟你几乎不需要造任何轮子第三Vue单文件组件的组织形式天然适合这种页面多但逻辑不算太复杂的中小型项目。具体到这个宠物商城前台需要商品列表、商品详情、购物车、订单中心这些用户端页面后台需要商品管理、订单管理、用户管理等管理端页面。用Vue Router做路由管理、Vuex做登录状态和购物车数量的全局管理、Axios做接口请求组件化拆分页面结构会非常清晰。前端代码的组织方式我建议按模块划分而非按页面堆积这一点后文会详细展开。1.3 版本选择springboot版本太高带来的那些坑这是我最想提醒你的一点。打开Spring Initializr最新版本SpringBoot 3.x直接映入眼帘但这不代表你应该选它。SpringBoot 3.0起强制要求JDK 17以上同时把javax.servlet命名空间迁移到了jakarta.servlet许多古老的教程和代码片段全部失效。而且部分依赖比如某些版本的MyBatis-Plus插件对SpringBoot 3的适配并不稳定出了问题你在网上搜到的90%解决方案都是针对2.x的。毕设场景下的稳妥组合是JDK 8 SpringBoot 2.7.x MyBatis-Plus 3.5.x MySQL 8.0。这套组合经过了大量项目验证教程多、报错少、资料全。如果你确实想用SpringBoot 3.x展示自己跟上了技术趋势那就要做好自己解决兼容性问题的准备比如必须用MyBatis-Plus 3.5.3以上的版本且JDK至少要配到17。Vue的版本也一样Vue 2 Element UI依然稳定Vue 3 Element Plus是新方向。如果你对Vue 2已经比较熟悉、目标只是顺利毕业选Vue 2没有问题如果时间充裕且想为找工作打基础Vue 3是更好的投资。前端框架的选择不影响后端接口设计两者通过HTTP协议交互这一点在毕设答辩时也可以作为前后端分离架构的论证点。2. 数据库设计SQL脚本里的门道2.1 核心表结构拆分逻辑宠物商城的数据库设计不需要很复杂但表的拆分要与业务边界吻合。我在项目中采用了七张核心表各自的职责非常清晰表名核心作用关键字段t_user用户账号与登录信息id, username, password, nickname, phone, avatar, create_timet_category商品分类id, category_name, sort_ordert_product商品信息id, category_id, product_name, main_image, price, stock, sales, statust_cart购物车id, user_id, product_id, quantity, create_timet_address收货地址id, user_id, receiver_name, receiver_phone, detail_address, is_defaultt_order订单主表id, order_no, user_id, total_price, status, address_id, create_timet_order_item订单明细id, order_id, product_id, product_name, product_image, price, quantity这个拆分的核心逻辑是购物车和订单虽然都涉及商品但它们本质上是不同的业务状态。购物车是用户临时想买但还没结算订单是用户已经提交购买意向的正式凭证。订单如果再拆分出主表和明细表是为了满足一个订单包含多个商品的情况。后续如果管理员要按订单维度查总价、按商品维度查销量统计这种设计都能撑住。商品分类单独建一张表而不是直接给商品加一个category字段是为了后续扩展方便。比如你想做一个宠物分类导航或者按销量统计某个分类下所有商品的销售情况有单独的分类表会方便得多。分类表里的sort_order字段用于控制前台导航的展示顺序这个字段虽小但会让前端实现简单很多。2.2 字段设计的几个容易忽略的细节第一金额字段必须用DECIMAL而不是FLOAT或DOUBLE。浮点数在计算机底层是二进制表示的计算0.10.2会出现精度丢失。电商涉及钱一分钱都不能差。DECIMAL(10,2)既能满足常规商品价格范围又保留了两位小数精度。这个细节如果答辩时被问到金额为什么不用double你能答出精度问题是很加分的。第二状态字段用TINYINT配合注释使用。订单状态我用了0、1、2、3、4分别表示待付款、待发货、待收货、已完成、已取消。存储上只是一个很小的整数但一定要在SQL注释或接口文档里写清楚状态枚举的含义。如果不写注释过两个星期你自己都分不清1和2谁先谁后。前端Switch开关绑定的时候也直接对应这些状态值。第三时间字段统一用datetime。创建时间、支付时间、发货时间各司其职别图省事只在订单表留一个create_time。订单生命周期里的关键时间节点是电商系统的标准动作也方便你写超时未支付自动取消这类定时任务时做时间判断。第四密码字段长度留够并加密存储。MD5加密后的字符串长度为32位所以密码字段最少设置varchar(64)。我在实际项目中还对MD5做了加盐处理防止用户使用简单密码被反查。这个属于安全加分项毕设阶段做了能体现你对最基本安全的认知。2.3 索引与初始化数据别把所有数据都往SQL里塞SQL脚本里除了建表语句还应该包含必要的初始化数据比如管理员账号、商品分类、几个示例商品。但很多同学会把几十上百条商品数据全部写在INSERT语句里这其实没必要。SQL脚本的价值在于让评审老师快速了解表结构和基本数据形态海量数据完全可以后续通过管理后台添加。索引设计上关注两个高频查询即可商品列表页会按category_id筛选所以给t_product.category_id加一个普通索引订单查询按user_id和order_no查询这两个字段也要索引。order_no订单号同时是业务上的唯一标识直接建唯一索引从数据库层面防重复。建表SQL脚本里我建议加一段DROP TABLE IF EXISTS开头保证脚本可以重复执行。数据初始化时管理员密码用加密后的值不要放明文这是评审老师很容易注意到的一个细节。3. 后端核心实现认证、权限和业务闭环3.1 JWT无状态登录在宠物商城里的落地姿势宠物商城涉及用户登录、购物车、订单这些私有业务所以登录认证是必须的。这里我选择JWT方案而不是传统的Session。原因是前后端分离架构下前端可能部署在一台服务器后端接口在另一台服务器Session的跨域共享会非常麻烦。使用JWT用户ID和过期时间被签名放进token里后端不需要存储登录状态天然适合这种分布式场景。集成JWT的步骤很清晰引入jjwt依赖写一个JwtUtil工具类负责生成token和解析token。用户登录成功后用用户ID和用户名生成token过期时间我设置为7天这样用户一段时间内不用重复登录。响应给前端的结构就是{ token: xxx, userInfo: { id: 1, username: admin } }。关键点在拦截器部分。我定义了一个JwtInterceptor实现HandlerInterceptor在preHandle方法里从请求头Authorization中取出token进行校验。这个拦截器在WebMvcConfigurer里注册addPathPatterns指定拦截所有接口excludePathPatterns放行登录、注册、商品列表这些无需认证的接口。购物车相关接口和订单相关接口全部要求登录否则返回401提示未登录或token已过期。注意JWT的token一旦签发在过期之前是没法主动作废的。所以如果要做退出登录功能前端直接丢弃token即可这是JWT方案的通用处理方式。如果你想做更严格的登出需要引入Redis记录黑名单但对于毕设而言前端丢弃token已经够用。3.2 拦截器与统一返回结果前后端约定的基础前后端分离项目里接口返回的数据结构一定要统一。我在项目中封装了统一的Result类结构如下public class ResultT { private Integer code; // 200成功 | 401未登录 | 500业务异常 private String message; // 提示信息 private T data; // 实际数据 private Long timestamp; // 时间戳 }所有Controller的方法都返回Result类型。用户登录成功返回Result.success(data)参数校验失败返回Result.error(用户名不能为空)系统异常返回Result.error(服务器开小差了)。前端axios拦截器统一判断code字段200直接取data401跳登录页其他code弹出message提示。配合这个统一返回结构我又加了一个全局异常处理器RestControllerAdvice。Controller层不需要手动写try-catch业务代码抛出自定义的业务异常全局异常处理器统一捕获并转换为Result.error返回。这样Controller层会非常干净只负责接收参数和调用service真正的判断逻辑全在service层。3.3 MyBatis-Plus组合条件查询商品搜索不用手写XML持久层框架我选的是MyBatis-Plus它比原生MyBatis省掉了大量XML文件的书写。尤其在做商品列表的分页和条件查询时MyBatis-Plus的LambdaQueryWrapper非常方便。商品列表页通常有分类筛选、关键词搜索、价格排序、分页这几个需求用代码写起来思路非常直接LambdaQueryWrapperProduct wrapper new LambdaQueryWrapper(); wrapper.eq(productId ! null, Product::getCategoryId, productId) .like(StringUtils.isNotBlank(keyword), Product::getProductName, keyword) .orderByDesc(Product::getSales); // 按销量排序 PageProduct page new Page(current, size); productMapper.selectPage(page, wrapper);这里的精妙之处在于条件为false时对应的SQL条件自动拼接不上前端没有传分类ID就不会有category_id的过滤没有传关键词就不会有LIKE查询。整段逻辑不需要if判断语义清晰还不会拼接出错。在商品管理后台的模糊搜索、订单管理后台的状态筛选里这套写法同样适用。当然完全不用手写XML也不现实。像订单报表里统计每天新增订单数最受欢迎的商品TOP10这类多表联查或聚合查询用MyBatis-Plus的Wrapper表达起来还是别扭。这种情况我再建立对应的Mapper接口方法写对应的XMLSQL。简单查询用MyBatis-Plus复杂查询走XML两条腿走路代码既不冗余性能也不妥协。3.4 购物车与订单事务是底线购物车逻辑的核心是购物车表与商品表的联动。加入购物车时去商品表查出当前价格存入购物车记录这样可以保证用户加购时的价格快照修改数量时要校验商品库存是否足够删除购物车记录时同时考虑是否同步修改用户购物车数量的前端状态。订单的下单流程是整个后端里最需要谨慎的部分。用户从购物车勾选商品点击结算时后端要做这几件事校验商品是否还在售、校验库存是否充足、计算订单总金额以数据库实时查询的商品价格为准、生成订单号、插入订单主表和订单明细表、清空已购买的购物车记录、扣减商品库存。这几个操作涉及多张表的修改任何一个步骤失败前面已经执行的写操作都会导致数据不一致所以必须放在一个事务里。我用Transactional注解加到service方法上配合Spring事务管理保证整个下单流程要么全部成功要么全部回滚。事务提交后前端跳转订单列表就能看到新订单。这个事务的讲解在答辩时也是业务严谨性的体现。数据库中订单状态从待付款流转到待发货通常在管理员后台点击发货完成这个状态流转更新时也要加一个状态校验防止状态跳跃更新产生脏数据。4. 前端工程化Vue侧的关键细节4.1 项目初始化与目录划分按模块组织别按角色堆页面前端我用Vue CLI创建项目选择Vue Router和Vuex。项目目录我刻意按模块划分而不是简单地按页面堆积。一个比较合理的目录结构是这样的src/ ├── api/ # 接口请求模块按业务域拆文件 │ ├── product.js │ ├── user.js │ └── order.js ├── assets/ # 静态资源 ├── components/ # 公共组件Header、Footer、商品卡片等 ├── router/ # 路由配置 ├── store/ # Vuex状态管理 ├── utils/ # 工具函数axios封装、日期格式化等 ├── views/ # 页面组件 │ ├── home/ # 商城前台页面 │ └── admin/ # 管理后台页面 └── App.vueapi目录单独抽出来的好处非常明显页面组件里不直接写axios.get这种裸请求而是统一引入api模块的函数。比如商品列表页调用getProductList(params)开发者不必关心内部URL是什么接口一变只需改api目录下的一个文件。这个习惯在你后续做任何前端项目时都会用到。4.2 axios封装与路由守卫一次配置全程受用axios封装是前端工程化的基础。我在utils/request.js里创建了一个axios实例设置baseURL为后端接口地址然后在请求拦截器里从localStorage取出token并加到请求头service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config })响应拦截器里则统一处理后端的Result结构。当code为200时直接返回response.data.data页面拿到的直接是业务数据少一层解构。当code为401时清除本地token并跳转到登录页。当其他错误时用Element UI的Message组件弹出后端返回的message提示。这样每个页面请求数据时只需要处理成功逻辑错误提示全部走统一拦截。路由守卫配合axios拦截器组成了完整的导航控制。我在路由配置里给需要登录才能访问的路由加meta: { requiresAuth: true }然后在全局前置守卫里判断router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) } else { next() } })这样没登录的用户访问购物车、个人中心、订单页面时会被自动踢到登录页。登录成功后跳回原来想访问的页面前后端权限控制的闭环就形成了。4.3 商品列表、详情与购物车的组件化思路前端页面的实现层面商品列表、商品详情、购物车这三个模块最值得讲。商品列表页采用栅格布局el-card包裹每个商品卡片商品卡片抽成一个名为ProductCard的组件接收product对象为prop点击跳转详情页。分类筛选通过侧边栏或顶部分类导航触发接口重新请求分页用el-pagination组件。这里要注意的是商品图片建议统一使用外部图片链接或上传到服务器后的访问路径不要放本地相对路径否则打包部署后很容易出现图片404。商品详情页主要展示大图、价格、库存、销量和商品描述。加入购物车的交互我做了数量选择器和加入购物车按钮。这里有个细节点击加入购物车后要同步调用后端的购物车接口并更新Vuex里的购物车数量让Header右上角的购物车角标实时变化。这个跨页面的状态同步如果不走Vuex只靠组件本地变量每次刷新都会丢失。购物车页面的数据是表格形式每一行展示商品图片、名称、单价、数量、小计。数量修改我用el-input-number组件监听change事件调用后端更新接口同时重算总价。总价字段在前端是计算属性依赖所有购物车记录的小计数据更新后页面自动刷新。全选、单选、删除这些常规功能都用el-checkbox组件配合计算属性实现。4.4 打包后布局异常静态资源路径与路由mode的配合前端开发完要npm run build生成静态文件这一步是毕设演示前最容易翻车的地方。最常见的症状是本地开发一切正常打包后页面白屏或者CSS样式丢失。这大概率是publicPath配置的问题。vue.config.js里publicPath如果默认为/打包后index.html引入的JS和CSS路径是绝对路径。如果你把dist文件夹部署在服务器根目录没问题但如果部署在Tomcat的webapps下的某个子路径或nginx的某个子目录中资源就会404。我的建议是构建时把publicPath设为./这样资源路径是相对路径放到任何子目录都能访问module.exports { publicPath: ./, devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }另一个常见问题是Vue Router使用history模式时打包部署后刷新页面出现404。原因是history模式下的路由是前端模拟的服务器上没有对应的真实文件刷新时服务器收到一个前端路由路径自然找不到资源。解决办法是nginx里配置try_files $uri $uri/ /index.html;把所有不存在的请求都回退到index.html让前端路由接管。如果不想在答辩时折腾服务器配置直接把路由mode改成hash模式URL带#号刷新不会出问题作为降级方案非常实用。5. 接口文档与联调效率毕设答辩的隐藏加分项5.1 接口规范统一返回结构 RESTful URL项目交付物里包含接口文档这个要求本身就是加分项。很多毕设项目代码能跑但接口文档缺失评审老师根本不知道你有什么接口、每个接口怎么调。而你有了接口文档相当于主动告诉老师我的项目是经过规范设计的前后端分离项目。接口URL设计上遵循RESTful风格把资源当作名词、HTTP方法当作动词方法URL功能POST/api/user/login用户登录POST/api/user/register用户注册GET/api/product/page商品分页查询GET/api/product/{id}商品详情POST/api/cart/add加入购物车GET/api/cart/list购物车列表POST/api/order/create创建订单GET/api/order/myOrders当前用户的订单GET/api/admin/product/page后台商品分页PUT/api/admin/product/status上下架商品所有参数和响应示例在文档里写清楚尤其是请求参数的字段名、类型、是否必填。前端就按照这个文档去联调后端也以这个文档为准实现。开发过程中如果字段有调整第一时间更新文档不要口头沟通后文档就放在那儿不管了。5.2 接口文档工具选择与维护技巧做接口文档的方式有很多种组合。可以用Swagger注解自动生成在线接口文档也可以使用Apifox这类工具在工具里手工维护接口再生成分享链接。毕设场景我比较推荐Apifox原因是它同时充当了API调试工具支持环境管理、接口导入导出调试时传入参数直接发送请求能很方便地验证接口。接口文档里的每个接口至少包含以下内容接口地址和请求方法请求参数列表字段名、类型、是否必填、说明请求示例JSON格式响应示例含code、message、data完整结构异常情况说明如未登录返回401参数错误返回500这份文档不仅答辩时要给老师看你自己在开发后期会频繁查阅。接口多起来后记不住每个字段的命名文档就是你的记忆外挂。5.3 联调阶段最容易出现的几类问题前端和后端联调时最头疼的问题一共就几类。第一是跨域问题前端跑在localhost:8081后端在localhost:8080浏览器跨域拦截请求。解决方式一是后端写CrossOrigin或CORS全局配置二是我上面提到的前端devServer代理。后端CORS配置我放在了项目里代理方式只在开发环境用线上部署统一走nginx反向代理。第二是参数名对不上。前端传的字段名是userId后端实体类是user_id接口直接报参数缺失。这个在MyBatis-Plus里如果开启了下划线转驼峰映射user_id能正确对应userId但前端传参时仍然要严格按后端定义的字段名来。所以我建议接口文档里把字段名写得非常明确两边以文档为基准对齐。第三是时间格式不一致。后端返回的LocalDateTime默认序列化成2024-05-20T12:30:00这种带T的格式前端如果不处理显示会很难看。我统一在后端配置了Jackson的日期格式输出yyyy-MM-dd HH:mm:ss的格式。这个不起眼的配置能让订单列表前端少写很多解析代码。6. 部署与演示别在答辩现场翻车6.1 本地打包与运行完整流程但别踩坑答辩前一天才发现项目跑不起来这是最惨痛的教训。它往往不是代码问题而是运行环境不一致。我建议你在答辩前至少完整走一遍这个流程后端部分IDEA右侧Maven面板点击package执行mvn clean package -DskipTests打包成可运行的jar包。这里有个常见坑JDK版本不匹配会导致打包失败。我项目里强制使用JDK 8pom.xml里也配置了java.version为1.8如果本地装的JDK 17最好先切换回来再打包。打包成功后命令行执行java -jar target/pet-shop.jar能正常启动且日志没有红色报错就说明后端没问题。前端部分执行npm run build生成dist文件夹这个文件夹就是所有前端静态文件的集合。你可以用nginx托管也可以直接把dist内容放到Tomcat的webapps/ROOT目录下。放到Tomcat时注意我之前讲的publicPath: ./配置否则资源路径全指向根目录会白屏。6.2 前后端分离架构下的nginx配置毕设项目如果在答辩现场直接本机运行跨域问题可以通过后端CORS配置解决。但如果想演示得更专业一些用nginx做反向代理是个好选择。一个精简的nginx配置如下server { listen 80; server_name localhost; # 前端静态资源 root /opt/pet-shop/dist; index index.html; # 解决history路由刷新404 location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这套配置的含义很直观用户访问根路径时nginx返回前端dist目录的index.html凡是URL带/api/前缀的请求nginx统一转发到后端的8080端口。前端axios的baseURL设为/api请求就会走同源路径不会触发浏览器跨域。部署完成后只需要把后端jar包跑起来再启动nginx整个项目就能通过一个端口对外提供服务。如果你不熟悉nginx也没关系直接用后端CORS跨域配置加前端打包后的dist静态文件双击index.html打开也能演示只是刷新路由的场景会受限。核心是保证答辩时演示流程顺畅nginx是加分的进阶方案。6.3 答辩演示的操作顺序与数据准备答辩演示环节是非常讲究顺序的。我的建议是先把数据库导入并启动后端再启动前端浏览器打开首页按用户视角来走一遍完整流程。具体大概是首页看到宠物商品列表 - 点击某个商品进入详情页 - 加入购物车 - 去结算此时未登录会跳登录页- 注册一个测试账号 - 登录后下单 - 在个人中心看到订单 - 切换管理员账号 - 后台看到新订单并发货 - 回到用户视角看到订单状态变化。这个流程走完系统的主要功能点全部覆盖到了。有几个预防翻车的细节第一提前用测试账号登录一遍确保token没过期第二商品库存设置充足不要在演示时出现库存不足的尴尬第三网络不稳定时图片加载可能很慢建议用本机图片或者加载快的图床链接第四关闭浏览器自动翻译插件避免页面样式错乱。数据的准备也提前做好。商品分类建议覆盖猫、狗、水族、小宠几类每个分类下两到三个商品图片和描述搭配好。再准备一个新注册的测试账号和一个有历史订单的管理员账号这样在展示订单中心时不会空白。7. 答辨证词背后的底层逻辑面试也会问到这些7.1 项目的难点和亮点应该怎么说很多同学答辩时只会说我这个项目有登录、有购物车、能下单这属于描述功能不是描述亮点。亮点要从技术维度提炼我给这个项目总结了三个能打的点。第一个亮点是前后端分离架构下的统一认证方案。我用的JWT无状态认证前端路由守卫拦截未登录用户、axios请求拦截器统一携带token、后端拦截器校验token权限这一整套闭环设计是电商类项目的通用框架。讲到这个点的时候顺带说一句Session方案在跨域场景下需要处理Cookie的跨域写入所以选了JWT就能体现你做过对比分析。第二个亮点是接口规范管理。统一返回结构、统一异常处理、接口文档完善这让前后端联调的效率大幅提升。尤其全局异常处理器我描述了后端自己抛出业务异常的场景比如下单时库存不足直接抛出异常全局处理器统一转成带提示信息的错误结果很能体现工程化思维。第三个亮点是数据库设计的合理性和事务的严谨性。订单主表和明细表分离、金额用DECIMAL存储、下单使用了事务保证数据一致性这三个点各一句话就能讲清楚但能证明你不是只会写CRUD而是考虑了业务的一致性和边界情况。7.2 高频追问的应对思路准备好亮点之后还要预判一些你可能答不上来的追问。我根据自己的经验把最容易碰到的几个问题整理如下。问JWT的token被别人盗了怎么办答token在有效期内的确是没法主动作废的这是JWT方案的一个固有特点。可以通过缩短token有效期、前后端配合定期刷新token来缓解。如果要彻底解决需要引入Redis存储token黑名单把用户登出后的token加入黑名单。这个回答既承认了方案的局限性又展示了你知道进阶解法。问怎么防止下单时库存超卖答我的项目里下单前会先查询库存并校验扣库存用的是UPDATE t_product SET stock stock - #{count} WHERE id #{productId} AND stock #{count}这样的原子更新语句数据库行锁能保证并发下不会扣成负数。如果用户量大还能用Redis分布式锁或乐观锁做进一步的保护。能把乐观锁原子更新这两个词说出来老师基本上就会满意点头。问SpringBoot自动配置原理说一说答按我前面第一部分讲的逻辑回答就行。重点是EnableAutoConfiguration如何通过AutoConfigurationImportSelector读取配置类列表并结合条件注解按需装配。问如果让你优化这个项目你打算怎么做答两个方向。一个是引入Redis缓存热点商品数据和购物车数据减轻数据库压力另一个是用ElasticSearch做商品搜索支持全文检索和按相关性排序。这两个优化方向都是电商业务的标准演进路径说明你有全局视野。回到我的实际体会做这个项目尤其要注意前松后紧的心态。很多同学前期慢慢磨页面到联调阶段发现接口对不上、数据库设计要改才不得不熬夜改代码。如果从一开始就锁定好数据库表结构、接口文档和统一返回结构后面所有的页面开发都是按照约定填内容整体节奏会顺很多。这个项目的每个模块都不复杂但把它们串成一个完整闭环的体验是那些只做前端展示页或只做增删改查的项目给不了的。希望你也能从这套项目里跑出自己的完整链路答辩时胸有成竹。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进