ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot+Vue民宿在线预定平台毕设源码拆解与实战指南

SpringBoot+Vue民宿在线预定平台毕设源码拆解与实战指南 很多做Java Web毕业设计的同学第一次看到“SpringBootVue民宿在线预定平台”这个题目时第一反应是“又是个管理系统”然后就开始焦虑到底要写哪些功能前后端怎么打通数据库怎么设计才不会被老师挑毛病这份毕设源码我前前后后整理了大半个月包括完整前端工程、后端服务、SQL脚本和接口文档整个过程踩了不少坑。这篇博文就把整个项目的拆解思路、核心代码逻辑、数据库设计要点和上线部署时容易翻车的地方都写出来希望能帮到正在选题或者已经开干却被卡住的人。“民宿在线预定平台”和普通的“房屋信息管理系统”有一个本质差别它存在真正的交易闭环。用户选房、下单、支付或模拟支付、入住、退房、评价每一个环节都涉及状态流转而且民宿行业的“房源—房型—日期价格”关系比标准酒店更灵活。这才是这个项目真正的技术含量所在。如果只是把CRUD堆起来答辩的时候一问业务逻辑就露馅了。所以整套源码在设计时重点没有放在“页面多花哨”上而是把功夫花在了订单状态机、库存扣减时机、价格日历、权限隔离这些真正会被追问的地方。下面先从项目整体拆解开始把设计思路讲清楚再根据实际编码过程中的经验把每一步的关键细节和填坑记录完整交代一遍。1. 项目整体设计与技术选型1.1 这个项目要解决的核心问题是什么先说业务边界。一套能拿得出手的民宿预定平台至少要回答清楚这几个问题普通用户游客/注册用户怎么浏览民宿、查看可订日期和价格用户下单之后房源在哪个时间点被锁定怎么防止同一天同一房间被两个人同时订走用户和民宿老板或管理员看到的数据有何不同普通用户能不能直接访问管理接口订单状态是怎么流转的待支付→已支付→已入住→已退房→已完成已取消价格是怎么算的周末价、节假日价是人工维护还是系统自动规则这套源码对应的项目默认角色分三种系统管理员、民宿老板、普通用户。管理员负责审核民宿入驻、管理用户、查看全平台订单民宿老板可以管理自己的房源和房型、设置不同日期的价格、处理本店订单普通用户则负责浏览、下单、支付模拟、评价和查看自己的订单。不同的角色对应不同的权限和接口范围这直接决定了后端接口不能只做一个全通配的全量CRUD而是必须做数据权限隔离。比如民宿老板调“查询订单”接口时绝对不能查到别的老板名下民宿的订单。这是校园里很多毕设项目最容易忽略、也最容易被答辩老师问住的地方。1.2 技术选型为什么锁定SpringBootVue选技术栈这件事通常有两种心态一种是觉得越“高级”越好上来就是微服务、分布式、消息队列另一种是能省就省后端一个Servlet搞定。我个人的建议很明确毕设的最佳技术栈一定是“自己能完全解释清楚 能找到大量参考文献 兼顾企业主流技术”这三者的交集。SpringBootVue恰好就是这个交集。从后端角度SpringBoot降低了配置成本一个带Web、MyBatis-Plus、MySQL驱动的工程十几分钟就能跑起来而且SpringBoot在就业市场中的普及度非常高面试时讲这个项目能接得上话。有人问“为什么不用Spring Cloud”答案很简单民宿预定平台的业务规模根本不需要分布式强行上微服务反而要把业务拆散增加大量不必要的复杂度答辩也容易露馅。从纯前端角度Vue的学习曲线比React平滑国内社区资料极多Element-UI或Element Plus组件库能让后台管理界面在短时间内达到不错的完成度。Vue的响应式数据绑定非常适合管理端表单和列表页这类的交互。前后端通过JSON格式对接Axios统一管理请求调试和排查问题都非常直观。此外这套组合还有一个隐性优势毕业设计论文好写。SpringBoot的自动配置原理、Vue的生命周期、RESTful API设计、JWT无状态鉴权、MySQL事务隔离级别……随便拿一个出来都能展开两三千字论文的“核心实现”章节完全不愁没内容。1.3 项目模块与功能全景图下面这张功能拆分表就是整套源码所有的功能范围基本覆盖了主流民宿平台的核心链路同时结构层次也很清晰模块子功能面向角色用户认证注册、登录、JWT鉴权、退出登录所有用户民宿浏览民宿列表、民宿详情、房型展示、关键词搜索、区域筛选游客/用户价格日历按日期查看房态与价格、设置周末/节假日价格用户/老板在线预订选日期→选房型→下单→模拟支付用户订单中心订单列表、订单详情、取消订单、退款/入住/退房状态流转用户/老板民宿管理新增/编辑民宿、房型管理、房源上下架民宿老板评价管理用户评价、老板回复、评价展示用户/老板系统管理用户管理、民宿审核、平台统计、订单总览管理员功能数量适中不多到完不成不少到没工作量。比起简单把“增删改查”铺满每个页面这套设计把重心放到了订单状态机和房态库存两个核心业务上这也是论文中“系统设计”部分最能出彩的亮点。2. 数据库设计与SQL脚本实战2.1 表结构设计思路与核心关系数据库设计是整个项目的地基。民宿预定平台的核心不是“房”而是“房在某天能不能订”。所以表结构设计时必须把**“房源-房型-日期-订单”**这条主线拉清楚。整套SQL脚本包含以下核心表用户表sys_user字段包括id、账号、密码BCrypt加密存储、昵称、手机号、头像、角色标识role、创建时间。这里要注意角色字段不要设计成简单的int去猜含义建议直接用字符串“ADMIN”、“OWNER”、“USER”代码里可读性高很多也避免团队沟通时还要对数字。民宿表homestay字段包括id、民宿名称、所在城市、详细地址、封面图片、简介、设施服务用逗号分隔或JSON、老板id、审核状态0待审核/1通过/2驳回、发布状态、创建时间。民宿表是平台的核心资源审核状态和老板id这两个字段非常关键前者对应平台管理模式后者对应数据权限。房型表room_type对应一个民宿下的不同房间类别例如“大床房”“双床房”“loft复式”。字段包括id、民宿id外键、房型名称、面积、可住人数、床型、房间数量、押金、默认价格、房型封面。有一个细节房间数量和“单间民宿”不同民宿虽然规模小但同一个老板可能会有3间大床房这时库存就是一个可配置的静态数据。价格日历表homestay_price字段包括id、房型id、日期、当天价格、库存状态是否有房、是否节假日。这张表是民宿行业区别于标准酒店的关键——不同日期价格是可以独立配置的系统按“日期维度”存价格而不是简单地给每个房型一个一口价。民宿老板可以在管理后台逐日维护价格也可以批量设置周末价。订单表order_info字段包括id、订单编号唯一业务流水号、用户id、民宿id、房型id、入住日期、离店日期、晚数、房间数、订单金额、下单时间、支付时间、订单状态0待支付/1已支付/2已入住/3已退房/4已完成/5已取消、联系人姓名、手机号、备注。评价表comment字段包括id、订单id一个订单只能评价一次、民宿id、用户id、评分、内容、老板回复、评价时间。其余还包括收藏表、通知公告表、轮播图表等辅助表。这里不再一一列字段SQL脚本里有完整的注释。表与表之间的关联关系是sys_user (老板) 1-N homestayhomestay 1-N room_typeroom_type 1-N homestay_pricesys_user (用户) 1-N order_infoorder_info N-1 room_type。逻辑非常清晰画ER图时也好看。2.2 关键字段设计的细节考量有几个字段的设计特别值得一提全是实操中总结出来的经验订单金额到底怎么算。订单金额不是在用户下单后才临时用“默认价格×晚数”去乘的而是下单那一刻就根据价格日历表的当日价格算出来然后把算好的金额冗余存储到订单表的金额字段。为什么这么做因为价格日历是可以被老板随时修改的如果订单表不存快照用户下单后老板改了明天的价格订单金额就变成“活数据”了这是很严重的业务事故。虽然这违背三范式的“消除冗余”但订单金额属于典型的历史快照数据冗余是为了业务正确性。库存为什么不用单独的库存表。很多系统会做一个“房型库存表”按天记录剩余房间数用户下单时扣减。但民宿场景房间很少一般3-10间如果单独建库存表反而要处理“加库存”“减库存”“释放库存”一堆并发问题。这套源码采取的策略是用价格日历表 订单状态双重判断是否有房。预订时查询价格日历表对应日期段的记录是否存在“不可订”的标记再统计已经处于“待支付/已支付/已入住”状态的有效订单占用的房间数如果占用数≥房型房间数就提示满房。这样表结构更精简逻辑也不难理解答辩时能解释得很透彻。订单编号不能是自增id。自增id太容易暴露业务量而且订单号通常需要具备一定格式可读性。项目中订单编号采用yyyyMMddHHmmss 随机4位数字的格式生成同时加唯一索引保证不重复。并发量不大的毕设场景下这种方案简单实用也很方便客服通过订单号快速定位订单。价格表日期字段一定要带索引。后面查询一个房型30天有没有房本质就是在homestay_price表上按room_type_id date区间查询这个字段作为查询条件出现频率最高不加索引会导致数据量上来后SQL越来越慢。2.3 SQL脚本组织方式与初始化数据SQL脚本不是简单把建表语句扔进去就完了还要考虑其他人拿到这份脚本能不能一键跑起来。源码压缩包内的db目录下我按以下顺序组织脚本01_create_database.sql创建数据库、设置字符集为utf8mb402_create_tables.sql全部建表语句包含字段注释和索引03_init_data.sql初始化数据管理员账号、测试民宿数据、房型数据、价格日历数据等有几个关键细节要提醒大家字符集一定要用utf8mb4而不是utf8。utf8在MySQL里最多存3字节而用户的昵称或者民宿名称里如果出现Emoji或生僻字会直接报错或者存成乱码。utf8mb4才是完整的Unicode支持。这个坑非常经典很多人都是上线后用户一输入特殊字符就出问题。初始化数据一定要包含一套可直接演示的完整数据。比如一个已经审核通过的民宿、名下3个房型、当前日期未来30天内每天的价格记录、一个测试账号密码123456。为什么这么要求因为拿到源码的人第一步肯定是把项目跑起来看效果如果没有初始化数据登录进去一片空白体验极其劝退。让用户打开就是“有内容可玩”的状态这是毕设源码应有的自觉。外键约束不要滥用。所有表之间的逻辑关联通过索引和业务代码维护而不是数据库层面强加物理外键。原因有两点第一民宿老板删除一个房型时如果订单表还有这个房型的订单物理外键会直接报错阻止删除而业务上合理的做法是提示“存在关联订单不允许删除”或者软删除第二物理外键在数据量上来之后会影响写入性能分库分表时还会受限。毕设答辩时如果老师问“为什么没有物理外键”你回答“为了保证业务数据的可控性和系统扩展性”是完全站得住脚的。3. SpringBoot后端实现的关键环节3.1 后端分层结构与包规划后端工程结构严格按照主流企业习惯划分包路径如下com.example.homestay ├── config // 配置类MyBatis-Plus配置、拦截器注册、跨域配置 ├── controller // 控制层接收请求参数校验返回结果 ├── service // 业务层存放核心业务逻辑接口实现 ├── mapper // 数据访问层MyBatis-Plus的Mapper接口 ├── entity // 实体类对应数据库表 ├── dto // 数据传输对象接收前端参数、返回前端视图对象 ├── common // 通用类统一返回结果、异常处理、常量、工具类 ├── security // JWT拦截器、登录逻辑、ThreadLocal用户上下文 └── task // 定时任务订单超时取消这个结构看起来“常规”但关键是每个层级要承担正确的职责。很多同学写后端容易犯一个毛病Controller里直接写SQL逻辑Service层形同虚设。我的编码规范是Controller只做三件事接收参数、调用Service、包装返回结果。里面不出现任何业务if-else。Service层承载全部业务逻辑包括参数校验、状态判断、事务控制。Mapper层只做数据访问SQL尽量用MyBatis-Plus的条件构造器复杂统计再用XML自定义SQL。分层清晰的直接好处是答疑和答辩时你只需要说“这个逻辑在Service层”而不是在一堆杂乱的代码里翻来找去。同时后续写接口文档也能直接照着Service层的方法梳理非常方便。3.2 JWT登录鉴权与权限控制登录鉴权这块项目没有用Session而是用JWTJson Web Token做无状态登录。开发现代Web项目JWT已经是非常主流的方案尤其适合前后端分离架构。整套实现包含三个部分登录接口用户提交账号密码后端查库校验密码密码使用BCrypt加密存储注意不是MD5校验成功后生成JWT字符串返回给前端。JWT中只存放用户id、角色、昵称过期时间设为24小时。签名的secret配置在application.yml中实际项目要放到环境变量或配置中心毕设放配置文件里问题不大。JWT拦截器SpringBoot通过HandlerInterceptor实现一个JwtInterceptor注册时排除掉登录接口、注册接口和民宿浏览接口这些接口不需要登录就能访问。拦截器中解析请求头Authorization字段里的Bearer token如果token非法、过期或者签名错误直接返回401状态码。ThreadLocal保存当前用户拦截器解析token成功后把用户id和角色存入ThreadLocal工具类。后续Controller和Service中只要调用UserContext.getUserId()就能取到当前登录用户是谁非常方便。请求结束后记得在afterCompletion里调用remove()清理ThreadLocal避免内存泄漏。角色权限怎么做。拦截器只能解决“有没有登录”不能解决“登录用户能不能干这件事”。项目里通过自定义RequireRole(OWNER)注解拦截器的方式实现角色控制拦截器先检查接口方法是否有该注解如果有则把ThreadLocal中的当前用户角色和注解要求的角色比对不一致返回403。这种方式比Spring Security更轻量代码量也不大适合毕设场景。3.3 民宿预订核心逻辑与并发控制预订是核心中的核心。简单描述这个过程用户选定民宿→选择房型→选择入住日期和离店日期→系统计算总价→生成订单→模拟支付。下单接口的Service层逻辑我详细展开一下Transactional public OrderInfo createOrder(OrderCreateDTO dto) { // 1. 参数校验日期合法性、入住晚数1 // 2. 查询该房型在入住日期范围内的价格日历记录 // 3. 计算价格列表和总金额 // 4. 检查日期段内所有日期的可售余量 // 5. 生成订单编号设置状态为待支付 // 6. 插入订单表 }这里必须加上Transactional事务注解保证订单生成过程中任何一个环节失败整个操作回滚不留下半截脏数据。并发扣库存的处理是所有做交易系统的人都绕不开的问题。比如一个民宿只有3间大床房两个用户同时下单数据库层面就可能出现“超卖”。本项目采用乐观锁思路在检查余量时不是简单地查一次就放行而是利用数据库的唯一索引和事务隔离特性在下单时查询有效订单数量如果数量小于房间数才允许插入订单同时给订单表增加一个业务唯一索引房型id入住日期离店日期不可能直接实现所以更实用的方式是在插入订单前通过SELECT ... FOR UPDATE对价格日历表中对应房型日期范围的记录进行行锁让同一房型同一时段的并发下单串行化。用FOR UPDATE锁住价格日历记录之后第二次并发请求必须等第一个事务提交后才能继续这时它重新统计订单数量发现已经满房就会抛异常“该日期段房间已订完”。这就是可重复读隔离级别下最朴素的防超卖方案虽然性能上不如Redis分布式锁但逻辑容易理解代码量少答辩时反而能讲清楚“为什么这样设计”。订单超时取消是一个很体现专业度的功能。用户下单但未支付系统不能让他永久占着库存。项目通过Spring的Scheduled定时任务每30秒扫描一次订单表把创建时间超过30分钟且状态为“待支付”的订单自动改成“已取消”。因为这个项目是纯Java Web毕设没有引入消息队列所以定时任务轮询是最合适的方案。如果你论文想加一点亮点可以在定时任务之外再提一句“生产环境更优方案是延时队列”但不要真的去集成RabbitMQ会拖慢开发节奏。4. Vue前端搭建与页面交互4.1 前端工程创建与路由规划前端使用Vue 2 Element-UI也可以用Vue 3 Element Plus两者思路一样这里以Vue 2为主因为网上参考资料最多、遇到的坑最少。用Vue CLI创建工程vue create homestay-web选择Router和VuexCSS预处理器选择Less包管理器用npm即可。工程目录下按模块组织视图组件src ├── api // axios请求封装每个模块一个js文件 ├── assets // 静态资源图片、全局样式 ├── components // 公共组件图片上传、分页、富文本等 ├── router // 路由配置文件 ├── store // Vuex状态管理存储用户信息、token ├── utils // 工具类axios实例、token存储 └── views // 页面视图 ├── home // 前台门户民宿列表、民宿详情 ├── user // 用户端登录、注册、个人中心、订单 ├── owner // 民宿老板端房源管理、订单处理、评价管理 └── admin // 平台管理员端用户管理、民宿审核、统计前端路由规划时最需要注意的就是权限路由问题。普通用户登录后不能访问老板端管理页老板不能访问管理员页面。项目里采用动态路由方案登录后根据用户的角色把对应角色的路由表动态添加到router.addRoutes中。路由元信息meta.roles标明访问角色配合路由守卫做前置校验router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login || to.path /register) { next() } else if (!token) { next(/login) } else if (to.meta.roles !to.meta.roles.includes(store.state.user.role)) { next(/403) } else { next() } })4.2 核心页面组件实现要点民宿列表页是整个前台最核心的页面。实现思路是进入页面时调后端分页接口条件城市、民宿名称关键词滚动分页或点击分页加载更多。每张民宿卡片展示封面图、民宿名称、所在城市、最低价格该民宿所有房型默认价格中最低的。列表请求接口时后端直接返回视图模型数据不需要前端做二次拼装。民宿详情页的开发要特别注意日期选择器与价格日历的联动。用户在详情页选择入住/离店日期后需要立即看到每一天的价格和是否有房。项目实现的方式是页面初始化时调/api/roomType/prices?roomTypeIdxxmonth2025-07接口一次性返回当月所有日期的价格和满房标记。前端根据接口数据渲染一个日历表格满房日期不可选。用户选中日期段后前端实时计算底部栏总价。这个交互逻辑其实是把部分业务判断放到了前端但最终下单价仍以后端计算为准前端展示的总价只是提醒用户续费用绝对不能让前端把价格传回来。否则用户用浏览器改一下请求参数就可以低价下单这是严重的安全漏洞。订单列表页则根据不同角色做不同的表格列。用户端展示订单编号、民宿名称、房型、入住/离店日期、金额、状态、操作取消/去支付/删除老板端展示订单编号、用户昵称、联系电话、民宿名称、房型、日期、金额、状态、操作确认入住/确认退房。老板端操作列实际上就是对订单状态机的推动和后面接口文档里的状态流转标识一一对应。4.3 前后端联调技巧与环境配置前后端联调最大的痛苦就是跨域问题。本地开发时Vue开发服务器默认跑在8080端口或5173后端SpringBoot跑在8080端口两边端口不一致就会产生跨域。项目里有两种解决方式我都用了第一种后端开启全局跨域配置。在SpringBoot中定义一个CorsFilter的WebMvcConfigurer允许来源为前端地址本地开发时就是http://localhost:端口允许所有请求头和请求方法。这是最省事的方案。第二种前端利用Vue CLI的代理配置。在vue.config.js中设置devServer.proxy把以/api开头的请求代理到后端的http://localhost:8080。这样前端代码中axios请求地址就是相对路径/api/xxx本地开发就像“同源”一样完全规避跨域。两种方式选其一即可我最终采用的是前端代理方案因为生产环境打包后前端静态文件由Nginx托管可以不依赖后端跨域配置。Axios请求封装也是联调体验的关键。项目在utils/request.js里统一创建axios实例设置了baseURL: /api并做了请求/响应拦截请求拦截器自动携带token响应拦截器统一处理后端返回的数据结构{code, message, data}如果code不为200就弹Message.error如果HTTP状态是401就跳转到登录页。统一封装的好处是所有接口的错误提示风格一致前端不用每个页面都写一遍错误处理代码干净很多。登录态的Vuex存储也值得一提用户点击登录成功后把后端返回的token和用户信息存储到vuex和localStorage两处。刷新页面时在created钩子里读取localStorage恢复登录状态避免刷新就掉登录的尴尬。5. 接口文档编写规范与示例5.1 一份合格接口文档应该包含什么接口文档是这份源码交付物里特别强调的一部分因为很多毕设项目的接口只有一份Postman导出的json同学拿回去根本不知道怎么用。一套可直接复现的接口文档至少包含以下内容接口基本信息请求URL、请求方法、功能描述、是否需要登录、需要的角色权限。请求参数表参数名、类型、是否必须、参数含义、示例值。响应结果示例成功/失败的JSON结构。错误码说明业务错误码、HTTP状态码的含义。数据格式我这里统一为{ code: 200, message: success, data: { token: ... } }分页接口的data格式统一为{ total: 56, records: [{ }, { }], current: 1, size: 10 }前后端约定大于配置一旦接口文档定下来前后端同步开发时所有的沟通成本都会大幅降低。5.2 核心接口逐个拆解下面挑几个典型接口详细说明便于理解文档里那些关键字段背后是怎么设计的POST /api/auth/login请求参数username账号、password密码。成功返回200data中包含token、userId、nickname、role四个字段。登录接口是少数不需要携带token的接口因为此时还没有token文档里要标注是否需要鉴权否。POST /api/order/create请求参数roomTypeId房型id、startDate入住日期、endDate离店日期、roomNum预订房间数、contactName联系人、contactPhone联系电话、remark备注。这个接口需要登录所有用户角色都可以操作。返回data为订单详情。GET /api/roomType/prices请求参数roomTypeId、month格式yyyy-MM。返回data为该月每天的价格和库存状态列表。这里要注意返回的日期价格列表是给前台用户看的只返回“可订/不可订”的状态不返回具体还剩几间防止同行通过接口探查库存。如果民宿老板要看每天剩余几间要在另一个管理端接口中查询。PUT /api/owner/order/status请求参数orderId、status目标状态2已入住/3已退房。这个接口需要OWNER或ADMIN角色。操作时后端会做状态流转校验比如“已退房”不能直接变成“已入住”必须按顺序流转。GET /api/admin/stat/overview请求参数无。需要ADMIN角色。返回平台总民宿数、总用户数、今日订单数、本月交易额等统计数据。前端管理员首页就是靠这个接口渲染一堆数字卡片。5.3 接口文档与Postman联调配合给到手的同学最好搭配一套Postman导出的环境变量文件把baseURL配置好后导入接口集合就能直接测试。我在源码包里已经附上了docs/民宿预定平台.postman_collection.json把登录接口测试成功后返回的token设置成环境变量{{token}}后续所有需要鉴权的接口请求头Authorization里引用这个变量做联调测试非常顺畅。接口文档还有一个作用就是帮助二次开发。很多同学拿源码回去后想加一个功能得先搞清楚现有接口的数据流向。文档里把每个接口的输入输出和权限标注清楚后照着文档找Service对应方法改就行了不用把整个项目从头到尾读一遍代码。6. 部署上线、常见问题排查与避坑经验6.1 从源码到可以跑通的完整流程拿到源码后第一步不是急着看代码而是先看交付物目录结构心里有个底。完整的启动流程我总结成了下面这几步导入SQL脚本在Navicat或者命令行中执行db目录下的三个SQL脚本按序号顺序执行即可。执行完毕后确认数据库中有11张表以及预置的初始数据。修改后端配置打开application.yml把数据源地址、用户名、密码改成你自己的MySQL信息。如果MySQL版本是8.x注意驱动的driver-class-name是com.mysql.cj.jdbc.Driver并且URL中要带上serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf8。启动后端用IDEA打开后端工程等待Maven下载依赖如果非常慢把Maven仓库地址改为阿里云镜像执行HomestayApplication.java的main方法观察控制台日志是否显示Started。启动前端用VSCode或WebStorm打开前端工程在终端执行npm install等待依赖安装完成再执行npm run serve。看到App running at提示后浏览器访问前端地址。使用测试账号登录初始管理员账号admin/admin123普通用户账号user/123456。用普通用户账号登录后可体验完整预订流程。有一点要特别提醒版本兼容性。当前网络环境下的SpringBoot版本已经卷到3.x了如果你在开发环境用的是JDK17建议直接用SpringBoot 2.7.xJDK8或者JDK11的组合最稳。SpringBoot 3.x虽然新但有些MyBatis-Plus的旧版本不兼容毕业设计没必要为了追新版本白白折腾一下午。6.2 我实际踩过的坑整理源码那几天我反复重跑了多遍遇到的坑不少挑几个有代表性的写出来希望后来的人不再踩第一个坑MyBatis-Plus分页插件没配置。很多同学用MyBatis-Plus的Page对象做分页结果查出来的records永远是整张表的所有数据total也是0。原因是没有添加分页插件PaginationInnerInterceptor到MyBatis-Plus配置类中。在MybatisPlusConfig里注册这个插件时还要注意新版分页插件配置方式发生了变化老教程里的OptimisticLockerInnerInterceptor之类要用新的MybatisPlusInterceptor统一装配。第二个坑LocalDate和JSON的序列化格式问题。Java 8的LocalDate类型在SpringBoot默认返回给前端时是数组格式比如[2025, 7, 1]前端拿到后很难直接用而且显示格式不符合常规[2025-07-01]预期。解决方案是全局配置Jackson的JavaTimeModule并设置日期格式spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8同时在局部JsonFormat(pattern yyyy-MM-dd)标注LocalDate字段确保日期展示正确。这个问题不解决前端日历什么都选不了。第三个坑Vue路由打包后刷新404。这个坑是在部署上线后遇到的。前端使用的是Vue Router的history模式打包后Nginx如果只配置了根路径的location /刷新二级页面就会404。解决办法有两种一是Nginx配置try_files $uri $uri/ /index.html;把不存在的路径全部重写到首页二是在Vue Router中使用hash模式。如果项目只是毕设场景不追求URL美观直接用hash模式最省事。第四个坑定时任务重复执行。如果你的项目用了Scheduled做订单超时取消在本地只有一个实例时没问题。但如果在云服务器上部署切记不要开多实例否则每个实例都会跑定时任务可能导致同一条订单被重复更新两次。可以通过在任务方法里加分布式锁如Redis锁或者更简单的方式就是只部署一个实例。第五个坑上传图片的路径问题。民宿封面和房型图片上传后不要存在前端工程目录下因为前端重新build时图片会被清掉。正确做法是后端提供一个静态资源映射目录图片上传到服务器本地的一个固定目录如/usr/local/homestay/upload/SpringBoot配置WebMvcConfigurer把该路径映射到/upload/**前端访问时拼接完整地址即可。6.3 答辩时老师常问的六个问题及答案方向整理完这套源码之后我顺便把答辩时老师最容易问的几个问题也梳理了一下提前准备好答案会从容得多为什么用JWT不用Session答前后端分离架构下后端服务可能多实例部署Session无法跨实例共享JWT无状态服务端不保存会话数据便于水平扩展。同时JWT可以携带用户基本信息减少查询数据库次数。订单状态是在前端控制还是后端控制答后端控制。前端只是展示按钮真正的状态流转校验放在后端Service层后端还要校验流转合法性不能跳状态。如何防止超卖答使用数据库行锁SELECT FOR UPDATE锁住价格日历记录让同一房型同一日期段的并发下单串行化同时使用事务保证多步操作原子性。价格日历的数据量会爆炸吗答正常民宿平台会定期清理过期价格记录或者按需生成未来一年的价格数据不会无限膨胀。本项目通过定时任务清理一年前的历史价格记录。如果用户支付成功后老板把房型删了怎么办答房间使用了逻辑删除deleted字段而非物理删除已产生订单的房型不会被真正删掉订单详情仍能正常展示。前后端如何联调答定义了统一接口文档后端按照文档返回统一数据结构前端通过Axios封装请求利用Vue CLI代理解决开发环境跨域部署后通过Nginx反向代理统一入口。把这些问题的答案背熟并理解透彻答辩时基本不会有太大问题。7. 源码包内容清单与二次开发建议7.1 交付目录结构说明拿到压缩包后先看一下整体结构方便快速定位资源homestay-project ├── backend // SpringBoot后端源码 ├── frontend // Vue前端源码 ├── db // SQL脚本建库、建表、初始化数据 ├── docs // 接口文档 Postman导出文件 └── README.md // 项目说明启动步骤、账号、注意事项README.md一定要认真写里面包含了默认端口、默认账号、启动顺序、常见报错的解决方案。很多人拿到源码第一件事就是看README把README写好能省去大量重复答疑时间。7.2 如何在这个基础上做二次扩展如果你不想直接原封不动交这套源码很多学校查重逻辑会比较严格可以从下面几个方向做适当扩展加入微信支付模拟沙箱在支付环节增加一个模拟支付页面后端集成微信支付沙箱API既有亮点又不复杂。加入消息通知用户下单成功后给民宿老板发一条站内信/邮件通知可以用SpringBoot自带的JavaMailSender实现不复杂但功能链条更完整。加入数据统计图表管理员首页用ECharts展示近7日订单量和销售额趋势前端集成ECharts比较简单视觉效果提升明显。加入收藏与“猜你喜欢”基于用户浏览记录做一个简单的推荐列表后端用标签匹配即可不需要机器学习。每个扩展点都会让项目看起来“不止是毕设”但也不会增加太多开发难度。我个人建议优先做支付模拟和ECharts统计这两个投入产出比最高。7.3 我最想告诉你的一句大实话最后说点实在的。毕设项目的本质是展示你具备独立完成一个完整Web业务系统的能力不是为了把系统做得像美团、携程那样包罗万象。这套民宿预定平台麻雀虽小五脏俱全——用户端体验、运营端管理、状态流转、权限控制、并发防超卖、定时任务、前后端分离这些实实在在的工程点全都有了。拿到源码之后我建议你先按README把项目跑通再去看你最在乎的那个功能比如下单逻辑是怎么实现的完整走一遍代码之后再决定要不要做二次开发。只要你把核心逻辑讲透了这个项目完全能撑起一场漂亮的答辩。我个人这段时间反复整理和优化这套源码的体会是技术选型是策略数据库设计是骨架业务状态机是灵魂而前后端联调是体力活。如果把这些环节都认真打磨过一遍比单纯背八股文实用得多。希望这份源码和这篇拆解能帮你少走一些弯路顺利搞定自己的Java Web毕业设计。
返回列表